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 extern char **environ
;
43 using namespace lldb_private
;
45 namespace lldb_private
{
46 class ProcessLaunchInfo
;
49 Environment
Host::GetEnvironment() { return Environment(environ
); }
51 static bool GetNetBSDProcessArgs(const ProcessInstanceInfoMatch
*match_info_ptr
,
52 ProcessInstanceInfo
&process_info
) {
53 if (!process_info
.ProcessIDIsValid())
56 int pid
= process_info
.GetProcessID();
58 int mib
[4] = {CTL_KERN
, KERN_PROC_ARGS
, pid
, KERN_PROC_ARGV
};
61 size_t arg_data_size
= sizeof(arg_data
);
62 if (::sysctl(mib
, 4, arg_data
, &arg_data_size
, NULL
, 0) != 0)
65 DataExtractor
data(arg_data
, arg_data_size
, endian::InlHostByteOrder(),
67 lldb::offset_t offset
= 0;
70 cstr
= data
.GetCStr(&offset
);
74 process_info
.GetExecutableFile().SetFile(cstr
,
75 FileSpec::Style::native
);
77 if (!(match_info_ptr
== NULL
||
78 NameMatches(process_info
.GetExecutableFile().GetFilename().GetCString(),
79 match_info_ptr
->GetNameMatchType(),
80 match_info_ptr
->GetProcessInfo().GetName())))
83 process_info
.SetArg0(cstr
);
84 Args
&proc_args
= process_info
.GetArguments();
86 const uint8_t *p
= data
.PeekData(offset
, 1);
87 while ((p
!= NULL
) && (*p
== '\0') && offset
< arg_data_size
) {
89 p
= data
.PeekData(offset
, 1);
91 if (p
== NULL
|| offset
>= arg_data_size
)
94 cstr
= data
.GetCStr(&offset
);
98 proc_args
.AppendArgument(llvm::StringRef(cstr
));
104 static bool GetNetBSDProcessCPUType(ProcessInstanceInfo
&process_info
) {
105 Log
*log
= GetLog(LLDBLog::Host
);
107 if (process_info
.ProcessIDIsValid()) {
108 auto buffer_sp
= FileSystem::Instance().CreateDataBuffer(
109 process_info
.GetExecutableFile(), 0x20, 0);
111 uint8_t exe_class
= llvm::object::getElfArchType(
112 {reinterpret_cast<char *>(buffer_sp
->GetBytes()),
113 size_t(buffer_sp
->GetByteSize())})
117 case llvm::ELF::ELFCLASS32
:
118 process_info
.GetArchitecture() =
119 HostInfo::GetArchitecture(HostInfo::eArchKind32
);
121 case llvm::ELF::ELFCLASS64
:
122 process_info
.GetArchitecture() =
123 HostInfo::GetArchitecture(HostInfo::eArchKind64
);
126 LLDB_LOG(log
, "Unknown elf class ({0}) in file {1}", exe_class
,
127 process_info
.GetExecutableFile());
131 process_info
.GetArchitecture().Clear();
135 static bool GetNetBSDProcessUserAndGroup(ProcessInstanceInfo
&process_info
) {
137 char errbuf
[_POSIX2_LINE_MAX
]; /* XXX: error string unused */
139 struct ::kinfo_proc2
*proc_kinfo
;
140 const int pid
= process_info
.GetProcessID();
143 if (!process_info
.ProcessIDIsValid())
146 if ((kdp
= ::kvm_openfiles(NULL
, NULL
, NULL
, KVM_NO_FILES
, errbuf
)) == NULL
)
149 if ((proc_kinfo
= ::kvm_getproc2(kdp
, KERN_PROC_PID
, pid
,
150 sizeof(struct ::kinfo_proc2
), &nproc
)) ==
157 ::kvm_close(kdp
); /* XXX: we don't check for error here */
161 process_info
.SetParentProcessID(proc_kinfo
->p_ppid
);
162 process_info
.SetUserID(proc_kinfo
->p_ruid
);
163 process_info
.SetGroupID(proc_kinfo
->p_rgid
);
164 process_info
.SetEffectiveUserID(proc_kinfo
->p_uid
);
165 process_info
.SetEffectiveGroupID(proc_kinfo
->p_gid
);
167 ::kvm_close(kdp
); /* XXX: we don't check for error here */
172 process_info
.SetParentProcessID(LLDB_INVALID_PROCESS_ID
);
173 process_info
.SetUserID(UINT32_MAX
);
174 process_info
.SetGroupID(UINT32_MAX
);
175 process_info
.SetEffectiveUserID(UINT32_MAX
);
176 process_info
.SetEffectiveGroupID(UINT32_MAX
);
180 uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch
&match_info
,
181 ProcessInstanceInfoList
&process_infos
) {
182 const ::pid_t our_pid
= ::getpid();
183 const ::uid_t our_uid
= ::getuid();
185 const bool all_users
=
186 match_info
.GetMatchAllUsers() ||
187 // Special case, if lldb is being run as root we can attach to anything
191 char errbuf
[_POSIX2_LINE_MAX
]; /* XXX: error string unused */
192 if ((kdp
= ::kvm_openfiles(NULL
, NULL
, NULL
, KVM_NO_FILES
, errbuf
)) == NULL
)
195 struct ::kinfo_proc2
*proc_kinfo
;
197 if ((proc_kinfo
= ::kvm_getproc2(kdp
, KERN_PROC_ALL
, 0,
198 sizeof(struct ::kinfo_proc2
), &nproc
)) ==
204 ProcessInstanceInfoMatch match_info_noname
{match_info
};
205 match_info_noname
.SetNameMatchType(NameMatch::Ignore
);
207 for (int i
= 0; i
< nproc
; i
++) {
208 if (proc_kinfo
[i
].p_pid
< 1)
209 continue; /* not valid */
210 /* Make sure the user is acceptable */
211 if (!all_users
&& proc_kinfo
[i
].p_ruid
!= our_uid
)
214 if (proc_kinfo
[i
].p_pid
== our_pid
|| // Skip this process
215 proc_kinfo
[i
].p_pid
== 0 || // Skip kernel (kernel pid is 0)
216 proc_kinfo
[i
].p_stat
== LSZOMB
|| // Zombies are bad
217 proc_kinfo
[i
].p_flag
& P_TRACED
|| // Being debugged?
218 proc_kinfo
[i
].p_flag
& P_WEXIT
) // Working on exiting
221 // Every thread is a process in NetBSD, but all the threads of a single
222 // process have the same pid. Do not store the process info in the result
223 // list if a process with given identifier is already registered there.
224 if (proc_kinfo
[i
].p_nlwps
> 1) {
225 bool already_registered
= false;
226 for (size_t pi
= 0; pi
< process_infos
.size(); pi
++) {
227 if ((::pid_t
)process_infos
[pi
].GetProcessID() == proc_kinfo
[i
].p_pid
) {
228 already_registered
= true;
233 if (already_registered
)
236 ProcessInstanceInfo process_info
;
237 process_info
.SetProcessID(proc_kinfo
[i
].p_pid
);
238 process_info
.SetParentProcessID(proc_kinfo
[i
].p_ppid
);
239 process_info
.SetUserID(proc_kinfo
[i
].p_ruid
);
240 process_info
.SetGroupID(proc_kinfo
[i
].p_rgid
);
241 process_info
.SetEffectiveUserID(proc_kinfo
[i
].p_uid
);
242 process_info
.SetEffectiveGroupID(proc_kinfo
[i
].p_gid
);
243 // Make sure our info matches before we go fetch the name and cpu type
244 if (match_info_noname
.Matches(process_info
) &&
245 GetNetBSDProcessArgs(&match_info
, process_info
)) {
246 GetNetBSDProcessCPUType(process_info
);
247 if (match_info
.Matches(process_info
))
248 process_infos
.push_back(process_info
);
252 kvm_close(kdp
); /* XXX: we don't check for error here */
254 return process_infos
.size();
257 bool Host::GetProcessInfo(lldb::pid_t pid
, ProcessInstanceInfo
&process_info
) {
258 process_info
.SetProcessID(pid
);
260 if (GetNetBSDProcessArgs(NULL
, process_info
)) {
261 GetNetBSDProcessCPUType(process_info
);
262 GetNetBSDProcessUserAndGroup(process_info
);
266 process_info
.Clear();
270 Status
Host::ShellExpandArguments(ProcessLaunchInfo
&launch_info
) {
271 return Status("unimplemented");