xref: /openbsd-src/gnu/llvm/lldb/source/Host/openbsd/Host.cpp (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1 //===-- source/Host/openbsd/Host.cpp ----------------------------*- C++ -*-===//
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 <stdio.h>
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 
44 Environment Host::GetEnvironment() {
45   Environment env;
46   char *v;
47   char **var = environ;
48   for (; var != NULL && *var != NULL; ++var) {
49     v = strchr(*var, (int)'-');
50     if (v == NULL)
51       continue;
52     env.insert(v);
53   }
54   return env;
55 }
56 
57 static bool
58 GetOpenBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
59                       ProcessInstanceInfo &process_info) {
60   if (!process_info.ProcessIDIsValid())
61     return false;
62 
63   int pid = process_info.GetProcessID();
64 
65   int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV};
66   size_t kern_proc_args_size = 0;
67 
68   // On OpenBSD, this will just fill ARG_MAX all the time
69   if (::sysctl(mib, 4, NULL, &kern_proc_args_size, NULL, 0) == -1)
70     return false;
71 
72   std::string arg_data(kern_proc_args_size, 0);
73 
74   if (::sysctl(mib, 4, (void *)arg_data.data(), &kern_proc_args_size, NULL, 0) == -1)
75     return false;
76 
77   arg_data.resize(kern_proc_args_size);
78 
79   // arg_data is a NULL terminated list of pointers, where the pointers
80   // point within arg_data to the location of the arg string
81   DataExtractor data(arg_data.data(), arg_data.length(), endian::InlHostByteOrder(), sizeof(void *));
82 
83   lldb::offset_t offset = 0;
84   lldb::offset_t arg_offset = 0;
85   uint64_t arg_addr = 0;
86   const char *cstr;
87 
88   arg_addr = data.GetAddress(&offset);
89   arg_offset = arg_addr - (uint64_t)arg_data.data();
90   cstr = data.GetCStr(&arg_offset);
91 
92   if (!cstr)
93     return false;
94 
95   process_info.GetExecutableFile().SetFile(cstr, FileSpec::Style::native);
96 
97   if (match_info_ptr != NULL &&
98       !NameMatches(process_info.GetExecutableFile().GetFilename().GetCString(),
99                   match_info_ptr->GetNameMatchType(),
100                   match_info_ptr->GetProcessInfo().GetName()))
101   {
102     return false;
103   }
104 
105   Args &proc_args = process_info.GetArguments();
106 
107   while (1) {
108     arg_addr = data.GetAddress(&offset);
109     if (arg_addr == 0)
110       break;
111     arg_offset = arg_addr - (uint64_t)arg_data.data();
112     cstr = data.GetCStr(&arg_offset);
113     proc_args.AppendArgument(cstr);
114   }
115   return true;
116 }
117 
118 static bool GetOpenBSDProcessCPUType(ProcessInstanceInfo &process_info) {
119   if (process_info.ProcessIDIsValid()) {
120     process_info.GetArchitecture() =
121         HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
122     return true;
123   }
124   process_info.GetArchitecture().Clear();
125   return false;
126 }
127 
128 static bool GetOpenBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) {
129 
130   if (process_info.ProcessIDIsValid()) {
131     struct kinfo_proc proc_kinfo = {};
132     size_t proc_kinfo_size = sizeof(proc_kinfo);
133     int mib[6] = {CTL_KERN, KERN_PROC, KERN_PROC_PID,
134                   (int)process_info.GetProcessID(),
135                   sizeof(proc_kinfo), 1};
136 
137     if (::sysctl(mib, 6, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) {
138       if (proc_kinfo_size > 0) {
139         process_info.SetParentProcessID(proc_kinfo.p_ppid);
140         process_info.SetUserID(proc_kinfo.p_ruid);
141         process_info.SetGroupID(proc_kinfo.p_rgid);
142         process_info.SetEffectiveUserID(proc_kinfo.p_uid);
143         process_info.SetEffectiveGroupID(proc_kinfo.p_gid);
144         return true;
145       }
146     }
147   }
148   process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);
149   process_info.SetUserID(UINT32_MAX);
150   process_info.SetGroupID(UINT32_MAX);
151   process_info.SetEffectiveUserID(UINT32_MAX);
152   process_info.SetEffectiveGroupID(UINT32_MAX);
153   return false;
154 }
155 
156 uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info,
157                              ProcessInstanceInfoList &process_infos) {
158   std::vector<struct kinfo_proc> kinfos;
159 
160   int mib[6] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), 0};
161 
162   size_t pid_data_size = 0;
163   if (::sysctl(mib, 6, NULL, &pid_data_size, NULL, 0) != 0)
164     return 0;
165 
166   // Add a few extra in case a few more show up
167   const size_t estimated_pid_count =
168       (pid_data_size / sizeof(struct kinfo_proc)) + 10;
169 
170   kinfos.resize(estimated_pid_count);
171   mib[5] = estimated_pid_count;
172   pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
173 
174   if (::sysctl(mib, 6, &kinfos[0], &pid_data_size, NULL, 0) != 0)
175     return 0;
176 
177   const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
178 
179   bool all_users = match_info.GetMatchAllUsers();
180   const ::pid_t our_pid = getpid();
181   const uid_t our_uid = getuid();
182   for (size_t i = 0; i < actual_pid_count; i++) {
183     const struct kinfo_proc &kinfo = kinfos[i];
184     const bool kinfo_user_matches = (all_users || (kinfo.p_ruid == our_uid) ||
185                                      // Special case, if lldb is being run as
186                                      // root we can attach to anything.
187                                      (our_uid == 0));
188 
189     if (kinfo_user_matches == false || // Make sure the user is acceptable
190         kinfo.p_pid == our_pid ||     // Skip this process
191         kinfo.p_pid == 0 ||           // Skip kernel (kernel pid is zero)
192         kinfo.p_stat == SZOMB ||      // Zombies are bad, they like brains...
193         kinfo.p_psflags & PS_TRACED || // Being debugged?
194         kinfo.p_flag & P_WEXIT)       // Working on exiting
195       continue;
196 
197     ProcessInstanceInfo process_info;
198     process_info.SetProcessID(kinfo.p_pid);
199     process_info.SetParentProcessID(kinfo.p_ppid);
200     process_info.SetUserID(kinfo.p_ruid);
201     process_info.SetGroupID(kinfo.p_rgid);
202     process_info.SetEffectiveUserID(kinfo.p_svuid);
203     process_info.SetEffectiveGroupID(kinfo.p_svgid);
204 
205     // Make sure our info matches before we go fetch the name and cpu type
206     if (match_info.Matches(process_info) &&
207         GetOpenBSDProcessArgs(&match_info, process_info)) {
208       GetOpenBSDProcessCPUType(process_info);
209       if (match_info.Matches(process_info))
210         process_infos.Append(process_info);
211     }
212   }
213 
214   return process_infos.GetSize();
215 }
216 
217 bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
218   process_info.SetProcessID(pid);
219 
220   if (GetOpenBSDProcessArgs(NULL, process_info)) {
221     // should use libprocstat instead of going right into sysctl?
222     GetOpenBSDProcessCPUType(process_info);
223     GetOpenBSDProcessUserAndGroup(process_info);
224     return true;
225   }
226 
227   process_info.Clear();
228   return false;
229 }
230 
231 Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
232   return Status("unimplemented");
233 }
234