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