Path: blob/main/contrib/llvm-project/lldb/source/Host/netbsd/HostNetBSD.cpp
39607 views
//===-- source/Host/netbsd/HostNetBSD.cpp ---------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include <cstdio>9#include <dlfcn.h>10#include <execinfo.h>11#include <sys/proc.h>12#include <sys/sysctl.h>13#include <sys/types.h>1415#include <climits>1617#include <kvm.h>18#include <sys/exec.h>19#include <sys/ptrace.h>2021#include "lldb/Host/FileSystem.h"22#include "lldb/Host/Host.h"23#include "lldb/Host/HostInfo.h"24#include "lldb/Utility/DataBufferHeap.h"25#include "lldb/Utility/DataExtractor.h"26#include "lldb/Utility/Endian.h"27#include "lldb/Utility/LLDBLog.h"28#include "lldb/Utility/Log.h"29#include "lldb/Utility/NameMatches.h"30#include "lldb/Utility/ProcessInfo.h"31#include "lldb/Utility/Status.h"32#include "lldb/Utility/StreamString.h"3334#include "llvm/Object/ELF.h"35#include "llvm/TargetParser/Host.h"3637extern "C" {38extern char **environ;39}4041using namespace lldb;42using namespace lldb_private;4344namespace lldb_private {45class ProcessLaunchInfo;46}4748Environment Host::GetEnvironment() { return Environment(environ); }4950static bool GetNetBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,51ProcessInstanceInfo &process_info) {52if (!process_info.ProcessIDIsValid())53return false;5455int pid = process_info.GetProcessID();5657int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV};5859char arg_data[8192];60size_t arg_data_size = sizeof(arg_data);61if (::sysctl(mib, 4, arg_data, &arg_data_size, NULL, 0) != 0)62return false;6364DataExtractor data(arg_data, arg_data_size, endian::InlHostByteOrder(),65sizeof(void *));66lldb::offset_t offset = 0;67const char *cstr;6869cstr = data.GetCStr(&offset);70if (!cstr)71return false;7273process_info.GetExecutableFile().SetFile(cstr,74FileSpec::Style::native);7576if (!(match_info_ptr == NULL ||77NameMatches(process_info.GetExecutableFile().GetFilename().GetCString(),78match_info_ptr->GetNameMatchType(),79match_info_ptr->GetProcessInfo().GetName())))80return false;8182process_info.SetArg0(cstr);83Args &proc_args = process_info.GetArguments();84while (1) {85const uint8_t *p = data.PeekData(offset, 1);86while ((p != NULL) && (*p == '\0') && offset < arg_data_size) {87++offset;88p = data.PeekData(offset, 1);89}90if (p == NULL || offset >= arg_data_size)91break;9293cstr = data.GetCStr(&offset);94if (!cstr)95break;9697proc_args.AppendArgument(llvm::StringRef(cstr));98}99100return true;101}102103static bool GetNetBSDProcessCPUType(ProcessInstanceInfo &process_info) {104Log *log = GetLog(LLDBLog::Host);105106if (process_info.ProcessIDIsValid()) {107auto buffer_sp = FileSystem::Instance().CreateDataBuffer(108process_info.GetExecutableFile(), 0x20, 0);109if (buffer_sp) {110uint8_t exe_class =111llvm::object::getElfArchType(112{reinterpret_cast<const char *>(buffer_sp->GetBytes()),113size_t(buffer_sp->GetByteSize())})114.first;115116switch (exe_class) {117case llvm::ELF::ELFCLASS32:118process_info.GetArchitecture() =119HostInfo::GetArchitecture(HostInfo::eArchKind32);120return true;121case llvm::ELF::ELFCLASS64:122process_info.GetArchitecture() =123HostInfo::GetArchitecture(HostInfo::eArchKind64);124return true;125default:126LLDB_LOG(log, "Unknown elf class ({0}) in file {1}", exe_class,127process_info.GetExecutableFile());128}129}130}131process_info.GetArchitecture().Clear();132return false;133}134135static bool GetNetBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) {136::kvm_t *kdp;137char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */138139struct ::kinfo_proc2 *proc_kinfo;140const int pid = process_info.GetProcessID();141int nproc;142143if (!process_info.ProcessIDIsValid())144goto error;145146if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)147goto error;148149if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_PID, pid,150sizeof(struct ::kinfo_proc2), &nproc)) ==151NULL) {152::kvm_close(kdp);153goto error;154}155156if (nproc < 1) {157::kvm_close(kdp); /* XXX: we don't check for error here */158goto error;159}160161process_info.SetParentProcessID(proc_kinfo->p_ppid);162process_info.SetUserID(proc_kinfo->p_ruid);163process_info.SetGroupID(proc_kinfo->p_rgid);164process_info.SetEffectiveUserID(proc_kinfo->p_uid);165process_info.SetEffectiveGroupID(proc_kinfo->p_gid);166167::kvm_close(kdp); /* XXX: we don't check for error here */168169return true;170171error:172process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);173process_info.SetUserID(UINT32_MAX);174process_info.SetGroupID(UINT32_MAX);175process_info.SetEffectiveUserID(UINT32_MAX);176process_info.SetEffectiveGroupID(UINT32_MAX);177return false;178}179180uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,181ProcessInstanceInfoList &process_infos) {182const ::pid_t our_pid = ::getpid();183const ::uid_t our_uid = ::getuid();184185const bool all_users =186match_info.GetMatchAllUsers() ||187// Special case, if lldb is being run as root we can attach to anything188(our_uid == 0);189190kvm_t *kdp;191char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */192if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)193return 0;194195struct ::kinfo_proc2 *proc_kinfo;196int nproc;197if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_ALL, 0,198sizeof(struct ::kinfo_proc2), &nproc)) ==199NULL) {200::kvm_close(kdp);201return 0;202}203204ProcessInstanceInfoMatch match_info_noname{match_info};205match_info_noname.SetNameMatchType(NameMatch::Ignore);206207for (int i = 0; i < nproc; i++) {208if (proc_kinfo[i].p_pid < 1)209continue; /* not valid */210/* Make sure the user is acceptable */211if (!all_users && proc_kinfo[i].p_ruid != our_uid)212continue;213214if (proc_kinfo[i].p_pid == our_pid || // Skip this process215proc_kinfo[i].p_pid == 0 || // Skip kernel (kernel pid is 0)216proc_kinfo[i].p_stat == LSZOMB || // Zombies are bad217proc_kinfo[i].p_flag & P_TRACED || // Being debugged?218proc_kinfo[i].p_flag & P_WEXIT) // Working on exiting219continue;220221// Every thread is a process in NetBSD, but all the threads of a single222// process have the same pid. Do not store the process info in the result223// list if a process with given identifier is already registered there.224if (proc_kinfo[i].p_nlwps > 1) {225bool already_registered = false;226for (size_t pi = 0; pi < process_infos.size(); pi++) {227if ((::pid_t)process_infos[pi].GetProcessID() == proc_kinfo[i].p_pid) {228already_registered = true;229break;230}231}232233if (already_registered)234continue;235}236ProcessInstanceInfo process_info;237process_info.SetProcessID(proc_kinfo[i].p_pid);238process_info.SetParentProcessID(proc_kinfo[i].p_ppid);239process_info.SetUserID(proc_kinfo[i].p_ruid);240process_info.SetGroupID(proc_kinfo[i].p_rgid);241process_info.SetEffectiveUserID(proc_kinfo[i].p_uid);242process_info.SetEffectiveGroupID(proc_kinfo[i].p_gid);243// Make sure our info matches before we go fetch the name and cpu type244if (match_info_noname.Matches(process_info) &&245GetNetBSDProcessArgs(&match_info, process_info)) {246GetNetBSDProcessCPUType(process_info);247if (match_info.Matches(process_info))248process_infos.push_back(process_info);249}250}251252kvm_close(kdp); /* XXX: we don't check for error here */253254return process_infos.size();255}256257bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {258process_info.SetProcessID(pid);259260if (GetNetBSDProcessArgs(NULL, process_info)) {261GetNetBSDProcessCPUType(process_info);262GetNetBSDProcessUserAndGroup(process_info);263return true;264}265266process_info.Clear();267return false;268}269270Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {271return Status("unimplemented");272}273274275