1 //===-- 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 
48 extern "C" {
49     extern char **environ;
50 }
51 
52 using namespace lldb;
53 using namespace lldb_private;
54 
55 size_t
56 Host::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 
70 static bool
71 GetNetBSDProcessArgs (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, 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 
124 static bool
125 GetNetBSDProcessCPUType (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 
136 static bool
137 GetNetBSDProcessUserAndGroup(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 
174 error:
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 
183 uint32_t
184 Host::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 
261 bool
262 Host::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 
277 lldb::DataBufferSP
278 Host::GetAuxvData(lldb_private::Process *process)
279 {
280 	return lldb::DataBufferSP();
281 }
282 
283 Error
284 Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
285 {
286     return Error("unimplemented");
287 }
288