brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.2 KiB · 8904df5 Raw
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