]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/llvm/tools/lldb/source/Host/freebsd/Host.cpp
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / llvm / tools / lldb / source / Host / freebsd / Host.cpp
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     Host::SetShortThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name, 16);
80 }
81
82 std::string
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
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
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
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
148 Host::LaunchProcess (ProcessLaunchInfo &launch_info)
149 {
150     Error error;
151     assert(!"Not implemented yet!!!");
152     return error;
153 }
154
155 bool
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
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
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
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
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
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
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 }