xref: /openbsd-src/gnu/llvm/lldb/source/Host/openbsd/Host.cpp (revision a0747c9f67a4ae71ccb71e62a28d1ea19e06a63c)
1 //===-- source/Host/openbsd/Host.cpp --------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include <sys/types.h>
10 
11 #include <sys/signal.h>
12 #include <sys/exec.h>
13 #include <sys/proc.h>
14 #include <sys/ptrace.h>
15 #include <sys/sysctl.h>
16 #include <sys/user.h>
17 
18 #include <cstdio>
19 
20 #include "lldb/Host/Host.h"
21 #include "lldb/Host/HostInfo.h"
22 #include "lldb/Utility/DataBufferHeap.h"
23 #include "lldb/Utility/DataExtractor.h"
24 #include "lldb/Utility/Endian.h"
25 #include "lldb/Utility/Log.h"
26 #include "lldb/Utility/NameMatches.h"
27 #include "lldb/Utility/ProcessInfo.h"
28 #include "lldb/Utility/Status.h"
29 #include "lldb/Utility/StreamString.h"
30 
31 #include "llvm/Support/Host.h"
32 
33 extern "C" {
34 extern char **environ;
35 }
36 
37 using namespace lldb;
38 using namespace lldb_private;
39 
40 namespace lldb_private {
41 class ProcessLaunchInfo;
42 }
43 
GetEnvironment()44 Environment Host::GetEnvironment() { return Environment(environ); }
45 
46 static bool
GetOpenBSDProcessArgs(const ProcessInstanceInfoMatch * match_info_ptr,ProcessInstanceInfo & process_info)47 GetOpenBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
48                       ProcessInstanceInfo &process_info) {
49   if (!process_info.ProcessIDIsValid())
50     return false;
51 
52   int pid = process_info.GetProcessID();
53 
54   int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV};
55   size_t kern_proc_args_size = 0;
56 
57   // On OpenBSD, this will just fill ARG_MAX all the time
58   if (::sysctl(mib, 4, NULL, &kern_proc_args_size, NULL, 0) == -1)
59     return false;
60 
61   std::string arg_data(kern_proc_args_size, 0);
62 
63   if (::sysctl(mib, 4, (void *)arg_data.data(), &kern_proc_args_size, NULL, 0) == -1)
64     return false;
65 
66   arg_data.resize(kern_proc_args_size);
67 
68   // arg_data is a NULL terminated list of pointers, where the pointers
69   // point within arg_data to the location of the arg string
70   DataExtractor data(arg_data.data(), arg_data.length(), endian::InlHostByteOrder(), sizeof(void *));
71 
72   lldb::offset_t offset = 0;
73   lldb::offset_t arg_offset = 0;
74   uint64_t arg_addr = 0;
75   const char *cstr;
76 
77   arg_addr = data.GetAddress(&offset);
78   arg_offset = arg_addr - (uint64_t)arg_data.data();
79   cstr = data.GetCStr(&arg_offset);
80 
81   if (!cstr)
82     return false;
83 
84   process_info.GetExecutableFile().SetFile(cstr, FileSpec::Style::native);
85 
86   if (match_info_ptr != NULL &&
87       !NameMatches(process_info.GetExecutableFile().GetFilename().GetCString(),
88                   match_info_ptr->GetNameMatchType(),
89                   match_info_ptr->GetProcessInfo().GetName()))
90   {
91     return false;
92   }
93 
94   Args &proc_args = process_info.GetArguments();
95 
96   while (1) {
97     arg_addr = data.GetAddress(&offset);
98     if (arg_addr == 0)
99       break;
100     arg_offset = arg_addr - (uint64_t)arg_data.data();
101     cstr = data.GetCStr(&arg_offset);
102     proc_args.AppendArgument(cstr);
103   }
104   return true;
105 }
106 
GetOpenBSDProcessCPUType(ProcessInstanceInfo & process_info)107 static bool GetOpenBSDProcessCPUType(ProcessInstanceInfo &process_info) {
108   if (process_info.ProcessIDIsValid()) {
109     process_info.GetArchitecture() =
110         HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
111     return true;
112   }
113   process_info.GetArchitecture().Clear();
114   return false;
115 }
116 
GetOpenBSDProcessUserAndGroup(ProcessInstanceInfo & process_info)117 static bool GetOpenBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) {
118 
119   if (process_info.ProcessIDIsValid()) {
120     struct kinfo_proc proc_kinfo = {};
121     size_t proc_kinfo_size = sizeof(proc_kinfo);
122     int mib[6] = {CTL_KERN, KERN_PROC, KERN_PROC_PID,
123                   (int)process_info.GetProcessID(),
124                   sizeof(proc_kinfo), 1};
125 
126     if (::sysctl(mib, 6, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) {
127       if (proc_kinfo_size > 0) {
128         process_info.SetParentProcessID(proc_kinfo.p_ppid);
129         process_info.SetUserID(proc_kinfo.p_ruid);
130         process_info.SetGroupID(proc_kinfo.p_rgid);
131         process_info.SetEffectiveUserID(proc_kinfo.p_uid);
132         process_info.SetEffectiveGroupID(proc_kinfo.p_gid);
133         return true;
134       }
135     }
136   }
137   process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);
138   process_info.SetUserID(UINT32_MAX);
139   process_info.SetGroupID(UINT32_MAX);
140   process_info.SetEffectiveUserID(UINT32_MAX);
141   process_info.SetEffectiveGroupID(UINT32_MAX);
142   return false;
143 }
144 
FindProcessesImpl(const ProcessInstanceInfoMatch & match_info,ProcessInstanceInfoList & process_infos)145 uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
146                                  ProcessInstanceInfoList &process_infos) {
147   std::vector<struct kinfo_proc> kinfos;
148 
149   int mib[6] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), 0};
150 
151   size_t pid_data_size = 0;
152   if (::sysctl(mib, 6, NULL, &pid_data_size, NULL, 0) != 0)
153     return 0;
154 
155   // Add a few extra in case a few more show up
156   const size_t estimated_pid_count =
157       (pid_data_size / sizeof(struct kinfo_proc)) + 10;
158 
159   kinfos.resize(estimated_pid_count);
160   mib[5] = estimated_pid_count;
161   pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
162 
163   if (::sysctl(mib, 6, &kinfos[0], &pid_data_size, NULL, 0) != 0)
164     return 0;
165 
166   const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
167 
168   bool all_users = match_info.GetMatchAllUsers();
169   const ::pid_t our_pid = getpid();
170   const uid_t our_uid = getuid();
171   for (size_t i = 0; i < actual_pid_count; i++) {
172     const struct kinfo_proc &kinfo = kinfos[i];
173     const bool kinfo_user_matches = (all_users || (kinfo.p_ruid == our_uid) ||
174                                      // Special case, if lldb is being run as
175                                      // root we can attach to anything.
176                                      (our_uid == 0));
177 
178     if (kinfo_user_matches == false || // Make sure the user is acceptable
179         kinfo.p_pid == our_pid ||     // Skip this process
180         kinfo.p_pid == 0 ||           // Skip kernel (kernel pid is zero)
181         kinfo.p_stat == SZOMB ||      // Zombies are bad, they like brains...
182         kinfo.p_psflags & PS_TRACED || // Being debugged?
183         kinfo.p_flag & P_WEXIT)       // Working on exiting
184       continue;
185 
186     ProcessInstanceInfo process_info;
187     process_info.SetProcessID(kinfo.p_pid);
188     process_info.SetParentProcessID(kinfo.p_ppid);
189     process_info.SetUserID(kinfo.p_ruid);
190     process_info.SetGroupID(kinfo.p_rgid);
191     process_info.SetEffectiveUserID(kinfo.p_svuid);
192     process_info.SetEffectiveGroupID(kinfo.p_svgid);
193 
194     // Make sure our info matches before we go fetch the name and cpu type
195     if (match_info.Matches(process_info) &&
196         GetOpenBSDProcessArgs(&match_info, process_info)) {
197       GetOpenBSDProcessCPUType(process_info);
198       if (match_info.Matches(process_info))
199         process_infos.push_back(process_info);
200     }
201   }
202 
203   return process_infos.size();
204 }
205 
GetProcessInfo(lldb::pid_t pid,ProcessInstanceInfo & process_info)206 bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
207   process_info.SetProcessID(pid);
208 
209   if (GetOpenBSDProcessArgs(NULL, process_info)) {
210     // should use libprocstat instead of going right into sysctl?
211     GetOpenBSDProcessCPUType(process_info);
212     GetOpenBSDProcessUserAndGroup(process_info);
213     return true;
214   }
215 
216   process_info.Clear();
217   return false;
218 }
219 
ShellExpandArguments(ProcessLaunchInfo & launch_info)220 Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
221   return Status("unimplemented");
222 }
223