• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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