blob: 7671cce151c8e410a6643c4352e11b0f351174ca [file] [log] [blame]
Johnny Chen8f3d8382011-08-02 20:52:42 +00001//===-- source/Host/freebsd/Host.cpp ------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10// C Includes
11#include <stdio.h>
Johnny Chen30213ff2012-01-05 19:17:38 +000012#include <dlfcn.h>
Johnny Chen8f3d8382011-08-02 20:52:42 +000013#include <execinfo.h>
14#include <sys/types.h>
15#include <sys/user.h>
16#include <sys/utsname.h>
17#include <sys/sysctl.h>
18
Johnny Chen30213ff2012-01-05 19:17:38 +000019#include <sys/ptrace.h>
20#include <sys/exec.h>
21#include <machine/elf.h>
22
23
Johnny Chen8f3d8382011-08-02 20:52:42 +000024// C++ Includes
25// Other libraries and framework includes
26// Project includes
27#include "lldb/Core/Error.h"
28#include "lldb/Host/Endian.h"
29#include "lldb/Host/Host.h"
30#include "lldb/Core/DataExtractor.h"
31#include "lldb/Core/StreamFile.h"
32#include "lldb/Core/StreamString.h"
33#include "lldb/Target/Process.h"
34
Johnny Chen30213ff2012-01-05 19:17:38 +000035#include "lldb/Core/DataBufferHeap.h"
36#include "lldb/Core/DataExtractor.h"
Johnny Chen8f3d8382011-08-02 20:52:42 +000037#include "llvm/Support/Host.h"
38
Johnny Chen30213ff2012-01-05 19:17:38 +000039
Johnny Chen8f3d8382011-08-02 20:52:42 +000040extern "C" {
Johnny Chen30213ff2012-01-05 19:17:38 +000041 extern char **environ;
Johnny Chen8f3d8382011-08-02 20:52:42 +000042}
43
44using namespace lldb;
45using namespace lldb_private;
46
Johnny Chen30213ff2012-01-05 19:17:38 +000047
Johnny Chen8f3d8382011-08-02 20:52:42 +000048class FreeBSDThread
49{
50public:
51 FreeBSDThread(const char *thread_name)
52 {
53 Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name);
54 }
55 static void PThreadDestructor (void *v)
56 {
57 delete (FreeBSDThread*)v;
58 }
59};
60
61static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT;
62static pthread_key_t g_thread_create_key = 0;
63
64static void
65InitThreadCreated()
66{
67 ::pthread_key_create (&g_thread_create_key, FreeBSDThread::PThreadDestructor);
68}
69
70void
71Host::ThreadCreated (const char *thread_name)
72{
73 ::pthread_once (&g_thread_create_once, InitThreadCreated);
74 if (g_thread_create_key)
75 {
76 ::pthread_setspecific (g_thread_create_key, new FreeBSDThread(thread_name));
77 }
78}
79
80void
81Host::Backtrace (Stream &strm, uint32_t max_frames)
82{
83 char backtrace_path[] = "/tmp/lldb-backtrace-tmp-XXXXXX";
84 int backtrace_fd = ::mkstemp (backtrace_path);
85 if (backtrace_fd != -1)
86 {
87 std::vector<void *> frame_buffer (max_frames, NULL);
88 int count = ::backtrace (&frame_buffer[0], frame_buffer.size());
89 ::backtrace_symbols_fd (&frame_buffer[0], count, backtrace_fd);
Johnny Chen30213ff2012-01-05 19:17:38 +000090
Johnny Chen8f3d8382011-08-02 20:52:42 +000091 const off_t buffer_size = ::lseek(backtrace_fd, 0, SEEK_CUR);
92
93 if (::lseek(backtrace_fd, 0, SEEK_SET) == 0)
94 {
95 char *buffer = (char *)::malloc (buffer_size);
96 if (buffer)
97 {
98 ssize_t bytes_read = ::read (backtrace_fd, buffer, buffer_size);
99 if (bytes_read > 0)
100 strm.Write(buffer, bytes_read);
101 ::free (buffer);
102 }
103 }
104 ::close (backtrace_fd);
105 ::unlink (backtrace_path);
106 }
107}
108
109size_t
110Host::GetEnvironment (StringList &env)
111{
112 char *v;
113 char **var = environ;
Johnny Chen30213ff2012-01-05 19:17:38 +0000114 for (; var != NULL && *var != NULL; ++var) {
Johnny Chen8f3d8382011-08-02 20:52:42 +0000115 v = strchr(*var, (int)'-');
116 if (v == NULL)
117 continue;
118 env.AppendString(v);
119 }
120 return env.GetSize();
121}
122
123bool
124Host::GetOSVersion(uint32_t &major,
125 uint32_t &minor,
126 uint32_t &update)
127{
128 struct utsname un;
129 int status;
130
131 if (uname(&un) < 0)
132 return false;
133
134 status = sscanf(un.release, "%u.%u-%u", &major, &minor, &update);
135 return status == 3;
136}
137
138Error
139Host::LaunchProcess (ProcessLaunchInfo &launch_info)
140{
141 Error error;
142 assert(!"Not implemented yet!!!");
143 return error;
144}
145
146bool
147Host::GetOSBuildString (std::string &s)
148{
149 int mib[2] = { CTL_KERN, KERN_OSREV };
150 char cstr[PATH_MAX];
151 size_t cstr_len = sizeof(cstr);
152 if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
153 {
154 s.assign (cstr, cstr_len);
155 return true;
156 }
157 s.clear();
158 return false;
159}
160
161bool
162Host::GetOSKernelDescription (std::string &s)
163{
164 int mib[2] = { CTL_KERN, KERN_VERSION };
165 char cstr[PATH_MAX];
166 size_t cstr_len = sizeof(cstr);
167 if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
168 {
169 s.assign (cstr, cstr_len);
170 return true;
171 }
172 s.clear();
173 return false;
174}
175
176static bool
177GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
178 ProcessInstanceInfo &process_info)
179{
180 if (process_info.ProcessIDIsValid()) {
Filipe Cabecinhasd0b87d82012-09-11 18:11:16 +0000181 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, (int)process_info.GetProcessID() };
Johnny Chen8f3d8382011-08-02 20:52:42 +0000182
183 char arg_data[8192];
184 size_t arg_data_size = sizeof(arg_data);
Johnny Chen30213ff2012-01-05 19:17:38 +0000185 if (::sysctl (mib, 4, arg_data, &arg_data_size , NULL, 0) == 0)
Johnny Chen8f3d8382011-08-02 20:52:42 +0000186 {
187 DataExtractor data (arg_data, arg_data_size, lldb::endian::InlHostByteOrder(), sizeof(void *));
188 uint32_t offset = 0;
Johnny Chen8f3d8382011-08-02 20:52:42 +0000189 const char *cstr;
Johnny Chen30213ff2012-01-05 19:17:38 +0000190
Johnny Chen8f3d8382011-08-02 20:52:42 +0000191 cstr = data.GetCStr (&offset);
192 if (cstr)
193 {
194 process_info.GetExecutableFile().SetFile(cstr, false);
195
Johnny Chen30213ff2012-01-05 19:17:38 +0000196 if (!(match_info_ptr == NULL ||
Johnny Chen8f3d8382011-08-02 20:52:42 +0000197 NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
198 match_info_ptr->GetNameMatchType(),
Johnny Chen30213ff2012-01-05 19:17:38 +0000199 match_info_ptr->GetProcessInfo().GetName())))
200 return false;
201
202 Args &proc_args = process_info.GetArguments();
203 while (1)
Johnny Chen8f3d8382011-08-02 20:52:42 +0000204 {
Johnny Chen30213ff2012-01-05 19:17:38 +0000205 const uint8_t *p = data.PeekData(offset, 1);
206 while ((p != NULL) && (*p == '\0') && offset < arg_data_size)
Johnny Chen8f3d8382011-08-02 20:52:42 +0000207 {
Johnny Chen8f3d8382011-08-02 20:52:42 +0000208 ++offset;
Johnny Chen30213ff2012-01-05 19:17:38 +0000209 p = data.PeekData(offset, 1);
Johnny Chen8f3d8382011-08-02 20:52:42 +0000210 }
Johnny Chen30213ff2012-01-05 19:17:38 +0000211 if (p == NULL || offset >= arg_data_size)
212 return true;
213
214 cstr = data.GetCStr(&offset);
215 if (cstr)
216 proc_args.AppendArgument(cstr);
217 else
218 return true;
Johnny Chen8f3d8382011-08-02 20:52:42 +0000219 }
220 }
Johnny Chen30213ff2012-01-05 19:17:38 +0000221 }
Johnny Chen8f3d8382011-08-02 20:52:42 +0000222 }
223 return false;
224}
225
226static bool
227GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info)
228{
229 if (process_info.ProcessIDIsValid()) {
Johnny Chen30213ff2012-01-05 19:17:38 +0000230 process_info.GetArchitecture() = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
231 return true;
Johnny Chen8f3d8382011-08-02 20:52:42 +0000232 }
233 process_info.GetArchitecture().Clear();
234 return false;
235}
236
237static bool
238GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info)
239{
240 struct kinfo_proc proc_kinfo;
241 size_t proc_kinfo_size;
242
243 if (process_info.ProcessIDIsValid())
244 {
245 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,
Filipe Cabecinhasd0b87d82012-09-11 18:11:16 +0000246 (int)process_info.GetProcessID() };
Johnny Chen8f3d8382011-08-02 20:52:42 +0000247 proc_kinfo_size = sizeof(struct kinfo_proc);
248
249 if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0)
250 {
251 if (proc_kinfo_size > 0)
252 {
253 process_info.SetParentProcessID (proc_kinfo.ki_ppid);
254 process_info.SetUserID (proc_kinfo.ki_ruid);
255 process_info.SetGroupID (proc_kinfo.ki_rgid);
256 process_info.SetEffectiveUserID (proc_kinfo.ki_uid);
257 if (proc_kinfo.ki_ngroups > 0)
258 process_info.SetEffectiveGroupID (proc_kinfo.ki_groups[0]);
259 else
Johnny Chen30213ff2012-01-05 19:17:38 +0000260 process_info.SetEffectiveGroupID (UINT32_MAX);
Johnny Chen8f3d8382011-08-02 20:52:42 +0000261 return true;
262 }
263 }
264 }
265 process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID);
266 process_info.SetUserID (UINT32_MAX);
267 process_info.SetGroupID (UINT32_MAX);
268 process_info.SetEffectiveUserID (UINT32_MAX);
Johnny Chen30213ff2012-01-05 19:17:38 +0000269 process_info.SetEffectiveGroupID (UINT32_MAX);
Johnny Chen8f3d8382011-08-02 20:52:42 +0000270 return false;
271}
272
273bool
274Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
275{
276 process_info.SetProcessID(pid);
277 if (GetFreeBSDProcessArgs(NULL, process_info)) {
278 // should use libprocstat instead of going right into sysctl?
279 GetFreeBSDProcessCPUType(process_info);
280 GetFreeBSDProcessUserAndGroup(process_info);
281 return true;
282 }
283 process_info.Clear();
284 return false;
285}
Johnny Chen30213ff2012-01-05 19:17:38 +0000286
287lldb::DataBufferSP
288Host::GetAuxvData(lldb_private::Process *process)
289{
290 int mib[2] = { CTL_KERN, KERN_PS_STRINGS };
291 void *ps_strings_addr, *auxv_addr;
292 size_t ps_strings_size = sizeof(void *);
293 Elf_Auxinfo aux_info[AT_COUNT];
294 struct ps_strings ps_strings;
295 struct ptrace_io_desc pid;
296 DataBufferSP buf_sp;
Greg Clayton7b0992d2013-04-18 22:45:39 +0000297 std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0));
Johnny Chen30213ff2012-01-05 19:17:38 +0000298
299 if (::sysctl(mib, 2, &ps_strings_addr, &ps_strings_size, NULL, 0) == 0) {
300 pid.piod_op = PIOD_READ_D;
301 pid.piod_addr = &ps_strings;
302 pid.piod_offs = ps_strings_addr;
303 pid.piod_len = sizeof(ps_strings);
Filipe Cabecinhasd0b87d82012-09-11 18:11:16 +0000304 if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) {
Johnny Chen30213ff2012-01-05 19:17:38 +0000305 perror("failed to fetch ps_strings");
306 buf_ap.release();
307 goto done;
308 }
309
310 auxv_addr = ps_strings.ps_envstr + ps_strings.ps_nenvstr + 1;
311
312 pid.piod_addr = aux_info;
313 pid.piod_offs = auxv_addr;
314 pid.piod_len = sizeof(aux_info);
Filipe Cabecinhasd0b87d82012-09-11 18:11:16 +0000315 if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) {
Johnny Chen30213ff2012-01-05 19:17:38 +0000316 perror("failed to fetch aux_info");
317 buf_ap.release();
318 goto done;
319 }
320 memcpy(buf_ap->GetBytes(), aux_info, pid.piod_len);
321 buf_sp.reset(buf_ap.release());
322 } else {
323 perror("sysctl failed on ps_strings");
324 }
325
326 done:
327 return buf_sp;
328}