1 //===-- source/Host/netbsd/HostNetBSD.cpp ---------------------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
13 #include <sys/sysctl.h>
14 #include <sys/types.h>
20 #include <sys/ptrace.h>
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"
35 #include "llvm/Object/ELF.h"
36 #include "llvm/TargetParser/Host.h"
39 using namespace lldb_private
;
41 namespace lldb_private
{
42 class ProcessLaunchInfo
;
45 static bool GetNetBSDProcessArgs(const ProcessInstanceInfoMatch
*match_info_ptr
,
46 ProcessInstanceInfo
&process_info
) {
47 if (!process_info
.ProcessIDIsValid())
50 int pid
= process_info
.GetProcessID();
52 int mib
[4] = {CTL_KERN
, KERN_PROC_ARGS
, pid
, KERN_PROC_ARGV
};
55 size_t arg_data_size
= sizeof(arg_data
);
56 if (::sysctl(mib
, 4, arg_data
, &arg_data_size
, NULL
, 0) != 0)
59 DataExtractor
data(arg_data
, arg_data_size
, endian::InlHostByteOrder(),
61 lldb::offset_t offset
= 0;
64 cstr
= data
.GetCStr(&offset
);
68 process_info
.GetExecutableFile().SetFile(cstr
,
69 FileSpec::Style::native
);
71 if (!(match_info_ptr
== NULL
||
72 NameMatches(process_info
.GetExecutableFile().GetFilename().GetCString(),
73 match_info_ptr
->GetNameMatchType(),
74 match_info_ptr
->GetProcessInfo().GetName())))
77 process_info
.SetArg0(cstr
);
78 Args
&proc_args
= process_info
.GetArguments();
80 const uint8_t *p
= data
.PeekData(offset
, 1);
81 while ((p
!= NULL
) && (*p
== '\0') && offset
< arg_data_size
) {
83 p
= data
.PeekData(offset
, 1);
85 if (p
== NULL
|| offset
>= arg_data_size
)
88 cstr
= data
.GetCStr(&offset
);
92 proc_args
.AppendArgument(llvm::StringRef(cstr
));
98 static bool GetNetBSDProcessCPUType(ProcessInstanceInfo
&process_info
) {
99 Log
*log
= GetLog(LLDBLog::Host
);
101 if (process_info
.ProcessIDIsValid()) {
102 auto buffer_sp
= FileSystem::Instance().CreateDataBuffer(
103 process_info
.GetExecutableFile(), 0x20, 0);
106 llvm::object::getElfArchType(
107 {reinterpret_cast<const char *>(buffer_sp
->GetBytes()),
108 size_t(buffer_sp
->GetByteSize())})
112 case llvm::ELF::ELFCLASS32
:
113 process_info
.GetArchitecture() =
114 HostInfo::GetArchitecture(HostInfo::eArchKind32
);
116 case llvm::ELF::ELFCLASS64
:
117 process_info
.GetArchitecture() =
118 HostInfo::GetArchitecture(HostInfo::eArchKind64
);
121 LLDB_LOG(log
, "Unknown elf class ({0}) in file {1}", exe_class
,
122 process_info
.GetExecutableFile());
126 process_info
.GetArchitecture().Clear();
130 static bool GetNetBSDProcessUserAndGroup(ProcessInstanceInfo
&process_info
) {
132 char errbuf
[_POSIX2_LINE_MAX
]; /* XXX: error string unused */
134 struct ::kinfo_proc2
*proc_kinfo
;
135 const int pid
= process_info
.GetProcessID();
138 if (!process_info
.ProcessIDIsValid())
141 if ((kdp
= ::kvm_openfiles(NULL
, NULL
, NULL
, KVM_NO_FILES
, errbuf
)) == NULL
)
144 if ((proc_kinfo
= ::kvm_getproc2(kdp
, KERN_PROC_PID
, pid
,
145 sizeof(struct ::kinfo_proc2
), &nproc
)) ==
152 ::kvm_close(kdp
); /* XXX: we don't check for error here */
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
);
162 ::kvm_close(kdp
); /* XXX: we don't check for error here */
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
);
175 uint32_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();
180 const bool all_users
=
181 match_info
.GetMatchAllUsers() ||
182 // Special case, if lldb is being run as root we can attach to anything
186 char errbuf
[_POSIX2_LINE_MAX
]; /* XXX: error string unused */
187 if ((kdp
= ::kvm_openfiles(NULL
, NULL
, NULL
, KVM_NO_FILES
, errbuf
)) == NULL
)
190 struct ::kinfo_proc2
*proc_kinfo
;
192 if ((proc_kinfo
= ::kvm_getproc2(kdp
, KERN_PROC_ALL
, 0,
193 sizeof(struct ::kinfo_proc2
), &nproc
)) ==
199 ProcessInstanceInfoMatch match_info_noname
{match_info
};
200 match_info_noname
.SetNameMatchType(NameMatch::Ignore
);
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
)
209 if (proc_kinfo
[i
].p_pid
== our_pid
|| // Skip this process
210 proc_kinfo
[i
].p_pid
== 0 || // Skip kernel (kernel pid is 0)
211 proc_kinfo
[i
].p_stat
== LSZOMB
|| // Zombies are bad
212 proc_kinfo
[i
].p_flag
& P_TRACED
|| // Being debugged?
213 proc_kinfo
[i
].p_flag
& P_WEXIT
) // Working on exiting
216 // Every thread is a process in NetBSD, but all the threads of a single
217 // process have the same pid. Do not store the process info in the result
218 // 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;
228 if (already_registered
)
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 type
239 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
);
247 kvm_close(kdp
); /* XXX: we don't check for error here */
249 return process_infos
.size();
252 bool Host::GetProcessInfo(lldb::pid_t pid
, ProcessInstanceInfo
&process_info
) {
253 process_info
.SetProcessID(pid
);
255 if (GetNetBSDProcessArgs(NULL
, process_info
)) {
256 GetNetBSDProcessCPUType(process_info
);
257 GetNetBSDProcessUserAndGroup(process_info
);
261 process_info
.Clear();
265 Status
Host::ShellExpandArguments(ProcessLaunchInfo
&launch_info
) {
266 return Status::FromErrorString("unimplemented");