xref: /freebsd-src/contrib/llvm-project/lldb/source/Host/netbsd/HostNetBSD.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1*5ffd83dbSDimitry Andric //===-- source/Host/netbsd/HostNetBSD.cpp ---------------------------------===//
2*5ffd83dbSDimitry Andric //
3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5ffd83dbSDimitry Andric //
7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
8*5ffd83dbSDimitry Andric 
9*5ffd83dbSDimitry Andric #include <dlfcn.h>
10*5ffd83dbSDimitry Andric #include <execinfo.h>
11*5ffd83dbSDimitry Andric #include <stdio.h>
12*5ffd83dbSDimitry Andric #include <sys/proc.h>
13*5ffd83dbSDimitry Andric #include <sys/sysctl.h>
14*5ffd83dbSDimitry Andric #include <sys/types.h>
15*5ffd83dbSDimitry Andric 
16*5ffd83dbSDimitry Andric #include <limits.h>
17*5ffd83dbSDimitry Andric 
18*5ffd83dbSDimitry Andric #include <kvm.h>
19*5ffd83dbSDimitry Andric #include <sys/exec.h>
20*5ffd83dbSDimitry Andric #include <sys/ptrace.h>
21*5ffd83dbSDimitry Andric 
22*5ffd83dbSDimitry Andric #include "lldb/Host/FileSystem.h"
23*5ffd83dbSDimitry Andric #include "lldb/Host/Host.h"
24*5ffd83dbSDimitry Andric #include "lldb/Host/HostInfo.h"
25*5ffd83dbSDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
26*5ffd83dbSDimitry Andric #include "lldb/Utility/DataExtractor.h"
27*5ffd83dbSDimitry Andric #include "lldb/Utility/Endian.h"
28*5ffd83dbSDimitry Andric #include "lldb/Utility/Log.h"
29*5ffd83dbSDimitry Andric #include "lldb/Utility/NameMatches.h"
30*5ffd83dbSDimitry Andric #include "lldb/Utility/ProcessInfo.h"
31*5ffd83dbSDimitry Andric #include "lldb/Utility/Status.h"
32*5ffd83dbSDimitry Andric #include "lldb/Utility/StreamString.h"
33*5ffd83dbSDimitry Andric 
34*5ffd83dbSDimitry Andric #include "llvm/Object/ELF.h"
35*5ffd83dbSDimitry Andric #include "llvm/Support/Host.h"
36*5ffd83dbSDimitry Andric 
37*5ffd83dbSDimitry Andric extern "C" {
38*5ffd83dbSDimitry Andric extern char **environ;
39*5ffd83dbSDimitry Andric }
40*5ffd83dbSDimitry Andric 
41*5ffd83dbSDimitry Andric using namespace lldb;
42*5ffd83dbSDimitry Andric using namespace lldb_private;
43*5ffd83dbSDimitry Andric 
44*5ffd83dbSDimitry Andric namespace lldb_private {
45*5ffd83dbSDimitry Andric class ProcessLaunchInfo;
46*5ffd83dbSDimitry Andric }
47*5ffd83dbSDimitry Andric 
48*5ffd83dbSDimitry Andric Environment Host::GetEnvironment() { return Environment(environ); }
49*5ffd83dbSDimitry Andric 
50*5ffd83dbSDimitry Andric static bool GetNetBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
51*5ffd83dbSDimitry Andric                                  ProcessInstanceInfo &process_info) {
52*5ffd83dbSDimitry Andric   if (!process_info.ProcessIDIsValid())
53*5ffd83dbSDimitry Andric     return false;
54*5ffd83dbSDimitry Andric 
55*5ffd83dbSDimitry Andric   int pid = process_info.GetProcessID();
56*5ffd83dbSDimitry Andric 
57*5ffd83dbSDimitry Andric   int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV};
58*5ffd83dbSDimitry Andric 
59*5ffd83dbSDimitry Andric   char arg_data[8192];
60*5ffd83dbSDimitry Andric   size_t arg_data_size = sizeof(arg_data);
61*5ffd83dbSDimitry Andric   if (::sysctl(mib, 4, arg_data, &arg_data_size, NULL, 0) != 0)
62*5ffd83dbSDimitry Andric     return false;
63*5ffd83dbSDimitry Andric 
64*5ffd83dbSDimitry Andric   DataExtractor data(arg_data, arg_data_size, endian::InlHostByteOrder(),
65*5ffd83dbSDimitry Andric                      sizeof(void *));
66*5ffd83dbSDimitry Andric   lldb::offset_t offset = 0;
67*5ffd83dbSDimitry Andric   const char *cstr;
68*5ffd83dbSDimitry Andric 
69*5ffd83dbSDimitry Andric   cstr = data.GetCStr(&offset);
70*5ffd83dbSDimitry Andric   if (!cstr)
71*5ffd83dbSDimitry Andric     return false;
72*5ffd83dbSDimitry Andric 
73*5ffd83dbSDimitry Andric   process_info.GetExecutableFile().SetFile(cstr,
74*5ffd83dbSDimitry Andric                                            FileSpec::Style::native);
75*5ffd83dbSDimitry Andric 
76*5ffd83dbSDimitry Andric   if (!(match_info_ptr == NULL ||
77*5ffd83dbSDimitry Andric         NameMatches(process_info.GetExecutableFile().GetFilename().GetCString(),
78*5ffd83dbSDimitry Andric                     match_info_ptr->GetNameMatchType(),
79*5ffd83dbSDimitry Andric                     match_info_ptr->GetProcessInfo().GetName())))
80*5ffd83dbSDimitry Andric     return false;
81*5ffd83dbSDimitry Andric 
82*5ffd83dbSDimitry Andric   process_info.SetArg0(cstr);
83*5ffd83dbSDimitry Andric   Args &proc_args = process_info.GetArguments();
84*5ffd83dbSDimitry Andric   while (1) {
85*5ffd83dbSDimitry Andric     const uint8_t *p = data.PeekData(offset, 1);
86*5ffd83dbSDimitry Andric     while ((p != NULL) && (*p == '\0') && offset < arg_data_size) {
87*5ffd83dbSDimitry Andric       ++offset;
88*5ffd83dbSDimitry Andric       p = data.PeekData(offset, 1);
89*5ffd83dbSDimitry Andric     }
90*5ffd83dbSDimitry Andric     if (p == NULL || offset >= arg_data_size)
91*5ffd83dbSDimitry Andric       break;
92*5ffd83dbSDimitry Andric 
93*5ffd83dbSDimitry Andric     cstr = data.GetCStr(&offset);
94*5ffd83dbSDimitry Andric     if (!cstr)
95*5ffd83dbSDimitry Andric       break;
96*5ffd83dbSDimitry Andric 
97*5ffd83dbSDimitry Andric     proc_args.AppendArgument(llvm::StringRef(cstr));
98*5ffd83dbSDimitry Andric   }
99*5ffd83dbSDimitry Andric 
100*5ffd83dbSDimitry Andric   return true;
101*5ffd83dbSDimitry Andric }
102*5ffd83dbSDimitry Andric 
103*5ffd83dbSDimitry Andric static bool GetNetBSDProcessCPUType(ProcessInstanceInfo &process_info) {
104*5ffd83dbSDimitry Andric   Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
105*5ffd83dbSDimitry Andric 
106*5ffd83dbSDimitry Andric   if (process_info.ProcessIDIsValid()) {
107*5ffd83dbSDimitry Andric     auto buffer_sp = FileSystem::Instance().CreateDataBuffer(
108*5ffd83dbSDimitry Andric         process_info.GetExecutableFile(), 0x20, 0);
109*5ffd83dbSDimitry Andric     if (buffer_sp) {
110*5ffd83dbSDimitry Andric       uint8_t exe_class =
111*5ffd83dbSDimitry Andric           llvm::object::getElfArchType(
112*5ffd83dbSDimitry Andric               {buffer_sp->GetChars(), size_t(buffer_sp->GetByteSize())})
113*5ffd83dbSDimitry Andric               .first;
114*5ffd83dbSDimitry Andric 
115*5ffd83dbSDimitry Andric       switch (exe_class) {
116*5ffd83dbSDimitry Andric       case llvm::ELF::ELFCLASS32:
117*5ffd83dbSDimitry Andric         process_info.GetArchitecture() =
118*5ffd83dbSDimitry Andric             HostInfo::GetArchitecture(HostInfo::eArchKind32);
119*5ffd83dbSDimitry Andric         return true;
120*5ffd83dbSDimitry Andric       case llvm::ELF::ELFCLASS64:
121*5ffd83dbSDimitry Andric         process_info.GetArchitecture() =
122*5ffd83dbSDimitry Andric             HostInfo::GetArchitecture(HostInfo::eArchKind64);
123*5ffd83dbSDimitry Andric         return true;
124*5ffd83dbSDimitry Andric       default:
125*5ffd83dbSDimitry Andric         LLDB_LOG(log, "Unknown elf class ({0}) in file {1}", exe_class,
126*5ffd83dbSDimitry Andric                  process_info.GetExecutableFile());
127*5ffd83dbSDimitry Andric       }
128*5ffd83dbSDimitry Andric     }
129*5ffd83dbSDimitry Andric   }
130*5ffd83dbSDimitry Andric   process_info.GetArchitecture().Clear();
131*5ffd83dbSDimitry Andric   return false;
132*5ffd83dbSDimitry Andric }
133*5ffd83dbSDimitry Andric 
134*5ffd83dbSDimitry Andric static bool GetNetBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) {
135*5ffd83dbSDimitry Andric   ::kvm_t *kdp;
136*5ffd83dbSDimitry Andric   char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */
137*5ffd83dbSDimitry Andric 
138*5ffd83dbSDimitry Andric   struct ::kinfo_proc2 *proc_kinfo;
139*5ffd83dbSDimitry Andric   const int pid = process_info.GetProcessID();
140*5ffd83dbSDimitry Andric   int nproc;
141*5ffd83dbSDimitry Andric 
142*5ffd83dbSDimitry Andric   if (!process_info.ProcessIDIsValid())
143*5ffd83dbSDimitry Andric     goto error;
144*5ffd83dbSDimitry Andric 
145*5ffd83dbSDimitry Andric   if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)
146*5ffd83dbSDimitry Andric     goto error;
147*5ffd83dbSDimitry Andric 
148*5ffd83dbSDimitry Andric   if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_PID, pid,
149*5ffd83dbSDimitry Andric                                    sizeof(struct ::kinfo_proc2), &nproc)) ==
150*5ffd83dbSDimitry Andric       NULL) {
151*5ffd83dbSDimitry Andric     ::kvm_close(kdp);
152*5ffd83dbSDimitry Andric     goto error;
153*5ffd83dbSDimitry Andric   }
154*5ffd83dbSDimitry Andric 
155*5ffd83dbSDimitry Andric   if (nproc < 1) {
156*5ffd83dbSDimitry Andric     ::kvm_close(kdp); /* XXX: we don't check for error here */
157*5ffd83dbSDimitry Andric     goto error;
158*5ffd83dbSDimitry Andric   }
159*5ffd83dbSDimitry Andric 
160*5ffd83dbSDimitry Andric   process_info.SetParentProcessID(proc_kinfo->p_ppid);
161*5ffd83dbSDimitry Andric   process_info.SetUserID(proc_kinfo->p_ruid);
162*5ffd83dbSDimitry Andric   process_info.SetGroupID(proc_kinfo->p_rgid);
163*5ffd83dbSDimitry Andric   process_info.SetEffectiveUserID(proc_kinfo->p_uid);
164*5ffd83dbSDimitry Andric   process_info.SetEffectiveGroupID(proc_kinfo->p_gid);
165*5ffd83dbSDimitry Andric 
166*5ffd83dbSDimitry Andric   ::kvm_close(kdp); /* XXX: we don't check for error here */
167*5ffd83dbSDimitry Andric 
168*5ffd83dbSDimitry Andric   return true;
169*5ffd83dbSDimitry Andric 
170*5ffd83dbSDimitry Andric error:
171*5ffd83dbSDimitry Andric   process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);
172*5ffd83dbSDimitry Andric   process_info.SetUserID(UINT32_MAX);
173*5ffd83dbSDimitry Andric   process_info.SetGroupID(UINT32_MAX);
174*5ffd83dbSDimitry Andric   process_info.SetEffectiveUserID(UINT32_MAX);
175*5ffd83dbSDimitry Andric   process_info.SetEffectiveGroupID(UINT32_MAX);
176*5ffd83dbSDimitry Andric   return false;
177*5ffd83dbSDimitry Andric }
178*5ffd83dbSDimitry Andric 
179*5ffd83dbSDimitry Andric uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
180*5ffd83dbSDimitry Andric                                  ProcessInstanceInfoList &process_infos) {
181*5ffd83dbSDimitry Andric   const ::pid_t our_pid = ::getpid();
182*5ffd83dbSDimitry Andric   const ::uid_t our_uid = ::getuid();
183*5ffd83dbSDimitry Andric 
184*5ffd83dbSDimitry Andric   const bool all_users =
185*5ffd83dbSDimitry Andric       match_info.GetMatchAllUsers() ||
186*5ffd83dbSDimitry Andric       // Special case, if lldb is being run as root we can attach to anything
187*5ffd83dbSDimitry Andric       (our_uid == 0);
188*5ffd83dbSDimitry Andric 
189*5ffd83dbSDimitry Andric   kvm_t *kdp;
190*5ffd83dbSDimitry Andric   char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */
191*5ffd83dbSDimitry Andric   if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)
192*5ffd83dbSDimitry Andric     return 0;
193*5ffd83dbSDimitry Andric 
194*5ffd83dbSDimitry Andric   struct ::kinfo_proc2 *proc_kinfo;
195*5ffd83dbSDimitry Andric   int nproc;
196*5ffd83dbSDimitry Andric   if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_ALL, 0,
197*5ffd83dbSDimitry Andric                                    sizeof(struct ::kinfo_proc2), &nproc)) ==
198*5ffd83dbSDimitry Andric       NULL) {
199*5ffd83dbSDimitry Andric     ::kvm_close(kdp);
200*5ffd83dbSDimitry Andric     return 0;
201*5ffd83dbSDimitry Andric   }
202*5ffd83dbSDimitry Andric 
203*5ffd83dbSDimitry Andric   for (int i = 0; i < nproc; i++) {
204*5ffd83dbSDimitry Andric     if (proc_kinfo[i].p_pid < 1)
205*5ffd83dbSDimitry Andric       continue; /* not valid */
206*5ffd83dbSDimitry Andric     /* Make sure the user is acceptable */
207*5ffd83dbSDimitry Andric     if (!all_users && proc_kinfo[i].p_ruid != our_uid)
208*5ffd83dbSDimitry Andric       continue;
209*5ffd83dbSDimitry Andric 
210*5ffd83dbSDimitry Andric     if (proc_kinfo[i].p_pid == our_pid ||  // Skip this process
211*5ffd83dbSDimitry Andric         proc_kinfo[i].p_pid == 0 ||        // Skip kernel (kernel pid is 0)
212*5ffd83dbSDimitry Andric         proc_kinfo[i].p_stat == LSZOMB ||  // Zombies are bad
213*5ffd83dbSDimitry Andric         proc_kinfo[i].p_flag & P_TRACED || // Being debugged?
214*5ffd83dbSDimitry Andric         proc_kinfo[i].p_flag & P_WEXIT)    // Working on exiting
215*5ffd83dbSDimitry Andric       continue;
216*5ffd83dbSDimitry Andric 
217*5ffd83dbSDimitry Andric     // Every thread is a process in NetBSD, but all the threads of a single
218*5ffd83dbSDimitry Andric     // process have the same pid. Do not store the process info in the result
219*5ffd83dbSDimitry Andric     // list if a process with given identifier is already registered there.
220*5ffd83dbSDimitry Andric     if (proc_kinfo[i].p_nlwps > 1) {
221*5ffd83dbSDimitry Andric       bool already_registered = false;
222*5ffd83dbSDimitry Andric       for (size_t pi = 0; pi < process_infos.size(); pi++) {
223*5ffd83dbSDimitry Andric         if (process_infos[pi].GetProcessID() == proc_kinfo[i].p_pid) {
224*5ffd83dbSDimitry Andric           already_registered = true;
225*5ffd83dbSDimitry Andric           break;
226*5ffd83dbSDimitry Andric         }
227*5ffd83dbSDimitry Andric       }
228*5ffd83dbSDimitry Andric 
229*5ffd83dbSDimitry Andric       if (already_registered)
230*5ffd83dbSDimitry Andric         continue;
231*5ffd83dbSDimitry Andric     }
232*5ffd83dbSDimitry Andric     ProcessInstanceInfo process_info;
233*5ffd83dbSDimitry Andric     process_info.SetProcessID(proc_kinfo[i].p_pid);
234*5ffd83dbSDimitry Andric     process_info.SetParentProcessID(proc_kinfo[i].p_ppid);
235*5ffd83dbSDimitry Andric     process_info.SetUserID(proc_kinfo[i].p_ruid);
236*5ffd83dbSDimitry Andric     process_info.SetGroupID(proc_kinfo[i].p_rgid);
237*5ffd83dbSDimitry Andric     process_info.SetEffectiveUserID(proc_kinfo[i].p_uid);
238*5ffd83dbSDimitry Andric     process_info.SetEffectiveGroupID(proc_kinfo[i].p_gid);
239*5ffd83dbSDimitry Andric     // Make sure our info matches before we go fetch the name and cpu type
240*5ffd83dbSDimitry Andric     if (match_info.Matches(process_info) &&
241*5ffd83dbSDimitry Andric         GetNetBSDProcessArgs(&match_info, process_info)) {
242*5ffd83dbSDimitry Andric       GetNetBSDProcessCPUType(process_info);
243*5ffd83dbSDimitry Andric       if (match_info.Matches(process_info))
244*5ffd83dbSDimitry Andric         process_infos.push_back(process_info);
245*5ffd83dbSDimitry Andric     }
246*5ffd83dbSDimitry Andric   }
247*5ffd83dbSDimitry Andric 
248*5ffd83dbSDimitry Andric   kvm_close(kdp); /* XXX: we don't check for error here */
249*5ffd83dbSDimitry Andric 
250*5ffd83dbSDimitry Andric   return process_infos.size();
251*5ffd83dbSDimitry Andric }
252*5ffd83dbSDimitry Andric 
253*5ffd83dbSDimitry Andric bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
254*5ffd83dbSDimitry Andric   process_info.SetProcessID(pid);
255*5ffd83dbSDimitry Andric 
256*5ffd83dbSDimitry Andric   if (GetNetBSDProcessArgs(NULL, process_info)) {
257*5ffd83dbSDimitry Andric     GetNetBSDProcessCPUType(process_info);
258*5ffd83dbSDimitry Andric     GetNetBSDProcessUserAndGroup(process_info);
259*5ffd83dbSDimitry Andric     return true;
260*5ffd83dbSDimitry Andric   }
261*5ffd83dbSDimitry Andric 
262*5ffd83dbSDimitry Andric   process_info.Clear();
263*5ffd83dbSDimitry Andric   return false;
264*5ffd83dbSDimitry Andric }
265*5ffd83dbSDimitry Andric 
266*5ffd83dbSDimitry Andric Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
267*5ffd83dbSDimitry Andric   return Status("unimplemented");
268*5ffd83dbSDimitry Andric }
269