xref: /openbsd-src/gnu/llvm/lldb/source/Host/openbsd/Host.cpp (revision a0747c9f67a4ae71ccb71e62a28d1ea19e06a63c)
1adae0cfdSpatrick //===-- source/Host/openbsd/Host.cpp --------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include <sys/types.h>
10061da546Spatrick 
11061da546Spatrick #include <sys/signal.h>
12061da546Spatrick #include <sys/exec.h>
13061da546Spatrick #include <sys/proc.h>
14061da546Spatrick #include <sys/ptrace.h>
15061da546Spatrick #include <sys/sysctl.h>
16061da546Spatrick #include <sys/user.h>
17061da546Spatrick 
18*a0747c9fSpatrick #include <cstdio>
19061da546Spatrick 
20061da546Spatrick #include "lldb/Host/Host.h"
21061da546Spatrick #include "lldb/Host/HostInfo.h"
22061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
23061da546Spatrick #include "lldb/Utility/DataExtractor.h"
24061da546Spatrick #include "lldb/Utility/Endian.h"
25061da546Spatrick #include "lldb/Utility/Log.h"
26061da546Spatrick #include "lldb/Utility/NameMatches.h"
27061da546Spatrick #include "lldb/Utility/ProcessInfo.h"
28061da546Spatrick #include "lldb/Utility/Status.h"
29061da546Spatrick #include "lldb/Utility/StreamString.h"
30061da546Spatrick 
31061da546Spatrick #include "llvm/Support/Host.h"
32061da546Spatrick 
33061da546Spatrick extern "C" {
34061da546Spatrick extern char **environ;
35061da546Spatrick }
36061da546Spatrick 
37061da546Spatrick using namespace lldb;
38061da546Spatrick using namespace lldb_private;
39061da546Spatrick 
40061da546Spatrick namespace lldb_private {
41061da546Spatrick class ProcessLaunchInfo;
42061da546Spatrick }
43061da546Spatrick 
GetEnvironment()44972f549bSmortimer Environment Host::GetEnvironment() { return Environment(environ); }
45061da546Spatrick 
46061da546Spatrick static bool
GetOpenBSDProcessArgs(const ProcessInstanceInfoMatch * match_info_ptr,ProcessInstanceInfo & process_info)47061da546Spatrick GetOpenBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
48061da546Spatrick                       ProcessInstanceInfo &process_info) {
49061da546Spatrick   if (!process_info.ProcessIDIsValid())
50061da546Spatrick     return false;
51061da546Spatrick 
52061da546Spatrick   int pid = process_info.GetProcessID();
53061da546Spatrick 
54061da546Spatrick   int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV};
55061da546Spatrick   size_t kern_proc_args_size = 0;
56061da546Spatrick 
57061da546Spatrick   // On OpenBSD, this will just fill ARG_MAX all the time
58061da546Spatrick   if (::sysctl(mib, 4, NULL, &kern_proc_args_size, NULL, 0) == -1)
59061da546Spatrick     return false;
60061da546Spatrick 
61061da546Spatrick   std::string arg_data(kern_proc_args_size, 0);
62061da546Spatrick 
63061da546Spatrick   if (::sysctl(mib, 4, (void *)arg_data.data(), &kern_proc_args_size, NULL, 0) == -1)
64061da546Spatrick     return false;
65061da546Spatrick 
66061da546Spatrick   arg_data.resize(kern_proc_args_size);
67061da546Spatrick 
68061da546Spatrick   // arg_data is a NULL terminated list of pointers, where the pointers
69061da546Spatrick   // point within arg_data to the location of the arg string
70061da546Spatrick   DataExtractor data(arg_data.data(), arg_data.length(), endian::InlHostByteOrder(), sizeof(void *));
71061da546Spatrick 
72061da546Spatrick   lldb::offset_t offset = 0;
73061da546Spatrick   lldb::offset_t arg_offset = 0;
74061da546Spatrick   uint64_t arg_addr = 0;
75061da546Spatrick   const char *cstr;
76061da546Spatrick 
77061da546Spatrick   arg_addr = data.GetAddress(&offset);
78061da546Spatrick   arg_offset = arg_addr - (uint64_t)arg_data.data();
79061da546Spatrick   cstr = data.GetCStr(&arg_offset);
80061da546Spatrick 
81061da546Spatrick   if (!cstr)
82061da546Spatrick     return false;
83061da546Spatrick 
84061da546Spatrick   process_info.GetExecutableFile().SetFile(cstr, FileSpec::Style::native);
85061da546Spatrick 
86061da546Spatrick   if (match_info_ptr != NULL &&
87061da546Spatrick       !NameMatches(process_info.GetExecutableFile().GetFilename().GetCString(),
88061da546Spatrick                   match_info_ptr->GetNameMatchType(),
89061da546Spatrick                   match_info_ptr->GetProcessInfo().GetName()))
90061da546Spatrick   {
91061da546Spatrick     return false;
92061da546Spatrick   }
93061da546Spatrick 
94061da546Spatrick   Args &proc_args = process_info.GetArguments();
95061da546Spatrick 
96061da546Spatrick   while (1) {
97061da546Spatrick     arg_addr = data.GetAddress(&offset);
98061da546Spatrick     if (arg_addr == 0)
99061da546Spatrick       break;
100061da546Spatrick     arg_offset = arg_addr - (uint64_t)arg_data.data();
101061da546Spatrick     cstr = data.GetCStr(&arg_offset);
102061da546Spatrick     proc_args.AppendArgument(cstr);
103061da546Spatrick   }
104061da546Spatrick   return true;
105061da546Spatrick }
106061da546Spatrick 
GetOpenBSDProcessCPUType(ProcessInstanceInfo & process_info)107061da546Spatrick static bool GetOpenBSDProcessCPUType(ProcessInstanceInfo &process_info) {
108061da546Spatrick   if (process_info.ProcessIDIsValid()) {
109061da546Spatrick     process_info.GetArchitecture() =
110061da546Spatrick         HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
111061da546Spatrick     return true;
112061da546Spatrick   }
113061da546Spatrick   process_info.GetArchitecture().Clear();
114061da546Spatrick   return false;
115061da546Spatrick }
116061da546Spatrick 
GetOpenBSDProcessUserAndGroup(ProcessInstanceInfo & process_info)117061da546Spatrick static bool GetOpenBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) {
118061da546Spatrick 
119061da546Spatrick   if (process_info.ProcessIDIsValid()) {
120061da546Spatrick     struct kinfo_proc proc_kinfo = {};
121061da546Spatrick     size_t proc_kinfo_size = sizeof(proc_kinfo);
122061da546Spatrick     int mib[6] = {CTL_KERN, KERN_PROC, KERN_PROC_PID,
123061da546Spatrick                   (int)process_info.GetProcessID(),
124061da546Spatrick                   sizeof(proc_kinfo), 1};
125061da546Spatrick 
126061da546Spatrick     if (::sysctl(mib, 6, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) {
127061da546Spatrick       if (proc_kinfo_size > 0) {
128061da546Spatrick         process_info.SetParentProcessID(proc_kinfo.p_ppid);
129061da546Spatrick         process_info.SetUserID(proc_kinfo.p_ruid);
130061da546Spatrick         process_info.SetGroupID(proc_kinfo.p_rgid);
131061da546Spatrick         process_info.SetEffectiveUserID(proc_kinfo.p_uid);
132061da546Spatrick         process_info.SetEffectiveGroupID(proc_kinfo.p_gid);
133061da546Spatrick         return true;
134061da546Spatrick       }
135061da546Spatrick     }
136061da546Spatrick   }
137061da546Spatrick   process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);
138061da546Spatrick   process_info.SetUserID(UINT32_MAX);
139061da546Spatrick   process_info.SetGroupID(UINT32_MAX);
140061da546Spatrick   process_info.SetEffectiveUserID(UINT32_MAX);
141061da546Spatrick   process_info.SetEffectiveGroupID(UINT32_MAX);
142061da546Spatrick   return false;
143061da546Spatrick }
144061da546Spatrick 
FindProcessesImpl(const ProcessInstanceInfoMatch & match_info,ProcessInstanceInfoList & process_infos)145adae0cfdSpatrick uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
146061da546Spatrick                                  ProcessInstanceInfoList &process_infos) {
147061da546Spatrick   std::vector<struct kinfo_proc> kinfos;
148061da546Spatrick 
149061da546Spatrick   int mib[6] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), 0};
150061da546Spatrick 
151061da546Spatrick   size_t pid_data_size = 0;
152061da546Spatrick   if (::sysctl(mib, 6, NULL, &pid_data_size, NULL, 0) != 0)
153061da546Spatrick     return 0;
154061da546Spatrick 
155061da546Spatrick   // Add a few extra in case a few more show up
156061da546Spatrick   const size_t estimated_pid_count =
157061da546Spatrick       (pid_data_size / sizeof(struct kinfo_proc)) + 10;
158061da546Spatrick 
159061da546Spatrick   kinfos.resize(estimated_pid_count);
160061da546Spatrick   mib[5] = estimated_pid_count;
161061da546Spatrick   pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
162061da546Spatrick 
163061da546Spatrick   if (::sysctl(mib, 6, &kinfos[0], &pid_data_size, NULL, 0) != 0)
164061da546Spatrick     return 0;
165061da546Spatrick 
166061da546Spatrick   const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
167061da546Spatrick 
168061da546Spatrick   bool all_users = match_info.GetMatchAllUsers();
169061da546Spatrick   const ::pid_t our_pid = getpid();
170061da546Spatrick   const uid_t our_uid = getuid();
171061da546Spatrick   for (size_t i = 0; i < actual_pid_count; i++) {
172061da546Spatrick     const struct kinfo_proc &kinfo = kinfos[i];
173061da546Spatrick     const bool kinfo_user_matches = (all_users || (kinfo.p_ruid == our_uid) ||
174061da546Spatrick                                      // Special case, if lldb is being run as
175061da546Spatrick                                      // root we can attach to anything.
176061da546Spatrick                                      (our_uid == 0));
177061da546Spatrick 
178061da546Spatrick     if (kinfo_user_matches == false || // Make sure the user is acceptable
179061da546Spatrick         kinfo.p_pid == our_pid ||     // Skip this process
180061da546Spatrick         kinfo.p_pid == 0 ||           // Skip kernel (kernel pid is zero)
181061da546Spatrick         kinfo.p_stat == SZOMB ||      // Zombies are bad, they like brains...
182061da546Spatrick         kinfo.p_psflags & PS_TRACED || // Being debugged?
183061da546Spatrick         kinfo.p_flag & P_WEXIT)       // Working on exiting
184061da546Spatrick       continue;
185061da546Spatrick 
186061da546Spatrick     ProcessInstanceInfo process_info;
187061da546Spatrick     process_info.SetProcessID(kinfo.p_pid);
188061da546Spatrick     process_info.SetParentProcessID(kinfo.p_ppid);
189061da546Spatrick     process_info.SetUserID(kinfo.p_ruid);
190061da546Spatrick     process_info.SetGroupID(kinfo.p_rgid);
191061da546Spatrick     process_info.SetEffectiveUserID(kinfo.p_svuid);
192061da546Spatrick     process_info.SetEffectiveGroupID(kinfo.p_svgid);
193061da546Spatrick 
194061da546Spatrick     // Make sure our info matches before we go fetch the name and cpu type
195061da546Spatrick     if (match_info.Matches(process_info) &&
196061da546Spatrick         GetOpenBSDProcessArgs(&match_info, process_info)) {
197061da546Spatrick       GetOpenBSDProcessCPUType(process_info);
198061da546Spatrick       if (match_info.Matches(process_info))
199adae0cfdSpatrick         process_infos.push_back(process_info);
200061da546Spatrick     }
201061da546Spatrick   }
202061da546Spatrick 
203adae0cfdSpatrick   return process_infos.size();
204061da546Spatrick }
205061da546Spatrick 
GetProcessInfo(lldb::pid_t pid,ProcessInstanceInfo & process_info)206061da546Spatrick bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
207061da546Spatrick   process_info.SetProcessID(pid);
208061da546Spatrick 
209061da546Spatrick   if (GetOpenBSDProcessArgs(NULL, process_info)) {
210061da546Spatrick     // should use libprocstat instead of going right into sysctl?
211061da546Spatrick     GetOpenBSDProcessCPUType(process_info);
212061da546Spatrick     GetOpenBSDProcessUserAndGroup(process_info);
213061da546Spatrick     return true;
214061da546Spatrick   }
215061da546Spatrick 
216061da546Spatrick   process_info.Clear();
217061da546Spatrick   return false;
218061da546Spatrick }
219061da546Spatrick 
ShellExpandArguments(ProcessLaunchInfo & launch_info)220061da546Spatrick Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
221061da546Spatrick   return Status("unimplemented");
222061da546Spatrick }
223