xref: /freebsd-src/contrib/llvm-project/lldb/source/Host/netbsd/HostNetBSD.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
15ffd83dbSDimitry Andric //===-- source/Host/netbsd/HostNetBSD.cpp ---------------------------------===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric 
9fe6060f1SDimitry Andric #include <cstdio>
105ffd83dbSDimitry Andric #include <dlfcn.h>
115ffd83dbSDimitry Andric #include <execinfo.h>
125ffd83dbSDimitry Andric #include <sys/proc.h>
135ffd83dbSDimitry Andric #include <sys/sysctl.h>
145ffd83dbSDimitry Andric #include <sys/types.h>
155ffd83dbSDimitry Andric 
16fe6060f1SDimitry Andric #include <climits>
175ffd83dbSDimitry Andric 
185ffd83dbSDimitry Andric #include <kvm.h>
195ffd83dbSDimitry Andric #include <sys/exec.h>
205ffd83dbSDimitry Andric #include <sys/ptrace.h>
215ffd83dbSDimitry Andric 
225ffd83dbSDimitry Andric #include "lldb/Host/FileSystem.h"
235ffd83dbSDimitry Andric #include "lldb/Host/Host.h"
245ffd83dbSDimitry Andric #include "lldb/Host/HostInfo.h"
255ffd83dbSDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
265ffd83dbSDimitry Andric #include "lldb/Utility/DataExtractor.h"
275ffd83dbSDimitry Andric #include "lldb/Utility/Endian.h"
2881ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
295ffd83dbSDimitry Andric #include "lldb/Utility/Log.h"
305ffd83dbSDimitry Andric #include "lldb/Utility/NameMatches.h"
315ffd83dbSDimitry Andric #include "lldb/Utility/ProcessInfo.h"
325ffd83dbSDimitry Andric #include "lldb/Utility/Status.h"
335ffd83dbSDimitry Andric #include "lldb/Utility/StreamString.h"
345ffd83dbSDimitry Andric 
355ffd83dbSDimitry Andric #include "llvm/Object/ELF.h"
3606c3fb27SDimitry Andric #include "llvm/TargetParser/Host.h"
375ffd83dbSDimitry Andric 
385ffd83dbSDimitry Andric extern "C" {
395ffd83dbSDimitry Andric extern char **environ;
405ffd83dbSDimitry Andric }
415ffd83dbSDimitry Andric 
425ffd83dbSDimitry Andric using namespace lldb;
435ffd83dbSDimitry Andric using namespace lldb_private;
445ffd83dbSDimitry Andric 
455ffd83dbSDimitry Andric namespace lldb_private {
465ffd83dbSDimitry Andric class ProcessLaunchInfo;
475ffd83dbSDimitry Andric }
485ffd83dbSDimitry Andric 
GetEnvironment()495ffd83dbSDimitry Andric Environment Host::GetEnvironment() { return Environment(environ); }
505ffd83dbSDimitry Andric 
GetNetBSDProcessArgs(const ProcessInstanceInfoMatch * match_info_ptr,ProcessInstanceInfo & process_info)515ffd83dbSDimitry Andric static bool GetNetBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
525ffd83dbSDimitry Andric                                  ProcessInstanceInfo &process_info) {
535ffd83dbSDimitry Andric   if (!process_info.ProcessIDIsValid())
545ffd83dbSDimitry Andric     return false;
555ffd83dbSDimitry Andric 
565ffd83dbSDimitry Andric   int pid = process_info.GetProcessID();
575ffd83dbSDimitry Andric 
585ffd83dbSDimitry Andric   int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV};
595ffd83dbSDimitry Andric 
605ffd83dbSDimitry Andric   char arg_data[8192];
615ffd83dbSDimitry Andric   size_t arg_data_size = sizeof(arg_data);
625ffd83dbSDimitry Andric   if (::sysctl(mib, 4, arg_data, &arg_data_size, NULL, 0) != 0)
635ffd83dbSDimitry Andric     return false;
645ffd83dbSDimitry Andric 
655ffd83dbSDimitry Andric   DataExtractor data(arg_data, arg_data_size, endian::InlHostByteOrder(),
665ffd83dbSDimitry Andric                      sizeof(void *));
675ffd83dbSDimitry Andric   lldb::offset_t offset = 0;
685ffd83dbSDimitry Andric   const char *cstr;
695ffd83dbSDimitry Andric 
705ffd83dbSDimitry Andric   cstr = data.GetCStr(&offset);
715ffd83dbSDimitry Andric   if (!cstr)
725ffd83dbSDimitry Andric     return false;
735ffd83dbSDimitry Andric 
745ffd83dbSDimitry Andric   process_info.GetExecutableFile().SetFile(cstr,
755ffd83dbSDimitry Andric                                            FileSpec::Style::native);
765ffd83dbSDimitry Andric 
775ffd83dbSDimitry Andric   if (!(match_info_ptr == NULL ||
785ffd83dbSDimitry Andric         NameMatches(process_info.GetExecutableFile().GetFilename().GetCString(),
795ffd83dbSDimitry Andric                     match_info_ptr->GetNameMatchType(),
805ffd83dbSDimitry Andric                     match_info_ptr->GetProcessInfo().GetName())))
815ffd83dbSDimitry Andric     return false;
825ffd83dbSDimitry Andric 
835ffd83dbSDimitry Andric   process_info.SetArg0(cstr);
845ffd83dbSDimitry Andric   Args &proc_args = process_info.GetArguments();
855ffd83dbSDimitry Andric   while (1) {
865ffd83dbSDimitry Andric     const uint8_t *p = data.PeekData(offset, 1);
875ffd83dbSDimitry Andric     while ((p != NULL) && (*p == '\0') && offset < arg_data_size) {
885ffd83dbSDimitry Andric       ++offset;
895ffd83dbSDimitry Andric       p = data.PeekData(offset, 1);
905ffd83dbSDimitry Andric     }
915ffd83dbSDimitry Andric     if (p == NULL || offset >= arg_data_size)
925ffd83dbSDimitry Andric       break;
935ffd83dbSDimitry Andric 
945ffd83dbSDimitry Andric     cstr = data.GetCStr(&offset);
955ffd83dbSDimitry Andric     if (!cstr)
965ffd83dbSDimitry Andric       break;
975ffd83dbSDimitry Andric 
985ffd83dbSDimitry Andric     proc_args.AppendArgument(llvm::StringRef(cstr));
995ffd83dbSDimitry Andric   }
1005ffd83dbSDimitry Andric 
1015ffd83dbSDimitry Andric   return true;
1025ffd83dbSDimitry Andric }
1035ffd83dbSDimitry Andric 
GetNetBSDProcessCPUType(ProcessInstanceInfo & process_info)1045ffd83dbSDimitry Andric static bool GetNetBSDProcessCPUType(ProcessInstanceInfo &process_info) {
10581ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Host);
1065ffd83dbSDimitry Andric 
1075ffd83dbSDimitry Andric   if (process_info.ProcessIDIsValid()) {
1085ffd83dbSDimitry Andric     auto buffer_sp = FileSystem::Instance().CreateDataBuffer(
1095ffd83dbSDimitry Andric         process_info.GetExecutableFile(), 0x20, 0);
1105ffd83dbSDimitry Andric     if (buffer_sp) {
111*5f757f3fSDimitry Andric       uint8_t exe_class =
112*5f757f3fSDimitry Andric           llvm::object::getElfArchType(
113*5f757f3fSDimitry Andric               {reinterpret_cast<const char *>(buffer_sp->GetBytes()),
11481ad6265SDimitry Andric                size_t(buffer_sp->GetByteSize())})
1155ffd83dbSDimitry Andric               .first;
1165ffd83dbSDimitry Andric 
1175ffd83dbSDimitry Andric       switch (exe_class) {
1185ffd83dbSDimitry Andric       case llvm::ELF::ELFCLASS32:
1195ffd83dbSDimitry Andric         process_info.GetArchitecture() =
1205ffd83dbSDimitry Andric             HostInfo::GetArchitecture(HostInfo::eArchKind32);
1215ffd83dbSDimitry Andric         return true;
1225ffd83dbSDimitry Andric       case llvm::ELF::ELFCLASS64:
1235ffd83dbSDimitry Andric         process_info.GetArchitecture() =
1245ffd83dbSDimitry Andric             HostInfo::GetArchitecture(HostInfo::eArchKind64);
1255ffd83dbSDimitry Andric         return true;
1265ffd83dbSDimitry Andric       default:
1275ffd83dbSDimitry Andric         LLDB_LOG(log, "Unknown elf class ({0}) in file {1}", exe_class,
1285ffd83dbSDimitry Andric                  process_info.GetExecutableFile());
1295ffd83dbSDimitry Andric       }
1305ffd83dbSDimitry Andric     }
1315ffd83dbSDimitry Andric   }
1325ffd83dbSDimitry Andric   process_info.GetArchitecture().Clear();
1335ffd83dbSDimitry Andric   return false;
1345ffd83dbSDimitry Andric }
1355ffd83dbSDimitry Andric 
GetNetBSDProcessUserAndGroup(ProcessInstanceInfo & process_info)1365ffd83dbSDimitry Andric static bool GetNetBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) {
1375ffd83dbSDimitry Andric   ::kvm_t *kdp;
1385ffd83dbSDimitry Andric   char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */
1395ffd83dbSDimitry Andric 
1405ffd83dbSDimitry Andric   struct ::kinfo_proc2 *proc_kinfo;
1415ffd83dbSDimitry Andric   const int pid = process_info.GetProcessID();
1425ffd83dbSDimitry Andric   int nproc;
1435ffd83dbSDimitry Andric 
1445ffd83dbSDimitry Andric   if (!process_info.ProcessIDIsValid())
1455ffd83dbSDimitry Andric     goto error;
1465ffd83dbSDimitry Andric 
1475ffd83dbSDimitry Andric   if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)
1485ffd83dbSDimitry Andric     goto error;
1495ffd83dbSDimitry Andric 
1505ffd83dbSDimitry Andric   if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_PID, pid,
1515ffd83dbSDimitry Andric                                    sizeof(struct ::kinfo_proc2), &nproc)) ==
1525ffd83dbSDimitry Andric       NULL) {
1535ffd83dbSDimitry Andric     ::kvm_close(kdp);
1545ffd83dbSDimitry Andric     goto error;
1555ffd83dbSDimitry Andric   }
1565ffd83dbSDimitry Andric 
1575ffd83dbSDimitry Andric   if (nproc < 1) {
1585ffd83dbSDimitry Andric     ::kvm_close(kdp); /* XXX: we don't check for error here */
1595ffd83dbSDimitry Andric     goto error;
1605ffd83dbSDimitry Andric   }
1615ffd83dbSDimitry Andric 
1625ffd83dbSDimitry Andric   process_info.SetParentProcessID(proc_kinfo->p_ppid);
1635ffd83dbSDimitry Andric   process_info.SetUserID(proc_kinfo->p_ruid);
1645ffd83dbSDimitry Andric   process_info.SetGroupID(proc_kinfo->p_rgid);
1655ffd83dbSDimitry Andric   process_info.SetEffectiveUserID(proc_kinfo->p_uid);
1665ffd83dbSDimitry Andric   process_info.SetEffectiveGroupID(proc_kinfo->p_gid);
1675ffd83dbSDimitry Andric 
1685ffd83dbSDimitry Andric   ::kvm_close(kdp); /* XXX: we don't check for error here */
1695ffd83dbSDimitry Andric 
1705ffd83dbSDimitry Andric   return true;
1715ffd83dbSDimitry Andric 
1725ffd83dbSDimitry Andric error:
1735ffd83dbSDimitry Andric   process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);
1745ffd83dbSDimitry Andric   process_info.SetUserID(UINT32_MAX);
1755ffd83dbSDimitry Andric   process_info.SetGroupID(UINT32_MAX);
1765ffd83dbSDimitry Andric   process_info.SetEffectiveUserID(UINT32_MAX);
1775ffd83dbSDimitry Andric   process_info.SetEffectiveGroupID(UINT32_MAX);
1785ffd83dbSDimitry Andric   return false;
1795ffd83dbSDimitry Andric }
1805ffd83dbSDimitry Andric 
FindProcessesImpl(const ProcessInstanceInfoMatch & match_info,ProcessInstanceInfoList & process_infos)1815ffd83dbSDimitry Andric uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
1825ffd83dbSDimitry Andric                                  ProcessInstanceInfoList &process_infos) {
1835ffd83dbSDimitry Andric   const ::pid_t our_pid = ::getpid();
1845ffd83dbSDimitry Andric   const ::uid_t our_uid = ::getuid();
1855ffd83dbSDimitry Andric 
1865ffd83dbSDimitry Andric   const bool all_users =
1875ffd83dbSDimitry Andric       match_info.GetMatchAllUsers() ||
1885ffd83dbSDimitry Andric       // Special case, if lldb is being run as root we can attach to anything
1895ffd83dbSDimitry Andric       (our_uid == 0);
1905ffd83dbSDimitry Andric 
1915ffd83dbSDimitry Andric   kvm_t *kdp;
1925ffd83dbSDimitry Andric   char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */
1935ffd83dbSDimitry Andric   if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)
1945ffd83dbSDimitry Andric     return 0;
1955ffd83dbSDimitry Andric 
1965ffd83dbSDimitry Andric   struct ::kinfo_proc2 *proc_kinfo;
1975ffd83dbSDimitry Andric   int nproc;
1985ffd83dbSDimitry Andric   if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_ALL, 0,
1995ffd83dbSDimitry Andric                                    sizeof(struct ::kinfo_proc2), &nproc)) ==
2005ffd83dbSDimitry Andric       NULL) {
2015ffd83dbSDimitry Andric     ::kvm_close(kdp);
2025ffd83dbSDimitry Andric     return 0;
2035ffd83dbSDimitry Andric   }
2045ffd83dbSDimitry Andric 
205e8d8bef9SDimitry Andric   ProcessInstanceInfoMatch match_info_noname{match_info};
206e8d8bef9SDimitry Andric   match_info_noname.SetNameMatchType(NameMatch::Ignore);
207e8d8bef9SDimitry Andric 
2085ffd83dbSDimitry Andric   for (int i = 0; i < nproc; i++) {
2095ffd83dbSDimitry Andric     if (proc_kinfo[i].p_pid < 1)
2105ffd83dbSDimitry Andric       continue; /* not valid */
2115ffd83dbSDimitry Andric     /* Make sure the user is acceptable */
2125ffd83dbSDimitry Andric     if (!all_users && proc_kinfo[i].p_ruid != our_uid)
2135ffd83dbSDimitry Andric       continue;
2145ffd83dbSDimitry Andric 
2155ffd83dbSDimitry Andric     if (proc_kinfo[i].p_pid == our_pid ||  // Skip this process
2165ffd83dbSDimitry Andric         proc_kinfo[i].p_pid == 0 ||        // Skip kernel (kernel pid is 0)
2175ffd83dbSDimitry Andric         proc_kinfo[i].p_stat == LSZOMB ||  // Zombies are bad
2185ffd83dbSDimitry Andric         proc_kinfo[i].p_flag & P_TRACED || // Being debugged?
2195ffd83dbSDimitry Andric         proc_kinfo[i].p_flag & P_WEXIT)    // Working on exiting
2205ffd83dbSDimitry Andric       continue;
2215ffd83dbSDimitry Andric 
2225ffd83dbSDimitry Andric     // Every thread is a process in NetBSD, but all the threads of a single
2235ffd83dbSDimitry Andric     // process have the same pid. Do not store the process info in the result
2245ffd83dbSDimitry Andric     // list if a process with given identifier is already registered there.
2255ffd83dbSDimitry Andric     if (proc_kinfo[i].p_nlwps > 1) {
2265ffd83dbSDimitry Andric       bool already_registered = false;
2275ffd83dbSDimitry Andric       for (size_t pi = 0; pi < process_infos.size(); pi++) {
228e8d8bef9SDimitry Andric         if ((::pid_t)process_infos[pi].GetProcessID() == proc_kinfo[i].p_pid) {
2295ffd83dbSDimitry Andric           already_registered = true;
2305ffd83dbSDimitry Andric           break;
2315ffd83dbSDimitry Andric         }
2325ffd83dbSDimitry Andric       }
2335ffd83dbSDimitry Andric 
2345ffd83dbSDimitry Andric       if (already_registered)
2355ffd83dbSDimitry Andric         continue;
2365ffd83dbSDimitry Andric     }
2375ffd83dbSDimitry Andric     ProcessInstanceInfo process_info;
2385ffd83dbSDimitry Andric     process_info.SetProcessID(proc_kinfo[i].p_pid);
2395ffd83dbSDimitry Andric     process_info.SetParentProcessID(proc_kinfo[i].p_ppid);
2405ffd83dbSDimitry Andric     process_info.SetUserID(proc_kinfo[i].p_ruid);
2415ffd83dbSDimitry Andric     process_info.SetGroupID(proc_kinfo[i].p_rgid);
2425ffd83dbSDimitry Andric     process_info.SetEffectiveUserID(proc_kinfo[i].p_uid);
2435ffd83dbSDimitry Andric     process_info.SetEffectiveGroupID(proc_kinfo[i].p_gid);
2445ffd83dbSDimitry Andric     // Make sure our info matches before we go fetch the name and cpu type
245e8d8bef9SDimitry Andric     if (match_info_noname.Matches(process_info) &&
2465ffd83dbSDimitry Andric         GetNetBSDProcessArgs(&match_info, process_info)) {
2475ffd83dbSDimitry Andric       GetNetBSDProcessCPUType(process_info);
2485ffd83dbSDimitry Andric       if (match_info.Matches(process_info))
2495ffd83dbSDimitry Andric         process_infos.push_back(process_info);
2505ffd83dbSDimitry Andric     }
2515ffd83dbSDimitry Andric   }
2525ffd83dbSDimitry Andric 
2535ffd83dbSDimitry Andric   kvm_close(kdp); /* XXX: we don't check for error here */
2545ffd83dbSDimitry Andric 
2555ffd83dbSDimitry Andric   return process_infos.size();
2565ffd83dbSDimitry Andric }
2575ffd83dbSDimitry Andric 
GetProcessInfo(lldb::pid_t pid,ProcessInstanceInfo & process_info)2585ffd83dbSDimitry Andric bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
2595ffd83dbSDimitry Andric   process_info.SetProcessID(pid);
2605ffd83dbSDimitry Andric 
2615ffd83dbSDimitry Andric   if (GetNetBSDProcessArgs(NULL, process_info)) {
2625ffd83dbSDimitry Andric     GetNetBSDProcessCPUType(process_info);
2635ffd83dbSDimitry Andric     GetNetBSDProcessUserAndGroup(process_info);
2645ffd83dbSDimitry Andric     return true;
2655ffd83dbSDimitry Andric   }
2665ffd83dbSDimitry Andric 
2675ffd83dbSDimitry Andric   process_info.Clear();
2685ffd83dbSDimitry Andric   return false;
2695ffd83dbSDimitry Andric }
2705ffd83dbSDimitry Andric 
ShellExpandArguments(ProcessLaunchInfo & launch_info)2715ffd83dbSDimitry Andric Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
2725ffd83dbSDimitry Andric   return Status("unimplemented");
2735ffd83dbSDimitry Andric }
274