268 lines · cpp
1//===-- source/Host/netbsd/HostNetBSD.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-exception6//7//===----------------------------------------------------------------------===//8 9#include <cstdio>10#include <dlfcn.h>11#include <execinfo.h>12#include <sys/proc.h>13#include <sys/sysctl.h>14#include <sys/types.h>15 16#include <climits>17 18#include <kvm.h>19#include <sys/exec.h>20#include <sys/ptrace.h>21 22#include "lldb/Host/FileSystem.h"23#include "lldb/Host/Host.h"24#include "lldb/Host/HostInfo.h"25#include "lldb/Utility/DataBufferHeap.h"26#include "lldb/Utility/DataExtractor.h"27#include "lldb/Utility/Endian.h"28#include "lldb/Utility/LLDBLog.h"29#include "lldb/Utility/Log.h"30#include "lldb/Utility/NameMatches.h"31#include "lldb/Utility/ProcessInfo.h"32#include "lldb/Utility/Status.h"33#include "lldb/Utility/StreamString.h"34 35#include "llvm/Object/ELF.h"36#include "llvm/TargetParser/Host.h"37 38using namespace lldb;39using namespace lldb_private;40 41namespace lldb_private {42class ProcessLaunchInfo;43}44 45static bool GetNetBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,46 ProcessInstanceInfo &process_info) {47 if (!process_info.ProcessIDIsValid())48 return false;49 50 int pid = process_info.GetProcessID();51 52 int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV};53 54 char arg_data[8192];55 size_t arg_data_size = sizeof(arg_data);56 if (::sysctl(mib, 4, arg_data, &arg_data_size, NULL, 0) != 0)57 return false;58 59 DataExtractor data(arg_data, arg_data_size, endian::InlHostByteOrder(),60 sizeof(void *));61 lldb::offset_t offset = 0;62 const char *cstr;63 64 cstr = data.GetCStr(&offset);65 if (!cstr)66 return false;67 68 process_info.GetExecutableFile().SetFile(cstr,69 FileSpec::Style::native);70 71 if (!(match_info_ptr == NULL ||72 NameMatches(process_info.GetExecutableFile().GetFilename().GetCString(),73 match_info_ptr->GetNameMatchType(),74 match_info_ptr->GetProcessInfo().GetName())))75 return false;76 77 process_info.SetArg0(cstr);78 Args &proc_args = process_info.GetArguments();79 while (1) {80 const uint8_t *p = data.PeekData(offset, 1);81 while ((p != NULL) && (*p == '\0') && offset < arg_data_size) {82 ++offset;83 p = data.PeekData(offset, 1);84 }85 if (p == NULL || offset >= arg_data_size)86 break;87 88 cstr = data.GetCStr(&offset);89 if (!cstr)90 break;91 92 proc_args.AppendArgument(llvm::StringRef(cstr));93 }94 95 return true;96}97 98static bool GetNetBSDProcessCPUType(ProcessInstanceInfo &process_info) {99 Log *log = GetLog(LLDBLog::Host);100 101 if (process_info.ProcessIDIsValid()) {102 auto buffer_sp = FileSystem::Instance().CreateDataBuffer(103 process_info.GetExecutableFile(), 0x20, 0);104 if (buffer_sp) {105 uint8_t exe_class =106 llvm::object::getElfArchType(107 {reinterpret_cast<const char *>(buffer_sp->GetBytes()),108 size_t(buffer_sp->GetByteSize())})109 .first;110 111 switch (exe_class) {112 case llvm::ELF::ELFCLASS32:113 process_info.GetArchitecture() =114 HostInfo::GetArchitecture(HostInfo::eArchKind32);115 return true;116 case llvm::ELF::ELFCLASS64:117 process_info.GetArchitecture() =118 HostInfo::GetArchitecture(HostInfo::eArchKind64);119 return true;120 default:121 LLDB_LOG(log, "Unknown elf class ({0}) in file {1}", exe_class,122 process_info.GetExecutableFile());123 }124 }125 }126 process_info.GetArchitecture().Clear();127 return false;128}129 130static bool GetNetBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) {131 ::kvm_t *kdp;132 char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */133 134 struct ::kinfo_proc2 *proc_kinfo;135 const int pid = process_info.GetProcessID();136 int nproc;137 138 if (!process_info.ProcessIDIsValid())139 goto error;140 141 if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)142 goto error;143 144 if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_PID, pid,145 sizeof(struct ::kinfo_proc2), &nproc)) ==146 NULL) {147 ::kvm_close(kdp);148 goto error;149 }150 151 if (nproc < 1) {152 ::kvm_close(kdp); /* XXX: we don't check for error here */153 goto error;154 }155 156 process_info.SetParentProcessID(proc_kinfo->p_ppid);157 process_info.SetUserID(proc_kinfo->p_ruid);158 process_info.SetGroupID(proc_kinfo->p_rgid);159 process_info.SetEffectiveUserID(proc_kinfo->p_uid);160 process_info.SetEffectiveGroupID(proc_kinfo->p_gid);161 162 ::kvm_close(kdp); /* XXX: we don't check for error here */163 164 return true;165 166error:167 process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);168 process_info.SetUserID(UINT32_MAX);169 process_info.SetGroupID(UINT32_MAX);170 process_info.SetEffectiveUserID(UINT32_MAX);171 process_info.SetEffectiveGroupID(UINT32_MAX);172 return false;173}174 175uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,176 ProcessInstanceInfoList &process_infos) {177 const ::pid_t our_pid = ::getpid();178 const ::uid_t our_uid = ::getuid();179 180 const bool all_users =181 match_info.GetMatchAllUsers() ||182 // Special case, if lldb is being run as root we can attach to anything183 (our_uid == 0);184 185 kvm_t *kdp;186 char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */187 if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)188 return 0;189 190 struct ::kinfo_proc2 *proc_kinfo;191 int nproc;192 if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_ALL, 0,193 sizeof(struct ::kinfo_proc2), &nproc)) ==194 NULL) {195 ::kvm_close(kdp);196 return 0;197 }198 199 ProcessInstanceInfoMatch match_info_noname{match_info};200 match_info_noname.SetNameMatchType(NameMatch::Ignore);201 202 for (int i = 0; i < nproc; i++) {203 if (proc_kinfo[i].p_pid < 1)204 continue; /* not valid */205 /* Make sure the user is acceptable */206 if (!all_users && proc_kinfo[i].p_ruid != our_uid)207 continue;208 209 if (proc_kinfo[i].p_pid == our_pid || // Skip this process210 proc_kinfo[i].p_pid == 0 || // Skip kernel (kernel pid is 0)211 proc_kinfo[i].p_stat == LSZOMB || // Zombies are bad212 proc_kinfo[i].p_flag & P_TRACED || // Being debugged?213 proc_kinfo[i].p_flag & P_WEXIT) // Working on exiting214 continue;215 216 // Every thread is a process in NetBSD, but all the threads of a single217 // process have the same pid. Do not store the process info in the result218 // list if a process with given identifier is already registered there.219 if (proc_kinfo[i].p_nlwps > 1) {220 bool already_registered = false;221 for (size_t pi = 0; pi < process_infos.size(); pi++) {222 if ((::pid_t)process_infos[pi].GetProcessID() == proc_kinfo[i].p_pid) {223 already_registered = true;224 break;225 }226 }227 228 if (already_registered)229 continue;230 }231 ProcessInstanceInfo process_info;232 process_info.SetProcessID(proc_kinfo[i].p_pid);233 process_info.SetParentProcessID(proc_kinfo[i].p_ppid);234 process_info.SetUserID(proc_kinfo[i].p_ruid);235 process_info.SetGroupID(proc_kinfo[i].p_rgid);236 process_info.SetEffectiveUserID(proc_kinfo[i].p_uid);237 process_info.SetEffectiveGroupID(proc_kinfo[i].p_gid);238 // Make sure our info matches before we go fetch the name and cpu type239 if (match_info_noname.Matches(process_info) &&240 GetNetBSDProcessArgs(&match_info, process_info)) {241 GetNetBSDProcessCPUType(process_info);242 if (match_info.Matches(process_info))243 process_infos.push_back(process_info);244 }245 }246 247 kvm_close(kdp); /* XXX: we don't check for error here */248 249 return process_infos.size();250}251 252bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {253 process_info.SetProcessID(pid);254 255 if (GetNetBSDProcessArgs(NULL, process_info)) {256 GetNetBSDProcessCPUType(process_info);257 GetNetBSDProcessUserAndGroup(process_info);258 return true;259 }260 261 process_info.Clear();262 return false;263}264 265Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {266 return Status::FromErrorString("unimplemented");267}268