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