1 //===-- 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>
12 #include <dlfcn.h>
13 #include <execinfo.h>
14 #include <sys/types.h>
15 #include <sys/user.h>
16 #include <sys/utsname.h>
17 #include <sys/sysctl.h>
18
19 #include <sys/ptrace.h>
20 #include <sys/exec.h>
21 #include <machine/elf.h>
22
23
24 // 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
35 #include "lldb/Core/DataBufferHeap.h"
36 #include "lldb/Core/DataExtractor.h"
37 #include "llvm/Support/Host.h"
38
39
40 extern "C" {
41 extern char **environ;
42 }
43
44 using namespace lldb;
45 using namespace lldb_private;
46
47
48 class FreeBSDThread
49 {
50 public:
FreeBSDThread(const char * thread_name)51 FreeBSDThread(const char *thread_name)
52 {
53 Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name);
54 }
PThreadDestructor(void * v)55 static void PThreadDestructor (void *v)
56 {
57 delete (FreeBSDThread*)v;
58 }
59 };
60
61 static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT;
62 static pthread_key_t g_thread_create_key = 0;
63
64 static void
InitThreadCreated()65 InitThreadCreated()
66 {
67 ::pthread_key_create (&g_thread_create_key, FreeBSDThread::PThreadDestructor);
68 }
69
70 void
ThreadCreated(const char * thread_name)71 Host::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 Host::SetShortThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name, 16);
80 }
81
82 std::string
GetThreadName(lldb::pid_t pid,lldb::tid_t tid)83 Host::GetThreadName (lldb::pid_t pid, lldb::tid_t tid)
84 {
85 std::string thread_name;
86 return thread_name;
87 }
88
89 void
Backtrace(Stream & strm,uint32_t max_frames)90 Host::Backtrace (Stream &strm, uint32_t max_frames)
91 {
92 char backtrace_path[] = "/tmp/lldb-backtrace-tmp-XXXXXX";
93 int backtrace_fd = ::mkstemp (backtrace_path);
94 if (backtrace_fd != -1)
95 {
96 std::vector<void *> frame_buffer (max_frames, NULL);
97 int count = ::backtrace (&frame_buffer[0], frame_buffer.size());
98 ::backtrace_symbols_fd (&frame_buffer[0], count, backtrace_fd);
99
100 const off_t buffer_size = ::lseek(backtrace_fd, 0, SEEK_CUR);
101
102 if (::lseek(backtrace_fd, 0, SEEK_SET) == 0)
103 {
104 char *buffer = (char *)::malloc (buffer_size);
105 if (buffer)
106 {
107 ssize_t bytes_read = ::read (backtrace_fd, buffer, buffer_size);
108 if (bytes_read > 0)
109 strm.Write(buffer, bytes_read);
110 ::free (buffer);
111 }
112 }
113 ::close (backtrace_fd);
114 ::unlink (backtrace_path);
115 }
116 }
117
118 size_t
GetEnvironment(StringList & env)119 Host::GetEnvironment (StringList &env)
120 {
121 char *v;
122 char **var = environ;
123 for (; var != NULL && *var != NULL; ++var) {
124 v = strchr(*var, (int)'-');
125 if (v == NULL)
126 continue;
127 env.AppendString(v);
128 }
129 return env.GetSize();
130 }
131
132 bool
GetOSVersion(uint32_t & major,uint32_t & minor,uint32_t & update)133 Host::GetOSVersion(uint32_t &major,
134 uint32_t &minor,
135 uint32_t &update)
136 {
137 struct utsname un;
138 int status;
139
140 if (uname(&un) < 0)
141 return false;
142
143 status = sscanf(un.release, "%u.%u", &major, &minor);
144 return status == 2;
145 }
146
147 Error
LaunchProcess(ProcessLaunchInfo & launch_info)148 Host::LaunchProcess (ProcessLaunchInfo &launch_info)
149 {
150 Error error;
151 assert(!"Not implemented yet!!!");
152 return error;
153 }
154
155 bool
GetOSBuildString(std::string & s)156 Host::GetOSBuildString (std::string &s)
157 {
158 int mib[2] = { CTL_KERN, KERN_OSREV };
159 char cstr[PATH_MAX];
160 size_t cstr_len = sizeof(cstr);
161 if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
162 {
163 s.assign (cstr, cstr_len);
164 return true;
165 }
166 s.clear();
167 return false;
168 }
169
170 bool
GetOSKernelDescription(std::string & s)171 Host::GetOSKernelDescription (std::string &s)
172 {
173 int mib[2] = { CTL_KERN, KERN_VERSION };
174 char cstr[PATH_MAX];
175 size_t cstr_len = sizeof(cstr);
176 if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
177 {
178 s.assign (cstr, cstr_len);
179 return true;
180 }
181 s.clear();
182 return false;
183 }
184
185 static bool
GetFreeBSDProcessArgs(const ProcessInstanceInfoMatch * match_info_ptr,ProcessInstanceInfo & process_info)186 GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
187 ProcessInstanceInfo &process_info)
188 {
189 if (process_info.ProcessIDIsValid()) {
190 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, (int)process_info.GetProcessID() };
191
192 char arg_data[8192];
193 size_t arg_data_size = sizeof(arg_data);
194 if (::sysctl (mib, 4, arg_data, &arg_data_size , NULL, 0) == 0)
195 {
196 DataExtractor data (arg_data, arg_data_size, lldb::endian::InlHostByteOrder(), sizeof(void *));
197 lldb::offset_t offset = 0;
198 const char *cstr;
199
200 cstr = data.GetCStr (&offset);
201 if (cstr)
202 {
203 process_info.GetExecutableFile().SetFile(cstr, false);
204
205 if (!(match_info_ptr == NULL ||
206 NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
207 match_info_ptr->GetNameMatchType(),
208 match_info_ptr->GetProcessInfo().GetName())))
209 return false;
210
211 Args &proc_args = process_info.GetArguments();
212 while (1)
213 {
214 const uint8_t *p = data.PeekData(offset, 1);
215 while ((p != NULL) && (*p == '\0') && offset < arg_data_size)
216 {
217 ++offset;
218 p = data.PeekData(offset, 1);
219 }
220 if (p == NULL || offset >= arg_data_size)
221 return true;
222
223 cstr = data.GetCStr(&offset);
224 if (cstr)
225 proc_args.AppendArgument(cstr);
226 else
227 return true;
228 }
229 }
230 }
231 }
232 return false;
233 }
234
235 static bool
GetFreeBSDProcessCPUType(ProcessInstanceInfo & process_info)236 GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info)
237 {
238 if (process_info.ProcessIDIsValid()) {
239 process_info.GetArchitecture() = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
240 return true;
241 }
242 process_info.GetArchitecture().Clear();
243 return false;
244 }
245
246 static bool
GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo & process_info)247 GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info)
248 {
249 struct kinfo_proc proc_kinfo;
250 size_t proc_kinfo_size;
251
252 if (process_info.ProcessIDIsValid())
253 {
254 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,
255 (int)process_info.GetProcessID() };
256 proc_kinfo_size = sizeof(struct kinfo_proc);
257
258 if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0)
259 {
260 if (proc_kinfo_size > 0)
261 {
262 process_info.SetParentProcessID (proc_kinfo.ki_ppid);
263 process_info.SetUserID (proc_kinfo.ki_ruid);
264 process_info.SetGroupID (proc_kinfo.ki_rgid);
265 process_info.SetEffectiveUserID (proc_kinfo.ki_uid);
266 if (proc_kinfo.ki_ngroups > 0)
267 process_info.SetEffectiveGroupID (proc_kinfo.ki_groups[0]);
268 else
269 process_info.SetEffectiveGroupID (UINT32_MAX);
270 return true;
271 }
272 }
273 }
274 process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID);
275 process_info.SetUserID (UINT32_MAX);
276 process_info.SetGroupID (UINT32_MAX);
277 process_info.SetEffectiveUserID (UINT32_MAX);
278 process_info.SetEffectiveGroupID (UINT32_MAX);
279 return false;
280 }
281
282 bool
GetProcessInfo(lldb::pid_t pid,ProcessInstanceInfo & process_info)283 Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
284 {
285 process_info.SetProcessID(pid);
286 if (GetFreeBSDProcessArgs(NULL, process_info)) {
287 // should use libprocstat instead of going right into sysctl?
288 GetFreeBSDProcessCPUType(process_info);
289 GetFreeBSDProcessUserAndGroup(process_info);
290 return true;
291 }
292 process_info.Clear();
293 return false;
294 }
295
296 lldb::DataBufferSP
GetAuxvData(lldb_private::Process * process)297 Host::GetAuxvData(lldb_private::Process *process)
298 {
299 int mib[2] = { CTL_KERN, KERN_PS_STRINGS };
300 void *ps_strings_addr, *auxv_addr;
301 size_t ps_strings_size = sizeof(void *);
302 Elf_Auxinfo aux_info[AT_COUNT];
303 struct ps_strings ps_strings;
304 struct ptrace_io_desc pid;
305 DataBufferSP buf_sp;
306 std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0));
307
308 if (::sysctl(mib, 2, &ps_strings_addr, &ps_strings_size, NULL, 0) == 0) {
309 pid.piod_op = PIOD_READ_D;
310 pid.piod_addr = &ps_strings;
311 pid.piod_offs = ps_strings_addr;
312 pid.piod_len = sizeof(ps_strings);
313 if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) {
314 perror("failed to fetch ps_strings");
315 buf_ap.release();
316 goto done;
317 }
318
319 auxv_addr = ps_strings.ps_envstr + ps_strings.ps_nenvstr + 1;
320
321 pid.piod_addr = aux_info;
322 pid.piod_offs = auxv_addr;
323 pid.piod_len = sizeof(aux_info);
324 if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) {
325 perror("failed to fetch aux_info");
326 buf_ap.release();
327 goto done;
328 }
329 memcpy(buf_ap->GetBytes(), aux_info, pid.piod_len);
330 buf_sp.reset(buf_ap.release());
331 } else {
332 perror("sysctl failed on ps_strings");
333 }
334
335 done:
336 return buf_sp;
337 }
338