1 | //===-- ThreadElfCore.cpp -------------------------------------------------===// |
2 | // |
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 |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "lldb/Target/RegisterContext.h" |
10 | #include "lldb/Target/StopInfo.h" |
11 | #include "lldb/Target/Target.h" |
12 | #include "lldb/Target/UnixSignals.h" |
13 | #include "lldb/Target/Unwind.h" |
14 | #include "lldb/Utility/DataExtractor.h" |
15 | #include "lldb/Utility/LLDBLog.h" |
16 | #include "lldb/Utility/Log.h" |
17 | #include "lldb/Utility/ProcessInfo.h" |
18 | |
19 | #include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" |
20 | #include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" |
21 | #include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" |
22 | #include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" |
23 | #include "Plugins/Process/Utility/RegisterContextLinux_i386.h" |
24 | #include "Plugins/Process/Utility/RegisterContextLinux_s390x.h" |
25 | #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" |
26 | #include "Plugins/Process/Utility/RegisterContextNetBSD_i386.h" |
27 | #include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h" |
28 | #include "Plugins/Process/Utility/RegisterContextOpenBSD_i386.h" |
29 | #include "Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h" |
30 | #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" |
31 | #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" |
32 | #include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h" |
33 | #include "ProcessElfCore.h" |
34 | #include "RegisterContextLinuxCore_x86_64.h" |
35 | #include "RegisterContextPOSIXCore_arm.h" |
36 | #include "RegisterContextPOSIXCore_arm64.h" |
37 | #include "RegisterContextPOSIXCore_loongarch64.h" |
38 | #include "RegisterContextPOSIXCore_mips64.h" |
39 | #include "RegisterContextPOSIXCore_powerpc.h" |
40 | #include "RegisterContextPOSIXCore_ppc64le.h" |
41 | #include "RegisterContextPOSIXCore_riscv32.h" |
42 | #include "RegisterContextPOSIXCore_riscv64.h" |
43 | #include "RegisterContextPOSIXCore_s390x.h" |
44 | #include "RegisterContextPOSIXCore_x86_64.h" |
45 | #include "ThreadElfCore.h" |
46 | |
47 | #include <memory> |
48 | |
49 | using namespace lldb; |
50 | using namespace lldb_private; |
51 | |
52 | // Construct a Thread object with given data |
53 | ThreadElfCore::ThreadElfCore(Process &process, const ThreadData &td) |
54 | : Thread(process, td.tid), m_thread_name(td.name), m_thread_reg_ctx_sp(), |
55 | m_gpregset_data(td.gpregset), m_notes(td.notes), |
56 | m_siginfo_bytes(std::move(td.siginfo_bytes)), m_signo(td.signo) {} |
57 | |
58 | ThreadElfCore::~ThreadElfCore() { DestroyThread(); } |
59 | |
60 | void ThreadElfCore::RefreshStateAfterStop() { |
61 | GetRegisterContext()->InvalidateIfNeeded(force: false); |
62 | } |
63 | |
64 | RegisterContextSP ThreadElfCore::GetRegisterContext() { |
65 | if (!m_reg_context_sp) { |
66 | m_reg_context_sp = CreateRegisterContextForFrame(frame: nullptr); |
67 | } |
68 | return m_reg_context_sp; |
69 | } |
70 | |
71 | RegisterContextSP |
72 | ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { |
73 | RegisterContextSP reg_ctx_sp; |
74 | uint32_t concrete_frame_idx = 0; |
75 | Log *log = GetLog(mask: LLDBLog::Thread); |
76 | |
77 | if (frame) |
78 | concrete_frame_idx = frame->GetConcreteFrameIndex(); |
79 | |
80 | bool is_linux = false; |
81 | if (concrete_frame_idx == 0) { |
82 | if (m_thread_reg_ctx_sp) |
83 | return m_thread_reg_ctx_sp; |
84 | |
85 | ProcessElfCore *process = static_cast<ProcessElfCore *>(GetProcess().get()); |
86 | ArchSpec arch = process->GetArchitecture(); |
87 | RegisterInfoInterface *reg_interface = nullptr; |
88 | |
89 | switch (arch.GetTriple().getOS()) { |
90 | case llvm::Triple::FreeBSD: { |
91 | switch (arch.GetMachine()) { |
92 | case llvm::Triple::aarch64: |
93 | case llvm::Triple::arm: |
94 | break; |
95 | case llvm::Triple::ppc: |
96 | reg_interface = new RegisterContextFreeBSD_powerpc32(arch); |
97 | break; |
98 | case llvm::Triple::ppc64: |
99 | case llvm::Triple::ppc64le: |
100 | reg_interface = new RegisterContextFreeBSD_powerpc64(arch); |
101 | break; |
102 | case llvm::Triple::mips64: |
103 | reg_interface = new RegisterContextFreeBSD_mips64(arch); |
104 | break; |
105 | case llvm::Triple::x86: |
106 | reg_interface = new RegisterContextFreeBSD_i386(arch); |
107 | break; |
108 | case llvm::Triple::x86_64: |
109 | reg_interface = new RegisterContextFreeBSD_x86_64(arch); |
110 | break; |
111 | default: |
112 | break; |
113 | } |
114 | break; |
115 | } |
116 | |
117 | case llvm::Triple::NetBSD: { |
118 | switch (arch.GetMachine()) { |
119 | case llvm::Triple::aarch64: |
120 | break; |
121 | case llvm::Triple::x86: |
122 | reg_interface = new RegisterContextNetBSD_i386(arch); |
123 | break; |
124 | case llvm::Triple::x86_64: |
125 | reg_interface = new RegisterContextNetBSD_x86_64(arch); |
126 | break; |
127 | default: |
128 | break; |
129 | } |
130 | break; |
131 | } |
132 | |
133 | case llvm::Triple::Linux: { |
134 | is_linux = true; |
135 | switch (arch.GetMachine()) { |
136 | case llvm::Triple::aarch64: |
137 | break; |
138 | case llvm::Triple::ppc64le: |
139 | reg_interface = new RegisterInfoPOSIX_ppc64le(arch); |
140 | break; |
141 | case llvm::Triple::systemz: |
142 | reg_interface = new RegisterContextLinux_s390x(arch); |
143 | break; |
144 | case llvm::Triple::x86: |
145 | reg_interface = new RegisterContextLinux_i386(arch); |
146 | break; |
147 | case llvm::Triple::x86_64: |
148 | reg_interface = new RegisterContextLinux_x86_64(arch); |
149 | break; |
150 | default: |
151 | break; |
152 | } |
153 | break; |
154 | } |
155 | |
156 | case llvm::Triple::OpenBSD: { |
157 | switch (arch.GetMachine()) { |
158 | case llvm::Triple::aarch64: |
159 | break; |
160 | case llvm::Triple::x86: |
161 | reg_interface = new RegisterContextOpenBSD_i386(arch); |
162 | break; |
163 | case llvm::Triple::x86_64: |
164 | reg_interface = new RegisterContextOpenBSD_x86_64(arch); |
165 | break; |
166 | default: |
167 | break; |
168 | } |
169 | break; |
170 | } |
171 | |
172 | default: |
173 | break; |
174 | } |
175 | |
176 | if (!reg_interface && arch.GetMachine() != llvm::Triple::aarch64 && |
177 | arch.GetMachine() != llvm::Triple::arm && |
178 | arch.GetMachine() != llvm::Triple::loongarch64 && |
179 | arch.GetMachine() != llvm::Triple::riscv64 && |
180 | arch.GetMachine() != llvm::Triple::riscv32) { |
181 | LLDB_LOGF(log, "elf-core::%s:: Architecture(%d) or OS(%d) not supported" , |
182 | __FUNCTION__, arch.GetMachine(), arch.GetTriple().getOS()); |
183 | assert(false && "Architecture or OS not supported" ); |
184 | } |
185 | |
186 | switch (arch.GetMachine()) { |
187 | case llvm::Triple::aarch64: |
188 | m_thread_reg_ctx_sp = RegisterContextCorePOSIX_arm64::Create( |
189 | thread&: *this, arch, gpregset: m_gpregset_data, notes: m_notes); |
190 | break; |
191 | case llvm::Triple::arm: |
192 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_arm>( |
193 | args&: *this, args: std::make_unique<RegisterInfoPOSIX_arm>(args&: arch), args&: m_gpregset_data, |
194 | args&: m_notes); |
195 | break; |
196 | case llvm::Triple::loongarch64: |
197 | m_thread_reg_ctx_sp = RegisterContextCorePOSIX_loongarch64::Create( |
198 | thread&: *this, arch, gpregset: m_gpregset_data, notes: m_notes); |
199 | break; |
200 | case llvm::Triple::riscv32: |
201 | m_thread_reg_ctx_sp = RegisterContextCorePOSIX_riscv32::Create( |
202 | thread&: *this, arch, gpregset: m_gpregset_data, notes: m_notes); |
203 | break; |
204 | case llvm::Triple::riscv64: |
205 | m_thread_reg_ctx_sp = RegisterContextCorePOSIX_riscv64::Create( |
206 | thread&: *this, arch, gpregset: m_gpregset_data, notes: m_notes); |
207 | break; |
208 | case llvm::Triple::mipsel: |
209 | case llvm::Triple::mips: |
210 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_mips64>( |
211 | args&: *this, args&: reg_interface, args&: m_gpregset_data, args&: m_notes); |
212 | break; |
213 | case llvm::Triple::mips64: |
214 | case llvm::Triple::mips64el: |
215 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_mips64>( |
216 | args&: *this, args&: reg_interface, args&: m_gpregset_data, args&: m_notes); |
217 | break; |
218 | case llvm::Triple::ppc: |
219 | case llvm::Triple::ppc64: |
220 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_powerpc>( |
221 | args&: *this, args&: reg_interface, args&: m_gpregset_data, args&: m_notes); |
222 | break; |
223 | case llvm::Triple::ppc64le: |
224 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_ppc64le>( |
225 | args&: *this, args&: reg_interface, args&: m_gpregset_data, args&: m_notes); |
226 | break; |
227 | case llvm::Triple::systemz: |
228 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_s390x>( |
229 | args&: *this, args&: reg_interface, args&: m_gpregset_data, args&: m_notes); |
230 | break; |
231 | case llvm::Triple::x86: |
232 | case llvm::Triple::x86_64: |
233 | if (is_linux) { |
234 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextLinuxCore_x86_64>( |
235 | args&: *this, args&: reg_interface, args&: m_gpregset_data, args&: m_notes); |
236 | } else { |
237 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_x86_64>( |
238 | args&: *this, args&: reg_interface, args&: m_gpregset_data, args&: m_notes); |
239 | } |
240 | break; |
241 | default: |
242 | break; |
243 | } |
244 | |
245 | reg_ctx_sp = m_thread_reg_ctx_sp; |
246 | } else { |
247 | reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame); |
248 | } |
249 | return reg_ctx_sp; |
250 | } |
251 | |
252 | llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> |
253 | ThreadElfCore::GetSiginfo(size_t max_size) const { |
254 | if (m_siginfo_bytes.empty()) |
255 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
256 | S: "no siginfo note" ); |
257 | |
258 | return llvm::MemoryBuffer::getMemBufferCopy(InputData: m_siginfo_bytes, |
259 | BufferName: "siginfo note bytes" ); |
260 | } |
261 | |
262 | bool ThreadElfCore::CalculateStopInfo() { |
263 | ProcessSP process_sp(GetProcess()); |
264 | if (!process_sp) |
265 | return false; |
266 | |
267 | PlatformSP platform_sp = process_sp->GetTarget().GetPlatform(); |
268 | if (platform_sp) { |
269 | lldb::StopInfoSP stopinfo_sp = platform_sp->GetStopInfoFromSiginfo(thread&: *this); |
270 | // The platform SP can optionally handle creating the stop info from the |
271 | // siginfo value however it's not guaraunteed to be implemented on every |
272 | // platform, so if we fall through this case, we create from just the signo. |
273 | if (stopinfo_sp) { |
274 | SetStopInfo(std::move(stopinfo_sp)); |
275 | return true; |
276 | } |
277 | } |
278 | |
279 | SetStopInfo(StopInfo::CreateStopReasonWithSignal(thread&: *this, signo: m_signo)); |
280 | return true; |
281 | } |
282 | |
283 | // Parse PRSTATUS from NOTE entry |
284 | ELFLinuxPrStatus::ELFLinuxPrStatus() { |
285 | memset(s: this, c: 0, n: sizeof(ELFLinuxPrStatus)); |
286 | } |
287 | |
288 | size_t ELFLinuxPrStatus::GetSize(const lldb_private::ArchSpec &arch) { |
289 | constexpr size_t mips_linux_pr_status_size_o32 = 96; |
290 | constexpr size_t mips_linux_pr_status_size_n32 = 72; |
291 | constexpr size_t num_ptr_size_members = 10; |
292 | if (arch.IsMIPS()) { |
293 | std::string abi = arch.GetTargetABI(); |
294 | assert(!abi.empty() && "ABI is not set" ); |
295 | if (abi == "n64" ) |
296 | return sizeof(ELFLinuxPrStatus); |
297 | else if (abi == "o32" ) |
298 | return mips_linux_pr_status_size_o32; |
299 | // N32 ABI |
300 | return mips_linux_pr_status_size_n32; |
301 | } |
302 | switch (arch.GetCore()) { |
303 | case lldb_private::ArchSpec::eCore_x86_32_i386: |
304 | case lldb_private::ArchSpec::eCore_x86_32_i486: |
305 | return 72; |
306 | default: |
307 | if (arch.GetAddressByteSize() == 8) |
308 | return sizeof(ELFLinuxPrStatus); |
309 | else |
310 | return sizeof(ELFLinuxPrStatus) - num_ptr_size_members * 4; |
311 | } |
312 | } |
313 | |
314 | Status ELFLinuxPrStatus::(const DataExtractor &data, |
315 | const ArchSpec &arch) { |
316 | Status error; |
317 | if (GetSize(arch) > data.GetByteSize()) { |
318 | error = Status::FromErrorStringWithFormat( |
319 | format: "NT_PRSTATUS size should be %zu, but the remaining bytes are: %" PRIu64, |
320 | GetSize(arch), data.GetByteSize()); |
321 | return error; |
322 | } |
323 | |
324 | // Read field by field to correctly account for endianess of both the core |
325 | // dump and the platform running lldb. |
326 | offset_t offset = 0; |
327 | si_signo = data.GetU32(offset_ptr: &offset); |
328 | si_code = data.GetU32(offset_ptr: &offset); |
329 | si_errno = data.GetU32(offset_ptr: &offset); |
330 | |
331 | pr_cursig = data.GetU16(offset_ptr: &offset); |
332 | offset += 2; // pad |
333 | |
334 | pr_sigpend = data.GetAddress(offset_ptr: &offset); |
335 | pr_sighold = data.GetAddress(offset_ptr: &offset); |
336 | |
337 | pr_pid = data.GetU32(offset_ptr: &offset); |
338 | pr_ppid = data.GetU32(offset_ptr: &offset); |
339 | pr_pgrp = data.GetU32(offset_ptr: &offset); |
340 | pr_sid = data.GetU32(offset_ptr: &offset); |
341 | |
342 | pr_utime.tv_sec = data.GetAddress(offset_ptr: &offset); |
343 | pr_utime.tv_usec = data.GetAddress(offset_ptr: &offset); |
344 | |
345 | pr_stime.tv_sec = data.GetAddress(offset_ptr: &offset); |
346 | pr_stime.tv_usec = data.GetAddress(offset_ptr: &offset); |
347 | |
348 | pr_cutime.tv_sec = data.GetAddress(offset_ptr: &offset); |
349 | pr_cutime.tv_usec = data.GetAddress(offset_ptr: &offset); |
350 | |
351 | pr_cstime.tv_sec = data.GetAddress(offset_ptr: &offset); |
352 | pr_cstime.tv_usec = data.GetAddress(offset_ptr: &offset); |
353 | |
354 | return error; |
355 | } |
356 | |
357 | static struct compat_timeval |
358 | copy_timespecs(const ProcessInstanceInfo::timespec &oth) { |
359 | using sec_t = decltype(compat_timeval::tv_sec); |
360 | using usec_t = decltype(compat_timeval::tv_usec); |
361 | return {.tv_sec: static_cast<sec_t>(oth.tv_sec), .tv_usec: static_cast<usec_t>(oth.tv_usec)}; |
362 | } |
363 | |
364 | std::optional<ELFLinuxPrStatus> |
365 | ELFLinuxPrStatus::Populate(const lldb::ThreadSP &thread_sp) { |
366 | ELFLinuxPrStatus prstatus{}; |
367 | prstatus.pr_pid = thread_sp->GetID(); |
368 | lldb::ProcessSP process_sp = thread_sp->GetProcess(); |
369 | ProcessInstanceInfo info; |
370 | if (!process_sp->GetProcessInfo(info)) |
371 | return std::nullopt; |
372 | |
373 | prstatus.pr_ppid = info.GetParentProcessID(); |
374 | prstatus.pr_pgrp = info.GetProcessGroupID(); |
375 | prstatus.pr_sid = info.GetProcessSessionID(); |
376 | prstatus.pr_utime = copy_timespecs(oth: info.GetUserTime()); |
377 | prstatus.pr_stime = copy_timespecs(oth: info.GetSystemTime()); |
378 | prstatus.pr_cutime = copy_timespecs(oth: info.GetCumulativeUserTime()); |
379 | prstatus.pr_cstime = copy_timespecs(oth: info.GetCumulativeSystemTime()); |
380 | return prstatus; |
381 | } |
382 | |
383 | // Parse PRPSINFO from NOTE entry |
384 | ELFLinuxPrPsInfo::ELFLinuxPrPsInfo() { |
385 | memset(s: this, c: 0, n: sizeof(ELFLinuxPrPsInfo)); |
386 | } |
387 | |
388 | size_t ELFLinuxPrPsInfo::GetSize(const lldb_private::ArchSpec &arch) { |
389 | constexpr size_t mips_linux_pr_psinfo_size_o32_n32 = 128; |
390 | if (arch.IsMIPS()) { |
391 | uint8_t address_byte_size = arch.GetAddressByteSize(); |
392 | if (address_byte_size == 8) |
393 | return sizeof(ELFLinuxPrPsInfo); |
394 | return mips_linux_pr_psinfo_size_o32_n32; |
395 | } |
396 | |
397 | switch (arch.GetCore()) { |
398 | case lldb_private::ArchSpec::eCore_s390x_generic: |
399 | case lldb_private::ArchSpec::eCore_x86_64_x86_64: |
400 | return sizeof(ELFLinuxPrPsInfo); |
401 | case lldb_private::ArchSpec::eCore_x86_32_i386: |
402 | case lldb_private::ArchSpec::eCore_x86_32_i486: |
403 | return 124; |
404 | default: |
405 | return 0; |
406 | } |
407 | } |
408 | |
409 | Status ELFLinuxPrPsInfo::(const DataExtractor &data, |
410 | const ArchSpec &arch) { |
411 | Status error; |
412 | ByteOrder byteorder = data.GetByteOrder(); |
413 | if (GetSize(arch) > data.GetByteSize()) { |
414 | error = Status::FromErrorStringWithFormat( |
415 | format: "NT_PRPSINFO size should be %zu, but the remaining bytes are: %" PRIu64, |
416 | GetSize(arch), data.GetByteSize()); |
417 | return error; |
418 | } |
419 | size_t size = 0; |
420 | offset_t offset = 0; |
421 | |
422 | pr_state = data.GetU8(offset_ptr: &offset); |
423 | pr_sname = data.GetU8(offset_ptr: &offset); |
424 | pr_zomb = data.GetU8(offset_ptr: &offset); |
425 | pr_nice = data.GetU8(offset_ptr: &offset); |
426 | if (data.GetAddressByteSize() == 8) { |
427 | // Word align the next field on 64 bit. |
428 | offset += 4; |
429 | } |
430 | |
431 | pr_flag = data.GetAddress(offset_ptr: &offset); |
432 | |
433 | if (arch.IsMIPS()) { |
434 | // The pr_uid and pr_gid is always 32 bit irrespective of platforms |
435 | pr_uid = data.GetU32(offset_ptr: &offset); |
436 | pr_gid = data.GetU32(offset_ptr: &offset); |
437 | } else { |
438 | // 16 bit on 32 bit platforms, 32 bit on 64 bit platforms |
439 | pr_uid = data.GetMaxU64(offset_ptr: &offset, byte_size: data.GetAddressByteSize() >> 1); |
440 | pr_gid = data.GetMaxU64(offset_ptr: &offset, byte_size: data.GetAddressByteSize() >> 1); |
441 | } |
442 | |
443 | pr_pid = data.GetU32(offset_ptr: &offset); |
444 | pr_ppid = data.GetU32(offset_ptr: &offset); |
445 | pr_pgrp = data.GetU32(offset_ptr: &offset); |
446 | pr_sid = data.GetU32(offset_ptr: &offset); |
447 | |
448 | size = 16; |
449 | data.ExtractBytes(offset, length: size, dst_byte_order: byteorder, dst: pr_fname); |
450 | offset += size; |
451 | |
452 | size = 80; |
453 | data.ExtractBytes(offset, length: size, dst_byte_order: byteorder, dst: pr_psargs); |
454 | offset += size; |
455 | |
456 | return error; |
457 | } |
458 | |
459 | std::optional<ELFLinuxPrPsInfo> |
460 | ELFLinuxPrPsInfo::Populate(const lldb::ProcessSP &process_sp) { |
461 | ProcessInstanceInfo info; |
462 | if (!process_sp->GetProcessInfo(info)) |
463 | return std::nullopt; |
464 | |
465 | return Populate(info, state: process_sp->GetState()); |
466 | } |
467 | |
468 | std::optional<ELFLinuxPrPsInfo> |
469 | ELFLinuxPrPsInfo::Populate(const lldb_private::ProcessInstanceInfo &info, |
470 | lldb::StateType process_state) { |
471 | ELFLinuxPrPsInfo prpsinfo{}; |
472 | prpsinfo.pr_pid = info.GetProcessID(); |
473 | prpsinfo.pr_nice = info.GetPriorityValue().value_or(u: 0); |
474 | prpsinfo.pr_zomb = 0; |
475 | if (auto zombie_opt = info.IsZombie(); zombie_opt.value_or(u: false)) { |
476 | prpsinfo.pr_zomb = 1; |
477 | } |
478 | /** |
479 | * In the linux kernel this comes from: |
480 | * state = READ_ONCE(p->__state); |
481 | * i = state ? ffz(~state) + 1 : 0; |
482 | * psinfo->pr_sname = (i > 5) ? '.' : "RSDTZW"[i]; |
483 | * |
484 | * So we replicate that here. From proc_pid_stats(5) |
485 | * R = Running |
486 | * S = Sleeping on uninterrutible wait |
487 | * D = Waiting on uninterruptable disk sleep |
488 | * T = Tracing stop |
489 | * Z = Zombie |
490 | * W = Paging |
491 | */ |
492 | switch (process_state) { |
493 | case lldb::StateType::eStateSuspended: |
494 | prpsinfo.pr_sname = 'S'; |
495 | prpsinfo.pr_state = 1; |
496 | break; |
497 | case lldb::StateType::eStateStopped: |
498 | [[fallthrough]]; |
499 | case lldb::StateType::eStateStepping: |
500 | prpsinfo.pr_sname = 'T'; |
501 | prpsinfo.pr_state = 3; |
502 | break; |
503 | case lldb::StateType::eStateUnloaded: |
504 | [[fallthrough]]; |
505 | case lldb::StateType::eStateRunning: |
506 | prpsinfo.pr_sname = 'R'; |
507 | prpsinfo.pr_state = 0; |
508 | break; |
509 | default: |
510 | break; |
511 | } |
512 | |
513 | /** |
514 | * pr_flags is left as 0. The values (in linux) are specific |
515 | * to the kernel. We recover them from the proc filesystem |
516 | * but don't put them in ProcessInfo because it would really |
517 | * become very linux specific and the utility here seems pretty |
518 | * dubious |
519 | */ |
520 | |
521 | if (info.EffectiveUserIDIsValid()) |
522 | prpsinfo.pr_uid = info.GetUserID(); |
523 | |
524 | if (info.EffectiveGroupIDIsValid()) |
525 | prpsinfo.pr_gid = info.GetGroupID(); |
526 | |
527 | if (info.ParentProcessIDIsValid()) |
528 | prpsinfo.pr_ppid = info.GetParentProcessID(); |
529 | |
530 | if (info.ProcessGroupIDIsValid()) |
531 | prpsinfo.pr_pgrp = info.GetProcessGroupID(); |
532 | |
533 | if (info.ProcessSessionIDIsValid()) |
534 | prpsinfo.pr_sid = info.GetProcessSessionID(); |
535 | |
536 | constexpr size_t fname_len = std::extent_v<decltype(prpsinfo.pr_fname)>; |
537 | static_assert(fname_len > 0, "This should always be non zero" ); |
538 | const llvm::StringRef fname = info.GetNameAsStringRef(); |
539 | auto fname_begin = fname.begin(); |
540 | std::copy_n(first: fname_begin, n: std::min(a: fname_len, b: fname.size()), |
541 | result: prpsinfo.pr_fname); |
542 | prpsinfo.pr_fname[fname_len - 1] = '\0'; |
543 | auto args = info.GetArguments(); |
544 | auto argentry_iterator = std::begin(cont&: args); |
545 | char *psargs = prpsinfo.pr_psargs; |
546 | char *psargs_end = std::end(arr&: prpsinfo.pr_psargs); |
547 | while (psargs < psargs_end && argentry_iterator != args.end()) { |
548 | llvm::StringRef argentry = argentry_iterator->ref(); |
549 | size_t len = |
550 | std::min<size_t>(a: std::distance(first: psargs, last: psargs_end), b: argentry.size()); |
551 | auto arg_iterator = std::begin(cont&: argentry); |
552 | psargs = std::copy_n(first: arg_iterator, n: len, result: psargs); |
553 | if (psargs != psargs_end) |
554 | *(psargs++) = ' '; |
555 | ++argentry_iterator; |
556 | } |
557 | *(psargs - 1) = '\0'; |
558 | return prpsinfo; |
559 | } |
560 | |