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#include <sys/proc.h>
19
20#include <sys/ptrace.h>
21#include <sys/exec.h>
22#include <machine/elf.h>
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/Module.h"
31#include "lldb/Core/DataExtractor.h"
32#include "lldb/Core/StreamFile.h"
33#include "lldb/Core/StreamString.h"
34#include "lldb/Core/Log.h"
35#include "lldb/Target/Process.h"
36#include "lldb/Target/Platform.h"
37
38#include "lldb/Core/DataBufferHeap.h"
39#include "lldb/Core/DataExtractor.h"
40#include "lldb/Utility/CleanUp.h"
41
42#include "llvm/Support/Host.h"
43
44
45extern "C" {
46    extern char **environ;
47}
48
49using namespace lldb;
50using namespace lldb_private;
51
52class FreeBSDThread
53{
54public:
55    FreeBSDThread(const char *thread_name)
56    {
57        Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name);
58    }
59    static void PThreadDestructor (void *v)
60    {
61        delete (FreeBSDThread*)v;
62    }
63};
64
65static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT;
66static pthread_key_t g_thread_create_key = 0;
67
68static void
69InitThreadCreated()
70{
71    ::pthread_key_create (&g_thread_create_key, FreeBSDThread::PThreadDestructor);
72}
73
74void
75Host::ThreadCreated (const char *thread_name)
76{
77    ::pthread_once (&g_thread_create_once, InitThreadCreated);
78    if (g_thread_create_key)
79    {
80        ::pthread_setspecific (g_thread_create_key, new FreeBSDThread(thread_name));
81    }
82
83    Host::SetShortThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name, 16);
84}
85
86std::string
87Host::GetThreadName (lldb::pid_t pid, lldb::tid_t tid)
88{
89    std::string thread_name;
90    return thread_name;
91}
92
93void
94Host::Backtrace (Stream &strm, uint32_t max_frames)
95{
96    char backtrace_path[] = "/tmp/lldb-backtrace-tmp-XXXXXX";
97    int backtrace_fd = ::mkstemp (backtrace_path);
98    if (backtrace_fd != -1)
99    {
100        std::vector<void *> frame_buffer (max_frames, NULL);
101        int count = ::backtrace (&frame_buffer[0], frame_buffer.size());
102        ::backtrace_symbols_fd (&frame_buffer[0], count, backtrace_fd);
103
104        const off_t buffer_size = ::lseek(backtrace_fd, 0, SEEK_CUR);
105
106        if (::lseek(backtrace_fd, 0, SEEK_SET) == 0)
107        {
108            char *buffer = (char *)::malloc (buffer_size);
109            if (buffer)
110            {
111                ssize_t bytes_read = ::read (backtrace_fd, buffer, buffer_size);
112                if (bytes_read > 0)
113                    strm.Write(buffer, bytes_read);
114                ::free (buffer);
115            }
116        }
117        ::close (backtrace_fd);
118        ::unlink (backtrace_path);
119    }
120}
121
122size_t
123Host::GetEnvironment (StringList &env)
124{
125    char *v;
126    char **var = environ;
127    for (; var != NULL && *var != NULL; ++var)
128    {
129        v = strchr(*var, (int)'-');
130        if (v == NULL)
131            continue;
132        env.AppendString(v);
133    }
134    return env.GetSize();
135}
136
137bool
138Host::GetOSVersion(uint32_t &major,
139                   uint32_t &minor,
140                   uint32_t &update)
141{
142    struct utsname un;
143
144    ::memset(&un, 0, sizeof(utsname));
145    if (uname(&un) < 0)
146        return false;
147
148    int status = sscanf(un.release, "%u.%u", &major, &minor);
149    return status == 2;
150}
151
152bool
153Host::GetOSBuildString (std::string &s)
154{
155    int mib[2] = { CTL_KERN, KERN_OSREV };
156    char osrev_str[12];
157    uint32_t osrev = 0;
158    size_t osrev_len = sizeof(osrev);
159
160    if (::sysctl (mib, 2, &osrev, &osrev_len, NULL, 0) == 0)
161    {
162        ::snprintf(osrev_str, sizeof(osrev_str), "%-8.8u", osrev);
163        s.assign (osrev_str);
164        return true;
165    }
166
167    s.clear();
168    return false;
169}
170
171bool
172Host::GetOSKernelDescription (std::string &s)
173{
174    struct utsname un;
175
176    ::memset(&un, 0, sizeof(utsname));
177    s.clear();
178
179    if (uname(&un) < 0)
180    return false;
181
182    s.assign (un.version);
183
184    return true;
185}
186
187static bool
188GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
189                      ProcessInstanceInfo &process_info)
190{
191    if (process_info.ProcessIDIsValid())
192    {
193        int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, (int)process_info.GetProcessID() };
194
195        char arg_data[8192];
196        size_t arg_data_size = sizeof(arg_data);
197        if (::sysctl (mib, 4, arg_data, &arg_data_size , NULL, 0) == 0)
198        {
199            DataExtractor data (arg_data, arg_data_size, lldb::endian::InlHostByteOrder(), sizeof(void *));
200            lldb::offset_t offset = 0;
201            const char *cstr;
202
203            cstr = data.GetCStr (&offset);
204            if (cstr)
205            {
206                process_info.GetExecutableFile().SetFile(cstr, false);
207
208                if (!(match_info_ptr == NULL ||
209                    NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
210                                 match_info_ptr->GetNameMatchType(),
211                                 match_info_ptr->GetProcessInfo().GetName())))
212                    return false;
213
214                Args &proc_args = process_info.GetArguments();
215                while (1)
216                {
217                    const uint8_t *p = data.PeekData(offset, 1);
218                    while ((p != NULL) && (*p == '\0') && offset < arg_data_size)
219                    {
220                        ++offset;
221                        p = data.PeekData(offset, 1);
222                    }
223                    if (p == NULL || offset >= arg_data_size)
224                        return true;
225
226                    cstr = data.GetCStr(&offset);
227                    if (cstr)
228                        proc_args.AppendArgument(cstr);
229                    else
230                        return true;
231                }
232            }
233        }
234    }
235    return false;
236}
237
238static bool
239GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info)
240{
241    if (process_info.ProcessIDIsValid())
242    {
243        process_info.GetArchitecture() = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
244        return true;
245    }
246    process_info.GetArchitecture().Clear();
247    return false;
248}
249
250static bool
251GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info)
252{
253    struct kinfo_proc proc_kinfo;
254    size_t proc_kinfo_size;
255
256    if (process_info.ProcessIDIsValid())
257    {
258        int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,
259            (int)process_info.GetProcessID() };
260        proc_kinfo_size = sizeof(struct kinfo_proc);
261
262        if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0)
263        {
264            if (proc_kinfo_size > 0)
265            {
266                process_info.SetParentProcessID (proc_kinfo.ki_ppid);
267                process_info.SetUserID (proc_kinfo.ki_ruid);
268                process_info.SetGroupID (proc_kinfo.ki_rgid);
269                process_info.SetEffectiveUserID (proc_kinfo.ki_uid);
270                if (proc_kinfo.ki_ngroups > 0)
271                    process_info.SetEffectiveGroupID (proc_kinfo.ki_groups[0]);
272                else
273                    process_info.SetEffectiveGroupID (UINT32_MAX);
274                return true;
275            }
276        }
277    }
278    process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID);
279    process_info.SetUserID (UINT32_MAX);
280    process_info.SetGroupID (UINT32_MAX);
281    process_info.SetEffectiveUserID (UINT32_MAX);
282    process_info.SetEffectiveGroupID (UINT32_MAX);
283    return false;
284}
285
286uint32_t
287Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
288{
289    std::vector<struct kinfo_proc> kinfos;
290
291    int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
292
293    size_t pid_data_size = 0;
294    if (::sysctl (mib, 3, NULL, &pid_data_size, NULL, 0) != 0)
295        return 0;
296
297    // Add a few extra in case a few more show up
298    const size_t estimated_pid_count = (pid_data_size / sizeof(struct kinfo_proc)) + 10;
299
300    kinfos.resize (estimated_pid_count);
301    pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
302
303    if (::sysctl (mib, 3, &kinfos[0], &pid_data_size, NULL, 0) != 0)
304        return 0;
305
306    const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
307
308    bool all_users = match_info.GetMatchAllUsers();
309    const lldb::pid_t our_pid = getpid();
310    const uid_t our_uid = getuid();
311    for (int i = 0; i < actual_pid_count; i++)
312    {
313        const struct kinfo_proc &kinfo = kinfos[i];
314        const bool kinfo_user_matches = (all_users ||
315                                         (kinfo.ki_ruid == our_uid) ||
316                                         // Special case, if lldb is being run as root we can attach to anything.
317                                         (our_uid == 0)
318                                         );
319
320        if (kinfo_user_matches == false      || // Make sure the user is acceptable
321            kinfo.ki_pid == our_pid          || // Skip this process
322            kinfo.ki_pid == 0                || // Skip kernel (kernel pid is zero)
323            kinfo.ki_stat == SZOMB    || // Zombies are bad, they like brains...
324            kinfo.ki_flag & P_TRACED  || // Being debugged?
325            kinfo.ki_flag & P_WEXIT)     // Working on exiting
326            continue;
327
328        // Every thread is a process in FreeBSD, but all the threads of a single process
329        // have the same pid. Do not store the process info in the result list if a process
330        // with given identifier is already registered there.
331        bool already_registered = false;
332        for (uint32_t pi = 0;
333             !already_registered &&
334             (const int)kinfo.ki_numthreads > 1 &&
335             pi < (const uint32_t)process_infos.GetSize(); pi++)
336            already_registered = (process_infos.GetProcessIDAtIndex(pi) == (uint32_t)kinfo.ki_pid);
337
338        if (already_registered)
339            continue;
340
341        ProcessInstanceInfo process_info;
342        process_info.SetProcessID (kinfo.ki_pid);
343        process_info.SetParentProcessID (kinfo.ki_ppid);
344        process_info.SetUserID (kinfo.ki_ruid);
345        process_info.SetGroupID (kinfo.ki_rgid);
346        process_info.SetEffectiveUserID (kinfo.ki_svuid);
347        process_info.SetEffectiveGroupID (kinfo.ki_svgid);
348
349        // Make sure our info matches before we go fetch the name and cpu type
350        if (match_info.Matches (process_info) &&
351            GetFreeBSDProcessArgs (&match_info, process_info))
352        {
353            GetFreeBSDProcessCPUType (process_info);
354            if (match_info.Matches (process_info))
355                process_infos.Append (process_info);
356        }
357    }
358
359    return process_infos.GetSize();
360}
361
362bool
363Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
364{
365    process_info.SetProcessID(pid);
366
367    if (GetFreeBSDProcessArgs(NULL, process_info))
368    {
369        // should use libprocstat instead of going right into sysctl?
370        GetFreeBSDProcessCPUType(process_info);
371        GetFreeBSDProcessUserAndGroup(process_info);
372        return true;
373    }
374
375    process_info.Clear();
376    return false;
377}
378
379lldb::DataBufferSP
380Host::GetAuxvData(lldb_private::Process *process)
381{
382   int mib[2] = { CTL_KERN, KERN_PS_STRINGS };
383   void *ps_strings_addr, *auxv_addr;
384   size_t ps_strings_size = sizeof(void *);
385   Elf_Auxinfo aux_info[AT_COUNT];
386   struct ps_strings ps_strings;
387   struct ptrace_io_desc pid;
388   DataBufferSP buf_sp;
389   std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0));
390
391   if (::sysctl(mib, 2, &ps_strings_addr, &ps_strings_size, NULL, 0) == 0) {
392           pid.piod_op = PIOD_READ_D;
393           pid.piod_addr = &ps_strings;
394           pid.piod_offs = ps_strings_addr;
395           pid.piod_len = sizeof(ps_strings);
396           if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) {
397                   perror("failed to fetch ps_strings");
398                   buf_ap.release();
399                   goto done;
400           }
401
402           auxv_addr = ps_strings.ps_envstr + ps_strings.ps_nenvstr + 1;
403
404           pid.piod_addr = aux_info;
405           pid.piod_offs = auxv_addr;
406           pid.piod_len = sizeof(aux_info);
407           if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) {
408                   perror("failed to fetch aux_info");
409                   buf_ap.release();
410                   goto done;
411           }
412           memcpy(buf_ap->GetBytes(), aux_info, pid.piod_len);
413           buf_sp.reset(buf_ap.release());
414   } else {
415           perror("sysctl failed on ps_strings");
416   }
417
418   done:
419   return buf_sp;
420}
421