1 //===-- source/Host/freebsd/Host.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/ptrace.h>
14 #include <sys/sysctl.h>
17 #include <machine/elf.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/Log.h"
29 #include "lldb/Utility/NameMatches.h"
30 #include "lldb/Utility/ProcessInfo.h"
31 #include "lldb/Utility/Status.h"
32 #include "lldb/Utility/StreamString.h"
34 #include "llvm/TargetParser/Host.h"
37 extern char **environ
;
40 namespace lldb_private
{
41 class ProcessLaunchInfo
;
45 using namespace lldb_private
;
48 GetFreeBSDProcessArgs(const ProcessInstanceInfoMatch
*match_info_ptr
,
49 ProcessInstanceInfo
&process_info
) {
50 if (!process_info
.ProcessIDIsValid())
53 int pid
= process_info
.GetProcessID();
55 int mib
[4] = {CTL_KERN
, KERN_PROC
, KERN_PROC_ARGS
, pid
};
58 size_t arg_data_size
= sizeof(arg_data
);
59 if (::sysctl(mib
, 4, arg_data
, &arg_data_size
, NULL
, 0) != 0)
62 DataExtractor
data(arg_data
, arg_data_size
, endian::InlHostByteOrder(),
64 lldb::offset_t offset
= 0;
67 cstr
= data
.GetCStr(&offset
);
71 // Get pathname for pid. If that fails fall back to argv[0].
72 char pathname
[MAXPATHLEN
];
73 size_t pathname_len
= sizeof(pathname
);
74 mib
[2] = KERN_PROC_PATHNAME
;
75 if (::sysctl(mib
, 4, pathname
, &pathname_len
, NULL
, 0) == 0)
76 process_info
.GetExecutableFile().SetFile(pathname
, FileSpec::Style::native
);
78 process_info
.GetExecutableFile().SetFile(cstr
, FileSpec::Style::native
);
80 if (!(match_info_ptr
== NULL
||
81 NameMatches(process_info
.GetExecutableFile().GetFilename().GetCString(),
82 match_info_ptr
->GetNameMatchType(),
83 match_info_ptr
->GetProcessInfo().GetName())))
86 process_info
.SetArg0(cstr
);
87 Args
&proc_args
= process_info
.GetArguments();
89 const uint8_t *p
= data
.PeekData(offset
, 1);
90 while ((p
!= NULL
) && (*p
== '\0') && offset
< arg_data_size
) {
92 p
= data
.PeekData(offset
, 1);
94 if (p
== NULL
|| offset
>= arg_data_size
)
97 cstr
= data
.GetCStr(&offset
);
101 proc_args
.AppendArgument(llvm::StringRef(cstr
));
107 static bool GetFreeBSDProcessCPUType(ProcessInstanceInfo
&process_info
) {
108 if (process_info
.ProcessIDIsValid()) {
109 process_info
.GetArchitecture() =
110 HostInfo::GetArchitecture(HostInfo::eArchKindDefault
);
113 process_info
.GetArchitecture().Clear();
117 static bool GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo
&process_info
) {
118 struct kinfo_proc proc_kinfo
;
119 size_t proc_kinfo_size
;
120 const int pid
= process_info
.GetProcessID();
121 int mib
[4] = {CTL_KERN
, KERN_PROC
, KERN_PROC_PID
, pid
};
123 if (!process_info
.ProcessIDIsValid())
126 proc_kinfo_size
= sizeof(struct kinfo_proc
);
128 if (::sysctl(mib
, 4, &proc_kinfo
, &proc_kinfo_size
, NULL
, 0) != 0)
131 if (proc_kinfo_size
== 0)
134 process_info
.SetParentProcessID(proc_kinfo
.ki_ppid
);
135 process_info
.SetUserID(proc_kinfo
.ki_ruid
);
136 process_info
.SetGroupID(proc_kinfo
.ki_rgid
);
137 process_info
.SetEffectiveUserID(proc_kinfo
.ki_uid
);
138 if (proc_kinfo
.ki_ngroups
> 0)
139 process_info
.SetEffectiveGroupID(proc_kinfo
.ki_groups
[0]);
141 process_info
.SetEffectiveGroupID(UINT32_MAX
);
145 process_info
.SetParentProcessID(LLDB_INVALID_PROCESS_ID
);
146 process_info
.SetUserID(UINT32_MAX
);
147 process_info
.SetGroupID(UINT32_MAX
);
148 process_info
.SetEffectiveUserID(UINT32_MAX
);
149 process_info
.SetEffectiveGroupID(UINT32_MAX
);
153 uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch
&match_info
,
154 ProcessInstanceInfoList
&process_infos
) {
155 const ::pid_t our_pid
= ::getpid();
156 const ::uid_t our_uid
= ::getuid();
157 std::vector
<struct kinfo_proc
> kinfos
;
158 // Special case, if lldb is being run as root we can attach to anything.
159 bool all_users
= match_info
.GetMatchAllUsers() || (our_uid
== 0);
161 int mib
[3] = {CTL_KERN
, KERN_PROC
, KERN_PROC_ALL
};
163 size_t pid_data_size
= 0;
164 if (::sysctl(mib
, 3, NULL
, &pid_data_size
, NULL
, 0) != 0)
167 // Add a few extra in case a few more show up
168 const size_t estimated_pid_count
=
169 (pid_data_size
/ sizeof(struct kinfo_proc
)) + 10;
171 kinfos
.resize(estimated_pid_count
);
172 pid_data_size
= kinfos
.size() * sizeof(struct kinfo_proc
);
174 if (::sysctl(mib
, 3, &kinfos
[0], &pid_data_size
, NULL
, 0) != 0)
177 const size_t actual_pid_count
= (pid_data_size
/ sizeof(struct kinfo_proc
));
179 ProcessInstanceInfoMatch match_info_noname
{match_info
};
180 match_info_noname
.SetNameMatchType(NameMatch::Ignore
);
182 for (size_t i
= 0; i
< actual_pid_count
; i
++) {
183 const struct kinfo_proc
&kinfo
= kinfos
[i
];
185 /* Make sure the user is acceptable */
186 if (!all_users
&& kinfo
.ki_ruid
!= our_uid
)
189 if (kinfo
.ki_pid
== our_pid
|| // Skip this process
190 kinfo
.ki_pid
== 0 || // Skip kernel (kernel pid is 0)
191 kinfo
.ki_stat
== SZOMB
|| // Zombies are bad
192 kinfo
.ki_flag
& P_TRACED
|| // Being debugged?
193 kinfo
.ki_flag
& P_WEXIT
) // Working on exiting
196 // Every thread is a process in FreeBSD, but all the threads of a single
197 // process have the same pid. Do not store the process info in the result
198 // list if a process with given identifier is already registered there.
199 bool already_registered
= false;
200 for (uint32_t pi
= 0;
201 !already_registered
&& (const int)kinfo
.ki_numthreads
> 1 &&
202 pi
< (const uint32_t)process_infos
.size();
205 (process_infos
[pi
].GetProcessID() == (uint32_t)kinfo
.ki_pid
);
207 if (already_registered
)
210 ProcessInstanceInfo process_info
;
211 process_info
.SetProcessID(kinfo
.ki_pid
);
212 process_info
.SetParentProcessID(kinfo
.ki_ppid
);
213 process_info
.SetUserID(kinfo
.ki_ruid
);
214 process_info
.SetGroupID(kinfo
.ki_rgid
);
215 process_info
.SetEffectiveUserID(kinfo
.ki_svuid
);
216 process_info
.SetEffectiveGroupID(kinfo
.ki_svgid
);
218 // Make sure our info matches before we go fetch the name and cpu type
219 if (match_info_noname
.Matches(process_info
) &&
220 GetFreeBSDProcessArgs(&match_info
, process_info
)) {
221 GetFreeBSDProcessCPUType(process_info
);
222 if (match_info
.Matches(process_info
))
223 process_infos
.push_back(process_info
);
227 return process_infos
.size();
230 bool Host::GetProcessInfo(lldb::pid_t pid
, ProcessInstanceInfo
&process_info
) {
231 process_info
.SetProcessID(pid
);
233 if (GetFreeBSDProcessArgs(NULL
, process_info
)) {
234 // should use libprocstat instead of going right into sysctl?
235 GetFreeBSDProcessCPUType(process_info
);
236 GetFreeBSDProcessUserAndGroup(process_info
);
240 process_info
.Clear();
244 Environment
Host::GetEnvironment() { return Environment(environ
); }
246 Status
Host::ShellExpandArguments(ProcessLaunchInfo
&launch_info
) {
247 return Status::FromErrorString("unimplemented");