blob: 2325a935323a490b7bafe06a31cbeb763b1ebfe1 [file] [log] [blame]
Bruce Mitchener910af4d2015-10-13 05:04:13 +00001//===-- source/Host/netbsd/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/sysctl.h>
17#include <sys/proc.h>
18
19#include <limits.h>
20
21#include <sys/ptrace.h>
22#include <sys/exec.h>
23#include <elf.h>
24#include <kvm.h>
25
26// C++ Includes
27// Other libraries and framework includes
28// Project includes
29#include "lldb/Core/Error.h"
30#include "lldb/Host/Endian.h"
31#include "lldb/Host/Host.h"
32#include "lldb/Host/HostInfo.h"
33#include "lldb/Core/Module.h"
34#include "lldb/Core/DataExtractor.h"
35#include "lldb/Core/StreamFile.h"
36#include "lldb/Core/StreamString.h"
37#include "lldb/Core/Log.h"
38#include "lldb/Target/Process.h"
39#include "lldb/Target/Platform.h"
40
41#include "lldb/Core/DataBufferHeap.h"
42#include "lldb/Core/DataExtractor.h"
43#include "lldb/Utility/CleanUp.h"
44#include "lldb/Utility/NameMatches.h"
45
46#include "llvm/Support/Host.h"
47
48extern "C" {
49 extern char **environ;
50}
51
52using namespace lldb;
53using namespace lldb_private;
54
55size_t
56Host::GetEnvironment (StringList &env)
57{
58 char *v;
59 char **var = environ;
60 for (; var != NULL && *var != NULL; ++var)
61 {
62 v = ::strchr(*var, (int)'-');
63 if (v == NULL)
64 continue;
65 env.AppendString(v);
66 }
67 return env.GetSize();
68}
69
70static bool
71GetNetBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
72 ProcessInstanceInfo &process_info)
73{
74 if (!process_info.ProcessIDIsValid())
75 return false;
76
77 int pid = process_info.GetProcessID();
78
79 int mib[4] = { CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV };
80
81 char arg_data[8192];
82 size_t arg_data_size = sizeof(arg_data);
83 if (::sysctl (mib, 4, arg_data, &arg_data_size , NULL, 0) != 0)
84 return false;
85
86 DataExtractor data (arg_data, arg_data_size, lldb::endian::InlHostByteOrder(), sizeof(void *));
87 lldb::offset_t offset = 0;
88 const char *cstr;
89
90 cstr = data.GetCStr (&offset);
91 if (!cstr)
92 return false;
93
94 process_info.GetExecutableFile().SetFile(cstr, false);
95
96 if (!(match_info_ptr == NULL ||
97 NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
98 match_info_ptr->GetNameMatchType(),
99 match_info_ptr->GetProcessInfo().GetName())))
100 return false;
101
102 Args &proc_args = process_info.GetArguments();
103 while (1)
104 {
105 const uint8_t *p = data.PeekData(offset, 1);
106 while ((p != NULL) && (*p == '\0') && offset < arg_data_size)
107 {
108 ++offset;
109 p = data.PeekData(offset, 1);
110 }
111 if (p == NULL || offset >= arg_data_size)
112 break;
113
114 cstr = data.GetCStr(&offset);
115 if (!cstr)
116 break;
117
118 proc_args.AppendArgument(cstr);
119 }
120
121 return true;
122}
123
124static bool
125GetNetBSDProcessCPUType (ProcessInstanceInfo &process_info)
126{
127 if (process_info.ProcessIDIsValid())
128 {
129 process_info.GetArchitecture() = HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
130 return true;
131 }
132 process_info.GetArchitecture().Clear();
133 return false;
134}
135
136static bool
137GetNetBSDProcessUserAndGroup(ProcessInstanceInfo &process_info)
138{
139 ::kvm_t *kdp;
140 char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */
141
142 struct ::kinfo_proc2 *proc_kinfo;
143 const int pid = process_info.GetProcessID();
144 int nproc;
145
146 if (!process_info.ProcessIDIsValid())
147 goto error;
148
149 if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)
150 goto error;
151
152 if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_PID, pid,
153 sizeof(struct ::kinfo_proc2),
154 &nproc)) == NULL) {
155 ::kvm_close(kdp);
156 goto error;
157 }
158
159 if (nproc < 1) {
160 ::kvm_close(kdp); /* XXX: we don't check for error here */
161 goto error;
162 }
163
164 process_info.SetParentProcessID (proc_kinfo->p_ppid);
165 process_info.SetUserID (proc_kinfo->p_ruid);
166 process_info.SetGroupID (proc_kinfo->p_rgid);
167 process_info.SetEffectiveUserID (proc_kinfo->p_uid);
168 process_info.SetEffectiveGroupID (proc_kinfo->p_gid);
169
170 ::kvm_close(kdp); /* XXX: we don't check for error here */
171
172 return true;
173
174error:
175 process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID);
176 process_info.SetUserID (UINT32_MAX);
177 process_info.SetGroupID (UINT32_MAX);
178 process_info.SetEffectiveUserID (UINT32_MAX);
179 process_info.SetEffectiveGroupID (UINT32_MAX);
180 return false;
181}
182
183uint32_t
184Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
185{
186 const ::pid_t our_pid = ::getpid();
187 const ::uid_t our_uid = ::getuid();
188
189 const bool all_users = match_info.GetMatchAllUsers() ||
190 // Special case, if lldb is being run as root we can attach to anything
191 (our_uid == 0);
192
193 kvm_t *kdp;
194 char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */
195 if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)
196 return 0;
197
198 struct ::kinfo_proc2 *proc_kinfo;
199 int nproc;
200 if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_ALL, 0,
201 sizeof(struct ::kinfo_proc2),
202 &nproc)) == NULL) {
203 ::kvm_close(kdp);
204 return 0;
205 }
206
207 for (int i = 0; i < nproc; i++) {
208 if (proc_kinfo[i].p_pid < 1)
209 continue; /* not valid */
210 /* Make sure the user is acceptable */
211 if (!all_users && proc_kinfo[i].p_ruid != our_uid)
212 continue;
213
214 if (proc_kinfo[i].p_pid == our_pid || // Skip this process
215 proc_kinfo[i].p_pid == 0 || // Skip kernel (kernel pid is 0)
216 proc_kinfo[i].p_stat == LSZOMB || // Zombies are bad
217 proc_kinfo[i].p_flag & P_TRACED || // Being debugged?
218 proc_kinfo[i].p_flag & P_WEXIT) // Working on exiting
219 continue;
220
221
222 // Every thread is a process in NetBSD, but all the threads of a single
223 // process have the same pid. Do not store the process info in the
224 // result list if a process with given identifier is already registered
225 // there.
226 if (proc_kinfo[i].p_nlwps > 1) {
227 bool already_registered = false;
228 for (size_t pi = 0; pi < process_infos.GetSize(); pi++) {
229 if (process_infos.GetProcessIDAtIndex(pi) ==
230 proc_kinfo[i].p_pid) {
231 already_registered = true;
232 break;
233 }
234 }
235
236 if (already_registered)
237 continue;
238 }
239 ProcessInstanceInfo process_info;
240 process_info.SetProcessID (proc_kinfo[i].p_pid);
241 process_info.SetParentProcessID (proc_kinfo[i].p_ppid);
242 process_info.SetUserID (proc_kinfo[i].p_ruid);
243 process_info.SetGroupID (proc_kinfo[i].p_rgid);
244 process_info.SetEffectiveUserID (proc_kinfo[i].p_uid);
245 process_info.SetEffectiveGroupID (proc_kinfo[i].p_gid);
246 // Make sure our info matches before we go fetch the name and cpu type
247 if (match_info.Matches (process_info) &&
248 GetNetBSDProcessArgs (&match_info, process_info))
249 {
250 GetNetBSDProcessCPUType (process_info);
251 if (match_info.Matches (process_info))
252 process_infos.Append (process_info);
253 }
254 }
255
256 kvm_close(kdp); /* XXX: we don't check for error here */
257
258 return process_infos.GetSize();
259}
260
261bool
262Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
263{
264 process_info.SetProcessID(pid);
265
266 if (GetNetBSDProcessArgs(NULL, process_info))
267 {
268 GetNetBSDProcessCPUType(process_info);
269 GetNetBSDProcessUserAndGroup(process_info);
270 return true;
271 }
272
273 process_info.Clear();
274 return false;
275}
276
277lldb::DataBufferSP
278Host::GetAuxvData(lldb_private::Process *process)
279{
280 return lldb::DataBufferSP();
281}
282
283Error
284Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
285{
286 return Error("unimplemented");
287}