xref: /llvm-project/lldb/source/Host/netbsd/HostNetBSD.cpp (revision cb04bc05ebab5f44b13639c0e3613506180bdbac)
106489eaaSMichał Górny //===-- source/Host/netbsd/HostNetBSD.cpp ---------------------------------===//
206489eaaSMichał Górny //
306489eaaSMichał Górny // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406489eaaSMichał Górny // See https://llvm.org/LICENSE.txt for license information.
506489eaaSMichał Górny // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606489eaaSMichał Górny //
706489eaaSMichał Górny //===----------------------------------------------------------------------===//
806489eaaSMichał Górny 
976e47d48SRaphael Isemann #include <cstdio>
1006489eaaSMichał Górny #include <dlfcn.h>
1106489eaaSMichał Górny #include <execinfo.h>
1206489eaaSMichał Górny #include <sys/proc.h>
1306489eaaSMichał Górny #include <sys/sysctl.h>
1406489eaaSMichał Górny #include <sys/types.h>
1506489eaaSMichał Górny 
1676e47d48SRaphael Isemann #include <climits>
1706489eaaSMichał Górny 
1806489eaaSMichał Górny #include <kvm.h>
1906489eaaSMichał Górny #include <sys/exec.h>
2006489eaaSMichał Górny #include <sys/ptrace.h>
2106489eaaSMichał Górny 
2206489eaaSMichał Górny #include "lldb/Host/FileSystem.h"
2306489eaaSMichał Górny #include "lldb/Host/Host.h"
2406489eaaSMichał Górny #include "lldb/Host/HostInfo.h"
2506489eaaSMichał Górny #include "lldb/Utility/DataBufferHeap.h"
2606489eaaSMichał Górny #include "lldb/Utility/DataExtractor.h"
2706489eaaSMichał Górny #include "lldb/Utility/Endian.h"
28c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
2906489eaaSMichał Górny #include "lldb/Utility/Log.h"
3006489eaaSMichał Górny #include "lldb/Utility/NameMatches.h"
3106489eaaSMichał Górny #include "lldb/Utility/ProcessInfo.h"
3206489eaaSMichał Górny #include "lldb/Utility/Status.h"
3306489eaaSMichał Górny #include "lldb/Utility/StreamString.h"
3406489eaaSMichał Górny 
3506489eaaSMichał Górny #include "llvm/Object/ELF.h"
36d768bf99SArchibald Elliott #include "llvm/TargetParser/Host.h"
3706489eaaSMichał Górny 
3806489eaaSMichał Górny using namespace lldb;
3906489eaaSMichał Górny using namespace lldb_private;
4006489eaaSMichał Górny 
4106489eaaSMichał Górny namespace lldb_private {
4206489eaaSMichał Górny class ProcessLaunchInfo;
4306489eaaSMichał Górny }
4406489eaaSMichał Górny 
4506489eaaSMichał Górny static bool GetNetBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
4606489eaaSMichał Górny                                  ProcessInstanceInfo &process_info) {
4706489eaaSMichał Górny   if (!process_info.ProcessIDIsValid())
4806489eaaSMichał Górny     return false;
4906489eaaSMichał Górny 
5006489eaaSMichał Górny   int pid = process_info.GetProcessID();
5106489eaaSMichał Górny 
5206489eaaSMichał Górny   int mib[4] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV};
5306489eaaSMichał Górny 
5406489eaaSMichał Górny   char arg_data[8192];
5506489eaaSMichał Górny   size_t arg_data_size = sizeof(arg_data);
5606489eaaSMichał Górny   if (::sysctl(mib, 4, arg_data, &arg_data_size, NULL, 0) != 0)
5706489eaaSMichał Górny     return false;
5806489eaaSMichał Górny 
5906489eaaSMichał Górny   DataExtractor data(arg_data, arg_data_size, endian::InlHostByteOrder(),
6006489eaaSMichał Górny                      sizeof(void *));
6106489eaaSMichał Górny   lldb::offset_t offset = 0;
6206489eaaSMichał Górny   const char *cstr;
6306489eaaSMichał Górny 
6406489eaaSMichał Górny   cstr = data.GetCStr(&offset);
6506489eaaSMichał Górny   if (!cstr)
6606489eaaSMichał Górny     return false;
6706489eaaSMichał Górny 
6806489eaaSMichał Górny   process_info.GetExecutableFile().SetFile(cstr,
6906489eaaSMichał Górny                                            FileSpec::Style::native);
7006489eaaSMichał Górny 
7106489eaaSMichał Górny   if (!(match_info_ptr == NULL ||
7206489eaaSMichał Górny         NameMatches(process_info.GetExecutableFile().GetFilename().GetCString(),
7306489eaaSMichał Górny                     match_info_ptr->GetNameMatchType(),
7406489eaaSMichał Górny                     match_info_ptr->GetProcessInfo().GetName())))
7506489eaaSMichał Górny     return false;
7606489eaaSMichał Górny 
7706489eaaSMichał Górny   process_info.SetArg0(cstr);
7806489eaaSMichał Górny   Args &proc_args = process_info.GetArguments();
7906489eaaSMichał Górny   while (1) {
8006489eaaSMichał Górny     const uint8_t *p = data.PeekData(offset, 1);
8106489eaaSMichał Górny     while ((p != NULL) && (*p == '\0') && offset < arg_data_size) {
8206489eaaSMichał Górny       ++offset;
8306489eaaSMichał Górny       p = data.PeekData(offset, 1);
8406489eaaSMichał Górny     }
8506489eaaSMichał Górny     if (p == NULL || offset >= arg_data_size)
8606489eaaSMichał Górny       break;
8706489eaaSMichał Górny 
8806489eaaSMichał Górny     cstr = data.GetCStr(&offset);
8906489eaaSMichał Górny     if (!cstr)
9006489eaaSMichał Górny       break;
9106489eaaSMichał Górny 
9206489eaaSMichał Górny     proc_args.AppendArgument(llvm::StringRef(cstr));
9306489eaaSMichał Górny   }
9406489eaaSMichał Górny 
9506489eaaSMichał Górny   return true;
9606489eaaSMichał Górny }
9706489eaaSMichał Górny 
9806489eaaSMichał Górny static bool GetNetBSDProcessCPUType(ProcessInstanceInfo &process_info) {
99a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Host);
10006489eaaSMichał Górny 
10106489eaaSMichał Górny   if (process_info.ProcessIDIsValid()) {
10206489eaaSMichał Górny     auto buffer_sp = FileSystem::Instance().CreateDataBuffer(
10306489eaaSMichał Górny         process_info.GetExecutableFile(), 0x20, 0);
10406489eaaSMichał Górny     if (buffer_sp) {
105c1e2457aSBrad Smith       uint8_t exe_class =
106c1e2457aSBrad Smith           llvm::object::getElfArchType(
107c1e2457aSBrad Smith               {reinterpret_cast<const char *>(buffer_sp->GetBytes()),
108f9ac13a8SJonas Devlieghere                size_t(buffer_sp->GetByteSize())})
10906489eaaSMichał Górny               .first;
11006489eaaSMichał Górny 
11106489eaaSMichał Górny       switch (exe_class) {
11206489eaaSMichał Górny       case llvm::ELF::ELFCLASS32:
11306489eaaSMichał Górny         process_info.GetArchitecture() =
11406489eaaSMichał Górny             HostInfo::GetArchitecture(HostInfo::eArchKind32);
11506489eaaSMichał Górny         return true;
11606489eaaSMichał Górny       case llvm::ELF::ELFCLASS64:
11706489eaaSMichał Górny         process_info.GetArchitecture() =
11806489eaaSMichał Górny             HostInfo::GetArchitecture(HostInfo::eArchKind64);
11906489eaaSMichał Górny         return true;
12006489eaaSMichał Górny       default:
12106489eaaSMichał Górny         LLDB_LOG(log, "Unknown elf class ({0}) in file {1}", exe_class,
12206489eaaSMichał Górny                  process_info.GetExecutableFile());
12306489eaaSMichał Górny       }
12406489eaaSMichał Górny     }
12506489eaaSMichał Górny   }
12606489eaaSMichał Górny   process_info.GetArchitecture().Clear();
12706489eaaSMichał Górny   return false;
12806489eaaSMichał Górny }
12906489eaaSMichał Górny 
13006489eaaSMichał Górny static bool GetNetBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) {
13106489eaaSMichał Górny   ::kvm_t *kdp;
13206489eaaSMichał Górny   char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */
13306489eaaSMichał Górny 
13406489eaaSMichał Górny   struct ::kinfo_proc2 *proc_kinfo;
13506489eaaSMichał Górny   const int pid = process_info.GetProcessID();
13606489eaaSMichał Górny   int nproc;
13706489eaaSMichał Górny 
13806489eaaSMichał Górny   if (!process_info.ProcessIDIsValid())
13906489eaaSMichał Górny     goto error;
14006489eaaSMichał Górny 
14106489eaaSMichał Górny   if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)
14206489eaaSMichał Górny     goto error;
14306489eaaSMichał Górny 
14406489eaaSMichał Górny   if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_PID, pid,
14506489eaaSMichał Górny                                    sizeof(struct ::kinfo_proc2), &nproc)) ==
14606489eaaSMichał Górny       NULL) {
14706489eaaSMichał Górny     ::kvm_close(kdp);
14806489eaaSMichał Górny     goto error;
14906489eaaSMichał Górny   }
15006489eaaSMichał Górny 
15106489eaaSMichał Górny   if (nproc < 1) {
15206489eaaSMichał Górny     ::kvm_close(kdp); /* XXX: we don't check for error here */
15306489eaaSMichał Górny     goto error;
15406489eaaSMichał Górny   }
15506489eaaSMichał Górny 
15606489eaaSMichał Górny   process_info.SetParentProcessID(proc_kinfo->p_ppid);
15706489eaaSMichał Górny   process_info.SetUserID(proc_kinfo->p_ruid);
15806489eaaSMichał Górny   process_info.SetGroupID(proc_kinfo->p_rgid);
15906489eaaSMichał Górny   process_info.SetEffectiveUserID(proc_kinfo->p_uid);
16006489eaaSMichał Górny   process_info.SetEffectiveGroupID(proc_kinfo->p_gid);
16106489eaaSMichał Górny 
16206489eaaSMichał Górny   ::kvm_close(kdp); /* XXX: we don't check for error here */
16306489eaaSMichał Górny 
16406489eaaSMichał Górny   return true;
16506489eaaSMichał Górny 
16606489eaaSMichał Górny error:
16706489eaaSMichał Górny   process_info.SetParentProcessID(LLDB_INVALID_PROCESS_ID);
16806489eaaSMichał Górny   process_info.SetUserID(UINT32_MAX);
16906489eaaSMichał Górny   process_info.SetGroupID(UINT32_MAX);
17006489eaaSMichał Górny   process_info.SetEffectiveUserID(UINT32_MAX);
17106489eaaSMichał Górny   process_info.SetEffectiveGroupID(UINT32_MAX);
17206489eaaSMichał Górny   return false;
17306489eaaSMichał Górny }
17406489eaaSMichał Górny 
17506489eaaSMichał Górny uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info,
17606489eaaSMichał Górny                                  ProcessInstanceInfoList &process_infos) {
17706489eaaSMichał Górny   const ::pid_t our_pid = ::getpid();
17806489eaaSMichał Górny   const ::uid_t our_uid = ::getuid();
17906489eaaSMichał Górny 
18006489eaaSMichał Górny   const bool all_users =
18106489eaaSMichał Górny       match_info.GetMatchAllUsers() ||
18206489eaaSMichał Górny       // Special case, if lldb is being run as root we can attach to anything
18306489eaaSMichał Górny       (our_uid == 0);
18406489eaaSMichał Górny 
18506489eaaSMichał Górny   kvm_t *kdp;
18606489eaaSMichał Górny   char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */
18706489eaaSMichał Górny   if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL)
18806489eaaSMichał Górny     return 0;
18906489eaaSMichał Górny 
19006489eaaSMichał Górny   struct ::kinfo_proc2 *proc_kinfo;
19106489eaaSMichał Górny   int nproc;
19206489eaaSMichał Górny   if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_ALL, 0,
19306489eaaSMichał Górny                                    sizeof(struct ::kinfo_proc2), &nproc)) ==
19406489eaaSMichał Górny       NULL) {
19506489eaaSMichał Górny     ::kvm_close(kdp);
19606489eaaSMichał Górny     return 0;
19706489eaaSMichał Górny   }
19806489eaaSMichał Górny 
199f893b293SMichał Górny   ProcessInstanceInfoMatch match_info_noname{match_info};
200f893b293SMichał Górny   match_info_noname.SetNameMatchType(NameMatch::Ignore);
201f893b293SMichał Górny 
20206489eaaSMichał Górny   for (int i = 0; i < nproc; i++) {
20306489eaaSMichał Górny     if (proc_kinfo[i].p_pid < 1)
20406489eaaSMichał Górny       continue; /* not valid */
20506489eaaSMichał Górny     /* Make sure the user is acceptable */
20606489eaaSMichał Górny     if (!all_users && proc_kinfo[i].p_ruid != our_uid)
20706489eaaSMichał Górny       continue;
20806489eaaSMichał Górny 
20906489eaaSMichał Górny     if (proc_kinfo[i].p_pid == our_pid ||  // Skip this process
21006489eaaSMichał Górny         proc_kinfo[i].p_pid == 0 ||        // Skip kernel (kernel pid is 0)
21106489eaaSMichał Górny         proc_kinfo[i].p_stat == LSZOMB ||  // Zombies are bad
21206489eaaSMichał Górny         proc_kinfo[i].p_flag & P_TRACED || // Being debugged?
21306489eaaSMichał Górny         proc_kinfo[i].p_flag & P_WEXIT)    // Working on exiting
21406489eaaSMichał Górny       continue;
21506489eaaSMichał Górny 
21606489eaaSMichał Górny     // Every thread is a process in NetBSD, but all the threads of a single
21706489eaaSMichał Górny     // process have the same pid. Do not store the process info in the result
21806489eaaSMichał Górny     // list if a process with given identifier is already registered there.
21906489eaaSMichał Górny     if (proc_kinfo[i].p_nlwps > 1) {
22006489eaaSMichał Górny       bool already_registered = false;
22106489eaaSMichał Górny       for (size_t pi = 0; pi < process_infos.size(); pi++) {
22252f42720SKamil Rytarowski         if ((::pid_t)process_infos[pi].GetProcessID() == proc_kinfo[i].p_pid) {
22306489eaaSMichał Górny           already_registered = true;
22406489eaaSMichał Górny           break;
22506489eaaSMichał Górny         }
22606489eaaSMichał Górny       }
22706489eaaSMichał Górny 
22806489eaaSMichał Górny       if (already_registered)
22906489eaaSMichał Górny         continue;
23006489eaaSMichał Górny     }
23106489eaaSMichał Górny     ProcessInstanceInfo process_info;
23206489eaaSMichał Górny     process_info.SetProcessID(proc_kinfo[i].p_pid);
23306489eaaSMichał Górny     process_info.SetParentProcessID(proc_kinfo[i].p_ppid);
23406489eaaSMichał Górny     process_info.SetUserID(proc_kinfo[i].p_ruid);
23506489eaaSMichał Górny     process_info.SetGroupID(proc_kinfo[i].p_rgid);
23606489eaaSMichał Górny     process_info.SetEffectiveUserID(proc_kinfo[i].p_uid);
23706489eaaSMichał Górny     process_info.SetEffectiveGroupID(proc_kinfo[i].p_gid);
23806489eaaSMichał Górny     // Make sure our info matches before we go fetch the name and cpu type
239f893b293SMichał Górny     if (match_info_noname.Matches(process_info) &&
24006489eaaSMichał Górny         GetNetBSDProcessArgs(&match_info, process_info)) {
24106489eaaSMichał Górny       GetNetBSDProcessCPUType(process_info);
24206489eaaSMichał Górny       if (match_info.Matches(process_info))
24306489eaaSMichał Górny         process_infos.push_back(process_info);
24406489eaaSMichał Górny     }
24506489eaaSMichał Górny   }
24606489eaaSMichał Górny 
24706489eaaSMichał Górny   kvm_close(kdp); /* XXX: we don't check for error here */
24806489eaaSMichał Górny 
24906489eaaSMichał Górny   return process_infos.size();
25006489eaaSMichał Górny }
25106489eaaSMichał Górny 
25206489eaaSMichał Górny bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
25306489eaaSMichał Górny   process_info.SetProcessID(pid);
25406489eaaSMichał Górny 
25506489eaaSMichał Górny   if (GetNetBSDProcessArgs(NULL, process_info)) {
25606489eaaSMichał Górny     GetNetBSDProcessCPUType(process_info);
25706489eaaSMichał Górny     GetNetBSDProcessUserAndGroup(process_info);
25806489eaaSMichał Górny     return true;
25906489eaaSMichał Górny   }
26006489eaaSMichał Górny 
26106489eaaSMichał Górny   process_info.Clear();
26206489eaaSMichał Górny   return false;
26306489eaaSMichał Górny }
26406489eaaSMichał Górny 
26506489eaaSMichał Górny Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
266*0642cd76SAdrian Prantl   return Status::FromErrorString("unimplemented");
26706489eaaSMichał Górny }
268