brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.9 KiB · dfdbfea Raw
257 lines · cpp
1//===-- source/Host/freebsd/Host.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 <sys/types.h>10 11#include <sys/exec.h>12#include <sys/proc.h>13#include <sys/ptrace.h>14#include <sys/sysctl.h>15#include <sys/user.h>16 17#include <cstdio>18#include <dlfcn.h>19#include <execinfo.h>20 21#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/Log.h"28#include "lldb/Utility/NameMatches.h"29#include "lldb/Utility/ProcessInfo.h"30#include "lldb/Utility/Status.h"31#include "lldb/Utility/StreamString.h"32 33#include "llvm/Object/ELF.h"34#include "llvm/TargetParser/Host.h"35 36namespace lldb_private {37class ProcessLaunchInfo;38}39 40using namespace lldb;41using namespace lldb_private;42 43static bool44GetFreeBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,45                      ProcessInstanceInfo &process_info) {46  if (!process_info.ProcessIDIsValid())47    return false;48 49  int pid = process_info.GetProcessID();50 51  int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ARGS, pid};52 53  char arg_data[8192];54  size_t arg_data_size = sizeof(arg_data);55  if (::sysctl(mib, 4, arg_data, &arg_data_size, NULL, 0) != 0)56    return false;57 58  DataExtractor data(arg_data, arg_data_size, endian::InlHostByteOrder(),59                     sizeof(void *));60  lldb::offset_t offset = 0;61  const char *cstr;62 63  cstr = data.GetCStr(&offset);64  if (!cstr)65    return false;66 67  // Get pathname for pid. If that fails fall back to argv[0].68  char pathname[MAXPATHLEN];69  size_t pathname_len = sizeof(pathname);70  mib[2] = KERN_PROC_PATHNAME;71  if (::sysctl(mib, 4, pathname, &pathname_len, NULL, 0) == 0)72    process_info.GetExecutableFile().SetFile(pathname, FileSpec::Style::native);73  else74    process_info.GetExecutableFile().SetFile(cstr, FileSpec::Style::native);75 76  if (!(match_info_ptr == NULL ||77        NameMatches(process_info.GetExecutableFile().GetFilename().GetCString(),78                    match_info_ptr->GetNameMatchType(),79                    match_info_ptr->GetProcessInfo().GetName())))80    return false;81 82  process_info.SetArg0(cstr);83  Args &proc_args = process_info.GetArguments();84  while (1) {85    const uint8_t *p = data.PeekData(offset, 1);86    while ((p != NULL) && (*p == '\0') && offset < arg_data_size) {87      ++offset;88      p = data.PeekData(offset, 1);89    }90    if (p == NULL || offset >= arg_data_size)91      break;92 93    cstr = data.GetCStr(&offset);94    if (!cstr)95      break;96 97    proc_args.AppendArgument(llvm::StringRef(cstr));98  }99 100  auto buffer_sp = FileSystem::Instance().CreateDataBuffer(pathname, 0x20, 0);101  if (!buffer_sp) {102    process_info.Clear();103    return true;104  }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.SetArchitecture(114        HostInfo::GetArchitecture(HostInfo::eArchKind32));115    break;116  case llvm::ELF::ELFCLASS64:117    process_info.SetArchitecture(118        HostInfo::GetArchitecture(HostInfo::eArchKind64));119    break;120  case llvm::ELF::ELFCLASSNONE:121    process_info.SetArchitecture(122        HostInfo::GetArchitecture(HostInfo::eArchKindDefault));123    break;124  }125 126  return true;127}128 129static bool GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) {130  struct kinfo_proc proc_kinfo;131  size_t proc_kinfo_size;132  const int pid = process_info.GetProcessID();133  int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};134 135  if (!process_info.ProcessIDIsValid())136    goto error;137 138  proc_kinfo_size = sizeof(struct kinfo_proc);139 140  if (::sysctl(mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) != 0)141    goto error;142 143  if (proc_kinfo_size == 0)144    goto error;145 146  process_info.SetParentProcessID(proc_kinfo.ki_ppid);147  process_info.SetUserID(proc_kinfo.ki_ruid);148  process_info.SetGroupID(proc_kinfo.ki_rgid);149  process_info.SetEffectiveUserID(proc_kinfo.ki_uid);150  if (proc_kinfo.ki_ngroups > 0)151    process_info.SetEffectiveGroupID(proc_kinfo.ki_groups[0]);152  else153    process_info.SetEffectiveGroupID(UINT32_MAX);154  return true;155 156error:157  process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);158  process_info.SetUserID(UINT32_MAX);159  process_info.SetGroupID(UINT32_MAX);160  process_info.SetEffectiveUserID(UINT32_MAX);161  process_info.SetEffectiveGroupID(UINT32_MAX);162  return false;163}164 165uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,166                                 ProcessInstanceInfoList &process_infos) {167  const ::pid_t our_pid = ::getpid();168  const ::uid_t our_uid = ::getuid();169  std::vector<struct kinfo_proc> kinfos;170  // Special case, if lldb is being run as root we can attach to anything.171  bool all_users = match_info.GetMatchAllUsers() || (our_uid == 0);172 173  int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};174 175  size_t pid_data_size = 0;176  if (::sysctl(mib, 3, NULL, &pid_data_size, NULL, 0) != 0)177    return 0;178 179  // Add a few extra in case a few more show up180  const size_t estimated_pid_count =181      (pid_data_size / sizeof(struct kinfo_proc)) + 10;182 183  kinfos.resize(estimated_pid_count);184  pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);185 186  if (::sysctl(mib, 3, &kinfos[0], &pid_data_size, NULL, 0) != 0)187    return 0;188 189  const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));190 191  ProcessInstanceInfoMatch match_info_noname{match_info};192  match_info_noname.SetNameMatchType(NameMatch::Ignore);193 194  for (size_t i = 0; i < actual_pid_count; i++) {195    const struct kinfo_proc &kinfo = kinfos[i];196 197    /* Make sure the user is acceptable */198    if (!all_users && kinfo.ki_ruid != our_uid)199      continue;200 201    if (kinfo.ki_pid == our_pid ||  // Skip this process202        kinfo.ki_pid == 0 ||        // Skip kernel (kernel pid is 0)203        kinfo.ki_stat == SZOMB ||   // Zombies are bad204        kinfo.ki_flag & P_TRACED || // Being debugged?205        kinfo.ki_flag & P_WEXIT)    // Working on exiting206      continue;207 208    // Every thread is a process in FreeBSD, but all the threads of a single209    // process have the same pid. Do not store the process info in the result210    // list if a process with given identifier is already registered there.211    bool already_registered = false;212    for (uint32_t pi = 0;213         !already_registered && (const int)kinfo.ki_numthreads > 1 &&214         pi < (const uint32_t)process_infos.size();215         pi++)216      already_registered =217          (process_infos[pi].GetProcessID() == (uint32_t)kinfo.ki_pid);218 219    if (already_registered)220      continue;221 222    ProcessInstanceInfo process_info;223    process_info.SetProcessID(kinfo.ki_pid);224    process_info.SetParentProcessID(kinfo.ki_ppid);225    process_info.SetUserID(kinfo.ki_ruid);226    process_info.SetGroupID(kinfo.ki_rgid);227    process_info.SetEffectiveUserID(kinfo.ki_svuid);228    process_info.SetEffectiveGroupID(kinfo.ki_svgid);229 230    // Make sure our info matches before we go fetch the name and cpu type231    if (match_info_noname.Matches(process_info) &&232        GetFreeBSDProcessArgs(&match_info, process_info)) {233      if (match_info.Matches(process_info))234        process_infos.push_back(process_info);235    }236  }237 238  return process_infos.size();239}240 241bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {242  process_info.SetProcessID(pid);243 244  if (GetFreeBSDProcessArgs(NULL, process_info)) {245    // should use libprocstat instead of going right into sysctl?246    GetFreeBSDProcessUserAndGroup(process_info);247    return true;248  }249 250  process_info.Clear();251  return false;252}253 254Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {255  return Status::FromErrorString("unimplemented");256}257