xref: /freebsd-src/contrib/llvm-project/lldb/source/Host/openbsd/Host.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
15ffd83dbSDimitry Andric //===-- source/Host/openbsd/Host.cpp --------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include <sys/types.h>
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include <sys/signal.h>
120b57cec5SDimitry Andric #include <sys/exec.h>
130b57cec5SDimitry Andric #include <sys/proc.h>
140b57cec5SDimitry Andric #include <sys/ptrace.h>
150b57cec5SDimitry Andric #include <sys/sysctl.h>
160b57cec5SDimitry Andric #include <sys/user.h>
170b57cec5SDimitry Andric 
18fe6060f1SDimitry Andric #include <cstdio>
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric #include "lldb/Host/Host.h"
210b57cec5SDimitry Andric #include "lldb/Host/HostInfo.h"
220b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
230b57cec5SDimitry Andric #include "lldb/Utility/DataExtractor.h"
240b57cec5SDimitry Andric #include "lldb/Utility/Endian.h"
250b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
260b57cec5SDimitry Andric #include "lldb/Utility/NameMatches.h"
270b57cec5SDimitry Andric #include "lldb/Utility/ProcessInfo.h"
280b57cec5SDimitry Andric #include "lldb/Utility/Status.h"
290b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h"
300b57cec5SDimitry Andric 
31*06c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h"
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric extern "C" {
340b57cec5SDimitry Andric extern char **environ;
350b57cec5SDimitry Andric }
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric using namespace lldb;
380b57cec5SDimitry Andric using namespace lldb_private;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric namespace lldb_private {
410b57cec5SDimitry Andric class ProcessLaunchInfo;
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
GetEnvironment()440b57cec5SDimitry Andric Environment Host::GetEnvironment() {
450b57cec5SDimitry Andric   Environment env;
460b57cec5SDimitry Andric   char *v;
470b57cec5SDimitry Andric   char **var = environ;
480b57cec5SDimitry Andric   for (; var != NULL && *var != NULL; ++var) {
490b57cec5SDimitry Andric     v = strchr(*var, (int)'-');
500b57cec5SDimitry Andric     if (v == NULL)
510b57cec5SDimitry Andric       continue;
520b57cec5SDimitry Andric     env.insert(v);
530b57cec5SDimitry Andric   }
540b57cec5SDimitry Andric   return env;
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric static bool
GetOpenBSDProcessArgs(const ProcessInstanceInfoMatch * match_info_ptr,ProcessInstanceInfo & process_info)580b57cec5SDimitry Andric GetOpenBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
590b57cec5SDimitry Andric                       ProcessInstanceInfo &process_info) {
600b57cec5SDimitry Andric   if (process_info.ProcessIDIsValid()) {
610b57cec5SDimitry Andric     int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ARGS,
620b57cec5SDimitry Andric                   (int)process_info.GetProcessID()};
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric     char arg_data[8192];
650b57cec5SDimitry Andric     size_t arg_data_size = sizeof(arg_data);
660b57cec5SDimitry Andric     if (::sysctl(mib, 4, arg_data, &arg_data_size, NULL, 0) == 0) {
670b57cec5SDimitry Andric       DataExtractor data(arg_data, arg_data_size, endian::InlHostByteOrder(),
680b57cec5SDimitry Andric                          sizeof(void *));
690b57cec5SDimitry Andric       lldb::offset_t offset = 0;
700b57cec5SDimitry Andric       const char *cstr;
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric       cstr = data.GetCStr(&offset);
730b57cec5SDimitry Andric       if (cstr) {
740b57cec5SDimitry Andric         process_info.GetExecutableFile().SetFile(cstr, FileSpec::Style::native);
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric         if (!(match_info_ptr == NULL ||
770b57cec5SDimitry Andric               NameMatches(
780b57cec5SDimitry Andric                   process_info.GetExecutableFile().GetFilename().GetCString(),
790b57cec5SDimitry Andric                   match_info_ptr->GetNameMatchType(),
800b57cec5SDimitry Andric                   match_info_ptr->GetProcessInfo().GetName())))
810b57cec5SDimitry Andric           return false;
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric         Args &proc_args = process_info.GetArguments();
840b57cec5SDimitry Andric         while (1) {
850b57cec5SDimitry Andric           const uint8_t *p = data.PeekData(offset, 1);
860b57cec5SDimitry Andric           while ((p != NULL) && (*p == '\0') && offset < arg_data_size) {
870b57cec5SDimitry Andric             ++offset;
880b57cec5SDimitry Andric             p = data.PeekData(offset, 1);
890b57cec5SDimitry Andric           }
900b57cec5SDimitry Andric           if (p == NULL || offset >= arg_data_size)
910b57cec5SDimitry Andric             return true;
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric           cstr = data.GetCStr(&offset);
940b57cec5SDimitry Andric           if (cstr)
950b57cec5SDimitry Andric             proc_args.AppendArgument(llvm::StringRef(cstr));
960b57cec5SDimitry Andric           else
970b57cec5SDimitry Andric             return true;
980b57cec5SDimitry Andric         }
990b57cec5SDimitry Andric       }
1000b57cec5SDimitry Andric     }
1010b57cec5SDimitry Andric   }
1020b57cec5SDimitry Andric   return false;
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric 
GetOpenBSDProcessCPUType(ProcessInstanceInfo & process_info)1050b57cec5SDimitry Andric static bool GetOpenBSDProcessCPUType(ProcessInstanceInfo &process_info) {
1060b57cec5SDimitry Andric   if (process_info.ProcessIDIsValid()) {
1070b57cec5SDimitry Andric     process_info.GetArchitecture() =
1080b57cec5SDimitry Andric         HostInfo::GetArchitecture(HostInfo::eArchKindDefault);
1090b57cec5SDimitry Andric     return true;
1100b57cec5SDimitry Andric   }
1110b57cec5SDimitry Andric   process_info.GetArchitecture().Clear();
1120b57cec5SDimitry Andric   return false;
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric 
GetOpenBSDProcessUserAndGroup(ProcessInstanceInfo & process_info)1150b57cec5SDimitry Andric static bool GetOpenBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) {
1160b57cec5SDimitry Andric   struct kinfo_proc proc_kinfo;
1170b57cec5SDimitry Andric   size_t proc_kinfo_size;
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric   if (process_info.ProcessIDIsValid()) {
1200b57cec5SDimitry Andric     int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID,
1210b57cec5SDimitry Andric                   (int)process_info.GetProcessID()};
1220b57cec5SDimitry Andric     proc_kinfo_size = sizeof(struct kinfo_proc);
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric     if (::sysctl(mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) {
1250b57cec5SDimitry Andric       if (proc_kinfo_size > 0) {
1260b57cec5SDimitry Andric         process_info.SetParentProcessID(proc_kinfo.p_ppid);
1270b57cec5SDimitry Andric         process_info.SetUserID(proc_kinfo.p_ruid);
1280b57cec5SDimitry Andric         process_info.SetGroupID(proc_kinfo.p_rgid);
1290b57cec5SDimitry Andric         process_info.SetEffectiveUserID(proc_kinfo.p_uid);
1300b57cec5SDimitry Andric 	process_info.SetEffectiveGroupID(proc_kinfo.p_gid);
1310b57cec5SDimitry Andric         return true;
1320b57cec5SDimitry Andric       }
1330b57cec5SDimitry Andric     }
1340b57cec5SDimitry Andric   }
1350b57cec5SDimitry Andric   process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);
1360b57cec5SDimitry Andric   process_info.SetUserID(UINT32_MAX);
1370b57cec5SDimitry Andric   process_info.SetGroupID(UINT32_MAX);
1380b57cec5SDimitry Andric   process_info.SetEffectiveUserID(UINT32_MAX);
1390b57cec5SDimitry Andric   process_info.SetEffectiveGroupID(UINT32_MAX);
1400b57cec5SDimitry Andric   return false;
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric 
FindProcessesImpl(const ProcessInstanceInfoMatch & match_info,ProcessInstanceInfoList & process_infos)1435ffd83dbSDimitry Andric uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
1440b57cec5SDimitry Andric                                  ProcessInstanceInfoList &process_infos) {
1450b57cec5SDimitry Andric   std::vector<struct kinfo_proc> kinfos;
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric   size_t pid_data_size = 0;
1500b57cec5SDimitry Andric   if (::sysctl(mib, 3, NULL, &pid_data_size, NULL, 0) != 0)
1510b57cec5SDimitry Andric     return 0;
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   // Add a few extra in case a few more show up
1540b57cec5SDimitry Andric   const size_t estimated_pid_count =
1550b57cec5SDimitry Andric       (pid_data_size / sizeof(struct kinfo_proc)) + 10;
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric   kinfos.resize(estimated_pid_count);
1580b57cec5SDimitry Andric   pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   if (::sysctl(mib, 3, &kinfos[0], &pid_data_size, NULL, 0) != 0)
1610b57cec5SDimitry Andric     return 0;
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric   const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric   bool all_users = match_info.GetMatchAllUsers();
1660b57cec5SDimitry Andric   const ::pid_t our_pid = getpid();
1670b57cec5SDimitry Andric   const uid_t our_uid = getuid();
1680b57cec5SDimitry Andric   for (size_t i = 0; i < actual_pid_count; i++) {
1690b57cec5SDimitry Andric     const struct kinfo_proc &kinfo = kinfos[i];
1700b57cec5SDimitry Andric     const bool kinfo_user_matches = (all_users || (kinfo.p_ruid == our_uid) ||
1710b57cec5SDimitry Andric                                      // Special case, if lldb is being run as
1720b57cec5SDimitry Andric                                      // root we can attach to anything.
1730b57cec5SDimitry Andric                                      (our_uid == 0));
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric     if (kinfo_user_matches == false || // Make sure the user is acceptable
1760b57cec5SDimitry Andric         kinfo.p_pid == our_pid ||     // Skip this process
1770b57cec5SDimitry Andric         kinfo.p_pid == 0 ||           // Skip kernel (kernel pid is zero)
1780b57cec5SDimitry Andric         kinfo.p_stat == SZOMB ||      // Zombies are bad, they like brains...
1790b57cec5SDimitry Andric         kinfo.p_psflags & PS_TRACED || // Being debugged?
1800b57cec5SDimitry Andric         kinfo.p_flag & P_WEXIT)       // Working on exiting
1810b57cec5SDimitry Andric       continue;
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric     ProcessInstanceInfo process_info;
1840b57cec5SDimitry Andric     process_info.SetProcessID(kinfo.p_pid);
1850b57cec5SDimitry Andric     process_info.SetParentProcessID(kinfo.p_ppid);
1860b57cec5SDimitry Andric     process_info.SetUserID(kinfo.p_ruid);
1870b57cec5SDimitry Andric     process_info.SetGroupID(kinfo.p_rgid);
1880b57cec5SDimitry Andric     process_info.SetEffectiveUserID(kinfo.p_svuid);
1890b57cec5SDimitry Andric     process_info.SetEffectiveGroupID(kinfo.p_svgid);
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric     // Make sure our info matches before we go fetch the name and cpu type
1920b57cec5SDimitry Andric     if (match_info.Matches(process_info) &&
1930b57cec5SDimitry Andric         GetOpenBSDProcessArgs(&match_info, process_info)) {
1940b57cec5SDimitry Andric       GetOpenBSDProcessCPUType(process_info);
1950b57cec5SDimitry Andric       if (match_info.Matches(process_info))
1965ffd83dbSDimitry Andric         process_infos.push_back(process_info);
1970b57cec5SDimitry Andric     }
1980b57cec5SDimitry Andric   }
1990b57cec5SDimitry Andric 
2005ffd83dbSDimitry Andric   return process_infos.size();
2010b57cec5SDimitry Andric }
2020b57cec5SDimitry Andric 
GetProcessInfo(lldb::pid_t pid,ProcessInstanceInfo & process_info)2030b57cec5SDimitry Andric bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
2040b57cec5SDimitry Andric   process_info.SetProcessID(pid);
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric   if (GetOpenBSDProcessArgs(NULL, process_info)) {
2070b57cec5SDimitry Andric     // should use libprocstat instead of going right into sysctl?
2080b57cec5SDimitry Andric     GetOpenBSDProcessCPUType(process_info);
2090b57cec5SDimitry Andric     GetOpenBSDProcessUserAndGroup(process_info);
2100b57cec5SDimitry Andric     return true;
2110b57cec5SDimitry Andric   }
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric   process_info.Clear();
2140b57cec5SDimitry Andric   return false;
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric 
ShellExpandArguments(ProcessLaunchInfo & launch_info)2170b57cec5SDimitry Andric Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
2180b57cec5SDimitry Andric   return Status("unimplemented");
2190b57cec5SDimitry Andric }
220