blob: 5f065e2810fe39a4abdb91560f652813710edd9d [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>
Johnny Chen8f3d8382011-08-02 20:52:42 +000016#include <sys/sysctl.h>
Daniel Maleae0f8f572013-08-26 23:57:52 +000017#include <sys/proc.h>
Johnny Chen8f3d8382011-08-02 20:52:42 +000018
Johnny Chen30213ff2012-01-05 19:17:38 +000019#include <sys/ptrace.h>
20#include <sys/exec.h>
21#include <machine/elf.h>
22
Johnny Chen8f3d8382011-08-02 20:52:42 +000023// C++ Includes
24// Other libraries and framework includes
25// Project includes
26#include "lldb/Core/Error.h"
27#include "lldb/Host/Endian.h"
28#include "lldb/Host/Host.h"
Zachary Turner13b18262014-08-20 16:42:51 +000029#include "lldb/Host/HostInfo.h"
Daniel Maleae0f8f572013-08-26 23:57:52 +000030#include "lldb/Core/Module.h"
Johnny Chen8f3d8382011-08-02 20:52:42 +000031#include "lldb/Core/DataExtractor.h"
32#include "lldb/Core/StreamFile.h"
33#include "lldb/Core/StreamString.h"
Daniel Malea34070302013-08-27 16:03:22 +000034#include "lldb/Core/Log.h"
Johnny Chen8f3d8382011-08-02 20:52:42 +000035#include "lldb/Target/Process.h"
Daniel Maleae0f8f572013-08-26 23:57:52 +000036#include "lldb/Target/Platform.h"
Johnny Chen8f3d8382011-08-02 20:52:42 +000037
Johnny Chen30213ff2012-01-05 19:17:38 +000038#include "lldb/Core/DataBufferHeap.h"
39#include "lldb/Core/DataExtractor.h"
Daniel Maleae0f8f572013-08-26 23:57:52 +000040#include "lldb/Utility/CleanUp.h"
41
Todd Fiala4ceced32014-08-29 17:35:57 +000042#include "Plugins/Process/Utility/FreeBSDSignals.h"
Johnny Chen8f3d8382011-08-02 20:52:42 +000043
Todd Fiala4ceced32014-08-29 17:35:57 +000044#include "llvm/Support/Host.h"
Johnny Chen30213ff2012-01-05 19:17:38 +000045
Johnny Chen8f3d8382011-08-02 20:52:42 +000046extern "C" {
Johnny Chen30213ff2012-01-05 19:17:38 +000047 extern char **environ;
Johnny Chen8f3d8382011-08-02 20:52:42 +000048}
49
50using namespace lldb;
51using namespace lldb_private;
52
Johnny Chen8f3d8382011-08-02 20:52:42 +000053void
54Host::Backtrace (Stream &strm, uint32_t max_frames)
55{
56 char backtrace_path[] = "/tmp/lldb-backtrace-tmp-XXXXXX";
57 int backtrace_fd = ::mkstemp (backtrace_path);
58 if (backtrace_fd != -1)
59 {
60 std::vector<void *> frame_buffer (max_frames, NULL);
61 int count = ::backtrace (&frame_buffer[0], frame_buffer.size());
62 ::backtrace_symbols_fd (&frame_buffer[0], count, backtrace_fd);
Johnny Chen30213ff2012-01-05 19:17:38 +000063
Johnny Chen8f3d8382011-08-02 20:52:42 +000064 const off_t buffer_size = ::lseek(backtrace_fd, 0, SEEK_CUR);
65
66 if (::lseek(backtrace_fd, 0, SEEK_SET) == 0)
67 {
68 char *buffer = (char *)::malloc (buffer_size);
69 if (buffer)
70 {
71 ssize_t bytes_read = ::read (backtrace_fd, buffer, buffer_size);
72 if (bytes_read > 0)
73 strm.Write(buffer, bytes_read);
74 ::free (buffer);
75 }
76 }
77 ::close (backtrace_fd);
78 ::unlink (backtrace_path);
79 }
80}
81
82size_t
83Host::GetEnvironment (StringList &env)
84{
85 char *v;
86 char **var = environ;
Daniel Maleae0f8f572013-08-26 23:57:52 +000087 for (; var != NULL && *var != NULL; ++var)
88 {
Johnny Chen8f3d8382011-08-02 20:52:42 +000089 v = strchr(*var, (int)'-');
90 if (v == NULL)
91 continue;
92 env.AppendString(v);
93 }
94 return env.GetSize();
95}
96
Johnny Chen8f3d8382011-08-02 20:52:42 +000097static bool
98GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
99 ProcessInstanceInfo &process_info)
100{
Daniel Maleae0f8f572013-08-26 23:57:52 +0000101 if (process_info.ProcessIDIsValid())
102 {
Filipe Cabecinhasd0b87d82012-09-11 18:11:16 +0000103 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, (int)process_info.GetProcessID() };
Johnny Chen8f3d8382011-08-02 20:52:42 +0000104
105 char arg_data[8192];
106 size_t arg_data_size = sizeof(arg_data);
Johnny Chen30213ff2012-01-05 19:17:38 +0000107 if (::sysctl (mib, 4, arg_data, &arg_data_size , NULL, 0) == 0)
Johnny Chen8f3d8382011-08-02 20:52:42 +0000108 {
109 DataExtractor data (arg_data, arg_data_size, lldb::endian::InlHostByteOrder(), sizeof(void *));
Ashok Thirumurthi0f3b9b82013-05-01 20:38:19 +0000110 lldb::offset_t offset = 0;
Johnny Chen8f3d8382011-08-02 20:52:42 +0000111 const char *cstr;
Johnny Chen30213ff2012-01-05 19:17:38 +0000112
Johnny Chen8f3d8382011-08-02 20:52:42 +0000113 cstr = data.GetCStr (&offset);
114 if (cstr)
115 {
116 process_info.GetExecutableFile().SetFile(cstr, false);
117
Ed Maste5d34af32013-06-24 15:09:18 +0000118 if (!(match_info_ptr == NULL ||
Johnny Chen8f3d8382011-08-02 20:52:42 +0000119 NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
120 match_info_ptr->GetNameMatchType(),
Johnny Chen30213ff2012-01-05 19:17:38 +0000121 match_info_ptr->GetProcessInfo().GetName())))
122 return false;
123
124 Args &proc_args = process_info.GetArguments();
125 while (1)
Johnny Chen8f3d8382011-08-02 20:52:42 +0000126 {
Johnny Chen30213ff2012-01-05 19:17:38 +0000127 const uint8_t *p = data.PeekData(offset, 1);
128 while ((p != NULL) && (*p == '\0') && offset < arg_data_size)
Johnny Chen8f3d8382011-08-02 20:52:42 +0000129 {
Johnny Chen8f3d8382011-08-02 20:52:42 +0000130 ++offset;
Johnny Chen30213ff2012-01-05 19:17:38 +0000131 p = data.PeekData(offset, 1);
Johnny Chen8f3d8382011-08-02 20:52:42 +0000132 }
Johnny Chen30213ff2012-01-05 19:17:38 +0000133 if (p == NULL || offset >= arg_data_size)
134 return true;
135
136 cstr = data.GetCStr(&offset);
137 if (cstr)
138 proc_args.AppendArgument(cstr);
139 else
140 return true;
Johnny Chen8f3d8382011-08-02 20:52:42 +0000141 }
142 }
Ed Maste5d34af32013-06-24 15:09:18 +0000143 }
Johnny Chen8f3d8382011-08-02 20:52:42 +0000144 }
145 return false;
146}
147
148static bool
149GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info)
150{
Daniel Maleae0f8f572013-08-26 23:57:52 +0000151 if (process_info.ProcessIDIsValid())
152 {
Zachary Turner13b18262014-08-20 16:42:51 +0000153 process_info.GetArchitecture() = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
Johnny Chen30213ff2012-01-05 19:17:38 +0000154 return true;
Johnny Chen8f3d8382011-08-02 20:52:42 +0000155 }
156 process_info.GetArchitecture().Clear();
157 return false;
158}
159
160static bool
161GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info)
162{
163 struct kinfo_proc proc_kinfo;
164 size_t proc_kinfo_size;
165
Ed Maste5d34af32013-06-24 15:09:18 +0000166 if (process_info.ProcessIDIsValid())
Johnny Chen8f3d8382011-08-02 20:52:42 +0000167 {
168 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,
Filipe Cabecinhasd0b87d82012-09-11 18:11:16 +0000169 (int)process_info.GetProcessID() };
Johnny Chen8f3d8382011-08-02 20:52:42 +0000170 proc_kinfo_size = sizeof(struct kinfo_proc);
171
172 if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0)
173 {
174 if (proc_kinfo_size > 0)
175 {
176 process_info.SetParentProcessID (proc_kinfo.ki_ppid);
177 process_info.SetUserID (proc_kinfo.ki_ruid);
178 process_info.SetGroupID (proc_kinfo.ki_rgid);
179 process_info.SetEffectiveUserID (proc_kinfo.ki_uid);
180 if (proc_kinfo.ki_ngroups > 0)
181 process_info.SetEffectiveGroupID (proc_kinfo.ki_groups[0]);
182 else
Johnny Chen30213ff2012-01-05 19:17:38 +0000183 process_info.SetEffectiveGroupID (UINT32_MAX);
Johnny Chen8f3d8382011-08-02 20:52:42 +0000184 return true;
185 }
186 }
187 }
188 process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID);
189 process_info.SetUserID (UINT32_MAX);
190 process_info.SetGroupID (UINT32_MAX);
191 process_info.SetEffectiveUserID (UINT32_MAX);
Johnny Chen30213ff2012-01-05 19:17:38 +0000192 process_info.SetEffectiveGroupID (UINT32_MAX);
Johnny Chen8f3d8382011-08-02 20:52:42 +0000193 return false;
194}
195
Daniel Maleae0f8f572013-08-26 23:57:52 +0000196uint32_t
197Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
198{
199 std::vector<struct kinfo_proc> kinfos;
200
201 int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
202
203 size_t pid_data_size = 0;
204 if (::sysctl (mib, 3, NULL, &pid_data_size, NULL, 0) != 0)
205 return 0;
206
207 // Add a few extra in case a few more show up
208 const size_t estimated_pid_count = (pid_data_size / sizeof(struct kinfo_proc)) + 10;
209
210 kinfos.resize (estimated_pid_count);
211 pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
212
213 if (::sysctl (mib, 3, &kinfos[0], &pid_data_size, NULL, 0) != 0)
214 return 0;
215
216 const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
217
218 bool all_users = match_info.GetMatchAllUsers();
Ed Maste2c2f83e2014-02-28 13:46:51 +0000219 const ::pid_t our_pid = getpid();
Daniel Maleae0f8f572013-08-26 23:57:52 +0000220 const uid_t our_uid = getuid();
Ed Maste2c2f83e2014-02-28 13:46:51 +0000221 for (size_t i = 0; i < actual_pid_count; i++)
Daniel Maleae0f8f572013-08-26 23:57:52 +0000222 {
223 const struct kinfo_proc &kinfo = kinfos[i];
224 const bool kinfo_user_matches = (all_users ||
225 (kinfo.ki_ruid == our_uid) ||
226 // Special case, if lldb is being run as root we can attach to anything.
227 (our_uid == 0)
228 );
229
230 if (kinfo_user_matches == false || // Make sure the user is acceptable
231 kinfo.ki_pid == our_pid || // Skip this process
232 kinfo.ki_pid == 0 || // Skip kernel (kernel pid is zero)
233 kinfo.ki_stat == SZOMB || // Zombies are bad, they like brains...
234 kinfo.ki_flag & P_TRACED || // Being debugged?
235 kinfo.ki_flag & P_WEXIT) // Working on exiting
236 continue;
237
238 // Every thread is a process in FreeBSD, but all the threads of a single process
239 // have the same pid. Do not store the process info in the result list if a process
240 // with given identifier is already registered there.
241 bool already_registered = false;
242 for (uint32_t pi = 0;
243 !already_registered &&
244 (const int)kinfo.ki_numthreads > 1 &&
245 pi < (const uint32_t)process_infos.GetSize(); pi++)
246 already_registered = (process_infos.GetProcessIDAtIndex(pi) == (uint32_t)kinfo.ki_pid);
247
248 if (already_registered)
249 continue;
250
251 ProcessInstanceInfo process_info;
252 process_info.SetProcessID (kinfo.ki_pid);
253 process_info.SetParentProcessID (kinfo.ki_ppid);
254 process_info.SetUserID (kinfo.ki_ruid);
255 process_info.SetGroupID (kinfo.ki_rgid);
256 process_info.SetEffectiveUserID (kinfo.ki_svuid);
257 process_info.SetEffectiveGroupID (kinfo.ki_svgid);
258
259 // Make sure our info matches before we go fetch the name and cpu type
260 if (match_info.Matches (process_info) &&
261 GetFreeBSDProcessArgs (&match_info, process_info))
262 {
263 GetFreeBSDProcessCPUType (process_info);
264 if (match_info.Matches (process_info))
265 process_infos.Append (process_info);
266 }
267 }
268
269 return process_infos.GetSize();
270}
271
Johnny Chen8f3d8382011-08-02 20:52:42 +0000272bool
273Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
274{
275 process_info.SetProcessID(pid);
Daniel Maleae0f8f572013-08-26 23:57:52 +0000276
277 if (GetFreeBSDProcessArgs(NULL, process_info))
278 {
Johnny Chen8f3d8382011-08-02 20:52:42 +0000279 // should use libprocstat instead of going right into sysctl?
280 GetFreeBSDProcessCPUType(process_info);
281 GetFreeBSDProcessUserAndGroup(process_info);
282 return true;
283 }
Daniel Maleae0f8f572013-08-26 23:57:52 +0000284
Johnny Chen8f3d8382011-08-02 20:52:42 +0000285 process_info.Clear();
286 return false;
287}
Johnny Chen30213ff2012-01-05 19:17:38 +0000288
289lldb::DataBufferSP
290Host::GetAuxvData(lldb_private::Process *process)
291{
292 int mib[2] = { CTL_KERN, KERN_PS_STRINGS };
293 void *ps_strings_addr, *auxv_addr;
294 size_t ps_strings_size = sizeof(void *);
295 Elf_Auxinfo aux_info[AT_COUNT];
296 struct ps_strings ps_strings;
297 struct ptrace_io_desc pid;
298 DataBufferSP buf_sp;
Greg Clayton7b0992d2013-04-18 22:45:39 +0000299 std::unique_ptr<DataBufferHeap> buf_ap(new DataBufferHeap(1024, 0));
Johnny Chen30213ff2012-01-05 19:17:38 +0000300
301 if (::sysctl(mib, 2, &ps_strings_addr, &ps_strings_size, NULL, 0) == 0) {
302 pid.piod_op = PIOD_READ_D;
303 pid.piod_addr = &ps_strings;
304 pid.piod_offs = ps_strings_addr;
305 pid.piod_len = sizeof(ps_strings);
Filipe Cabecinhasd0b87d82012-09-11 18:11:16 +0000306 if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) {
Johnny Chen30213ff2012-01-05 19:17:38 +0000307 perror("failed to fetch ps_strings");
308 buf_ap.release();
309 goto done;
310 }
311
312 auxv_addr = ps_strings.ps_envstr + ps_strings.ps_nenvstr + 1;
313
314 pid.piod_addr = aux_info;
315 pid.piod_offs = auxv_addr;
316 pid.piod_len = sizeof(aux_info);
Filipe Cabecinhasd0b87d82012-09-11 18:11:16 +0000317 if (::ptrace(PT_IO, process->GetID(), (caddr_t)&pid, 0)) {
Johnny Chen30213ff2012-01-05 19:17:38 +0000318 perror("failed to fetch aux_info");
319 buf_ap.release();
320 goto done;
321 }
322 memcpy(buf_ap->GetBytes(), aux_info, pid.piod_len);
323 buf_sp.reset(buf_ap.release());
324 } else {
325 perror("sysctl failed on ps_strings");
326 }
327
328 done:
329 return buf_sp;
330}
Todd Fiala4ceced32014-08-29 17:35:57 +0000331
332const UnixSignalsSP&
333Host::GetUnixSignals ()
334{
335 static const lldb_private::UnixSignalsSP s_unix_signals_sp (new FreeBSDSignals ());
336 return s_unix_signals_sp;
337}
338