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