blob: b585d62b531816258b8d4de06dff91d8f7f9deb8 [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
Ed Maste5d34af32013-06-24 15:09:18 +0000124Host::GetOSVersion(uint32_t &major,
125 uint32_t &minor,
Johnny Chen8f3d8382011-08-02 20:52:42 +0000126 uint32_t &update)
127{
128 struct utsname un;
129 int status;
130
131 if (uname(&un) < 0)
132 return false;
133
Ed Maste2f0d5902013-06-25 20:50:07 +0000134 status = sscanf(un.release, "%u.%u", &major, &minor);
135 update = UINT32_MAX;
136 return status == 2;
Johnny Chen8f3d8382011-08-02 20:52:42 +0000137}
138
139Error
140Host::LaunchProcess (ProcessLaunchInfo &launch_info)
141{
142 Error error;
143 assert(!"Not implemented yet!!!");
144 return error;
145}
146
147bool
148Host::GetOSBuildString (std::string &s)
149{
150 int mib[2] = { CTL_KERN, KERN_OSREV };
151 char cstr[PATH_MAX];
152 size_t cstr_len = sizeof(cstr);
153 if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
154 {
155 s.assign (cstr, cstr_len);
156 return true;
157 }
158 s.clear();
159 return false;
160}
161
162bool
163Host::GetOSKernelDescription (std::string &s)
164{
165 int mib[2] = { CTL_KERN, KERN_VERSION };
166 char cstr[PATH_MAX];
167 size_t cstr_len = sizeof(cstr);
168 if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
169 {
170 s.assign (cstr, cstr_len);
171 return true;
172 }
173 s.clear();
174 return false;
175}
176
177static bool
178GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
179 ProcessInstanceInfo &process_info)
180{
181 if (process_info.ProcessIDIsValid()) {
Filipe Cabecinhasd0b87d82012-09-11 18:11:16 +0000182 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, (int)process_info.GetProcessID() };
Johnny Chen8f3d8382011-08-02 20:52:42 +0000183
184 char arg_data[8192];
185 size_t arg_data_size = sizeof(arg_data);
Johnny Chen30213ff2012-01-05 19:17:38 +0000186 if (::sysctl (mib, 4, arg_data, &arg_data_size , NULL, 0) == 0)
Johnny Chen8f3d8382011-08-02 20:52:42 +0000187 {
188 DataExtractor data (arg_data, arg_data_size, lldb::endian::InlHostByteOrder(), sizeof(void *));
Ashok Thirumurthi0f3b9b82013-05-01 20:38:19 +0000189 lldb::offset_t offset = 0;
Johnny Chen8f3d8382011-08-02 20:52:42 +0000190 const char *cstr;
Johnny Chen30213ff2012-01-05 19:17:38 +0000191
Johnny Chen8f3d8382011-08-02 20:52:42 +0000192 cstr = data.GetCStr (&offset);
193 if (cstr)
194 {
195 process_info.GetExecutableFile().SetFile(cstr, false);
196
Ed Maste5d34af32013-06-24 15:09:18 +0000197 if (!(match_info_ptr == NULL ||
Johnny Chen8f3d8382011-08-02 20:52:42 +0000198 NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
199 match_info_ptr->GetNameMatchType(),
Johnny Chen30213ff2012-01-05 19:17:38 +0000200 match_info_ptr->GetProcessInfo().GetName())))
201 return false;
202
203 Args &proc_args = process_info.GetArguments();
204 while (1)
Johnny Chen8f3d8382011-08-02 20:52:42 +0000205 {
Johnny Chen30213ff2012-01-05 19:17:38 +0000206 const uint8_t *p = data.PeekData(offset, 1);
207 while ((p != NULL) && (*p == '\0') && offset < arg_data_size)
Johnny Chen8f3d8382011-08-02 20:52:42 +0000208 {
Johnny Chen8f3d8382011-08-02 20:52:42 +0000209 ++offset;
Johnny Chen30213ff2012-01-05 19:17:38 +0000210 p = data.PeekData(offset, 1);
Johnny Chen8f3d8382011-08-02 20:52:42 +0000211 }
Johnny Chen30213ff2012-01-05 19:17:38 +0000212 if (p == NULL || offset >= arg_data_size)
213 return true;
214
215 cstr = data.GetCStr(&offset);
216 if (cstr)
217 proc_args.AppendArgument(cstr);
218 else
219 return true;
Johnny Chen8f3d8382011-08-02 20:52:42 +0000220 }
221 }
Ed Maste5d34af32013-06-24 15:09:18 +0000222 }
Johnny Chen8f3d8382011-08-02 20:52:42 +0000223 }
224 return false;
225}
226
227static bool
228GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info)
229{
230 if (process_info.ProcessIDIsValid()) {
Johnny Chen30213ff2012-01-05 19:17:38 +0000231 process_info.GetArchitecture() = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
232 return true;
Johnny Chen8f3d8382011-08-02 20:52:42 +0000233 }
234 process_info.GetArchitecture().Clear();
235 return false;
236}
237
238static bool
239GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info)
240{
241 struct kinfo_proc proc_kinfo;
242 size_t proc_kinfo_size;
243
Ed Maste5d34af32013-06-24 15:09:18 +0000244 if (process_info.ProcessIDIsValid())
Johnny Chen8f3d8382011-08-02 20:52:42 +0000245 {
246 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,
Filipe Cabecinhasd0b87d82012-09-11 18:11:16 +0000247 (int)process_info.GetProcessID() };
Johnny Chen8f3d8382011-08-02 20:52:42 +0000248 proc_kinfo_size = sizeof(struct kinfo_proc);
249
250 if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0)
251 {
252 if (proc_kinfo_size > 0)
253 {
254 process_info.SetParentProcessID (proc_kinfo.ki_ppid);
255 process_info.SetUserID (proc_kinfo.ki_ruid);
256 process_info.SetGroupID (proc_kinfo.ki_rgid);
257 process_info.SetEffectiveUserID (proc_kinfo.ki_uid);
258 if (proc_kinfo.ki_ngroups > 0)
259 process_info.SetEffectiveGroupID (proc_kinfo.ki_groups[0]);
260 else
Johnny Chen30213ff2012-01-05 19:17:38 +0000261 process_info.SetEffectiveGroupID (UINT32_MAX);
Johnny Chen8f3d8382011-08-02 20:52:42 +0000262 return true;
263 }
264 }
265 }
266 process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID);
267 process_info.SetUserID (UINT32_MAX);
268 process_info.SetGroupID (UINT32_MAX);
269 process_info.SetEffectiveUserID (UINT32_MAX);
Johnny Chen30213ff2012-01-05 19:17:38 +0000270 process_info.SetEffectiveGroupID (UINT32_MAX);
Johnny Chen8f3d8382011-08-02 20:52:42 +0000271 return false;
272}
273
274bool
275Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
276{
277 process_info.SetProcessID(pid);
278 if (GetFreeBSDProcessArgs(NULL, process_info)) {
279 // should use libprocstat instead of going right into sysctl?
280 GetFreeBSDProcessCPUType(process_info);
281 GetFreeBSDProcessUserAndGroup(process_info);
282 return true;
283 }
284 process_info.Clear();
285 return false;
286}
Johnny Chen30213ff2012-01-05 19:17:38 +0000287
288lldb::DataBufferSP
289Host::GetAuxvData(lldb_private::Process *process)
290{
291 int mib[2] = { CTL_KERN, KERN_PS_STRINGS };
292 void *ps_strings_addr, *auxv_addr;
293 size_t ps_strings_size = sizeof(void *);
294 Elf_Auxinfo aux_info[AT_COUNT];
295 struct ps_strings ps_strings;
296 struct ptrace_io_desc pid;
297 DataBufferSP buf_sp;
Greg Clayton7b0992d2013-04-18 22:45:39 +0000298 std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0));
Johnny Chen30213ff2012-01-05 19:17:38 +0000299
300 if (::sysctl(mib, 2, &ps_strings_addr, &ps_strings_size, NULL, 0) == 0) {
301 pid.piod_op = PIOD_READ_D;
302 pid.piod_addr = &ps_strings;
303 pid.piod_offs = ps_strings_addr;
304 pid.piod_len = sizeof(ps_strings);
Filipe Cabecinhasd0b87d82012-09-11 18:11:16 +0000305 if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) {
Johnny Chen30213ff2012-01-05 19:17:38 +0000306 perror("failed to fetch ps_strings");
307 buf_ap.release();
308 goto done;
309 }
310
311 auxv_addr = ps_strings.ps_envstr + ps_strings.ps_nenvstr + 1;
312
313 pid.piod_addr = aux_info;
314 pid.piod_offs = auxv_addr;
315 pid.piod_len = sizeof(aux_info);
Filipe Cabecinhasd0b87d82012-09-11 18:11:16 +0000316 if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) {
Johnny Chen30213ff2012-01-05 19:17:38 +0000317 perror("failed to fetch aux_info");
318 buf_ap.release();
319 goto done;
320 }
321 memcpy(buf_ap->GetBytes(), aux_info, pid.piod_len);
322 buf_sp.reset(buf_ap.release());
323 } else {
324 perror("sysctl failed on ps_strings");
325 }
326
327 done:
328 return buf_sp;
329}