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:
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 
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
65 InitThreadCreated()
66 {
67     ::pthread_key_create (&g_thread_create_key, FreeBSDThread::PThreadDestructor);
68 }
69 
70 void
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 
80 void
81 Host::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);
90 
91         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 
109 size_t
110 Host::GetEnvironment (StringList &env)
111 {
112     char *v;
113     char **var = environ;
114     for (; var != NULL && *var != NULL; ++var) {
115         v = strchr(*var, (int)'-');
116         if (v == NULL)
117             continue;
118         env.AppendString(v);
119     }
120     return env.GetSize();
121 }
122 
123 bool
124 Host::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 
138 Error
139 Host::LaunchProcess (ProcessLaunchInfo &launch_info)
140 {
141     Error error;
142     assert(!"Not implemented yet!!!");
143     return error;
144 }
145 
146 bool
147 Host::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 
161 bool
162 Host::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 
176 static bool
177 GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
178                       ProcessInstanceInfo &process_info)
179 {
180     if (process_info.ProcessIDIsValid()) {
181         int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, (int)process_info.GetProcessID() };
182 
183         char arg_data[8192];
184         size_t arg_data_size = sizeof(arg_data);
185         if (::sysctl (mib, 4, arg_data, &arg_data_size , NULL, 0) == 0)
186         {
187             DataExtractor data (arg_data, arg_data_size, lldb::endian::InlHostByteOrder(), sizeof(void *));
188             lldb::offset_t offset = 0;
189             const char *cstr;
190 
191             cstr = data.GetCStr (&offset);
192             if (cstr)
193             {
194                 process_info.GetExecutableFile().SetFile(cstr, false);
195 
196                 if (!(match_info_ptr == NULL ||
197                     NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
198                                  match_info_ptr->GetNameMatchType(),
199                                  match_info_ptr->GetProcessInfo().GetName())))
200                     return false;
201 
202                 Args &proc_args = process_info.GetArguments();
203                 while (1)
204                 {
205                     const uint8_t *p = data.PeekData(offset, 1);
206                     while ((p != NULL) && (*p == '\0') && offset < arg_data_size)
207                     {
208                         ++offset;
209                         p = data.PeekData(offset, 1);
210                     }
211                     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;
219                 }
220             }
221         }
222     }
223     return false;
224 }
225 
226 static bool
227 GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info)
228 {
229     if (process_info.ProcessIDIsValid()) {
230         process_info.GetArchitecture() = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
231         return true;
232     }
233     process_info.GetArchitecture().Clear();
234     return false;
235 }
236 
237 static bool
238 GetFreeBSDProcessUserAndGroup(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,
246             (int)process_info.GetProcessID() };
247         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
260                     process_info.SetEffectiveGroupID (UINT32_MAX);
261                 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);
269     process_info.SetEffectiveGroupID (UINT32_MAX);
270     return false;
271 }
272 
273 bool
274 Host::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 }
286 
287 lldb::DataBufferSP
288 Host::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;
297    std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0));
298 
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);
304            if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) {
305                    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);
315            if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) {
316                    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 }
329