1//===-- PlatformLinux.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 "PlatformLinux.h"
10#include "lldb/Host/Config.h"
11
12#include <cstdio>
13#if LLDB_ENABLE_POSIX
14#include <sys/utsname.h>
15#endif
16
17#include "Plugins/Process/Utility/LinuxSignals.h"
18#include "Utility/ARM64_DWARF_Registers.h"
19#include "lldb/Core/Debugger.h"
20#include "lldb/Core/PluginManager.h"
21#include "lldb/Host/HostInfo.h"
22#include "lldb/Symbol/UnwindPlan.h"
23#include "lldb/Target/Process.h"
24#include "lldb/Target/Target.h"
25#include "lldb/Utility/FileSpec.h"
26#include "lldb/Utility/LLDBLog.h"
27#include "lldb/Utility/Log.h"
28#include "lldb/Utility/State.h"
29#include "lldb/Utility/Status.h"
30#include "lldb/Utility/StreamString.h"
31
32// Define these constants from Linux mman.h for use when targeting remote linux
33// systems even when host has different values.
34#define MAP_PRIVATE 2
35#define MAP_ANON 0x20
36
37// For other platforms that use platform linux
38#ifndef SIGILL
39#define SIGILL 4
40#endif
41#ifndef SIGBUS
42#define SIGBUS 7
43#endif
44#ifndef SIGFPE
45#define SIGFPE 8
46#endif
47#ifndef SIGSEGV
48#define SIGSEGV 11
49#endif
50
51using namespace lldb;
52using namespace lldb_private;
53using namespace lldb_private::platform_linux;
54
55LLDB_PLUGIN_DEFINE(PlatformLinux)
56
57static uint32_t g_initialize_count = 0;
58
59
60PlatformSP PlatformLinux::CreateInstance(bool force, const ArchSpec *arch) {
61 Log *log = GetLog(mask: LLDBLog::Platform);
62 LLDB_LOG(log, "force = {0}, arch=({1}, {2})", force,
63 arch ? arch->GetArchitectureName() : "<null>",
64 arch ? arch->GetTriple().getTriple() : "<null>");
65
66 bool create = force;
67 if (!create && arch && arch->IsValid()) {
68 const llvm::Triple &triple = arch->GetTriple();
69 switch (triple.getOS()) {
70 case llvm::Triple::Linux:
71 create = true;
72 break;
73
74#if defined(__linux__)
75 // Only accept "unknown" for the OS if the host is linux and it "unknown"
76 // wasn't specified (it was just returned because it was NOT specified)
77 case llvm::Triple::OSType::UnknownOS:
78 create = !arch->TripleOSWasSpecified();
79 break;
80#endif
81 default:
82 break;
83 }
84 }
85
86 LLDB_LOG(log, "create = {0}", create);
87 if (create) {
88 return PlatformSP(new PlatformLinux(false));
89 }
90 return PlatformSP();
91}
92
93llvm::StringRef PlatformLinux::GetPluginDescriptionStatic(bool is_host) {
94 if (is_host)
95 return "Local Linux user platform plug-in.";
96 return "Remote Linux user platform plug-in.";
97}
98
99void PlatformLinux::Initialize() {
100 PlatformPOSIX::Initialize();
101
102 if (g_initialize_count++ == 0) {
103#if defined(__linux__) && !defined(__ANDROID__)
104 PlatformSP default_platform_sp(new PlatformLinux(true));
105 default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
106 Platform::SetHostPlatform(default_platform_sp);
107#endif
108 PluginManager::RegisterPlugin(
109 name: PlatformLinux::GetPluginNameStatic(is_host: false),
110 description: PlatformLinux::GetPluginDescriptionStatic(is_host: false),
111 create_callback: PlatformLinux::CreateInstance, debugger_init_callback: nullptr);
112 }
113}
114
115void PlatformLinux::Terminate() {
116 if (g_initialize_count > 0) {
117 if (--g_initialize_count == 0) {
118 PluginManager::UnregisterPlugin(create_callback: PlatformLinux::CreateInstance);
119 }
120 }
121
122 PlatformPOSIX::Terminate();
123}
124
125/// Default Constructor
126PlatformLinux::PlatformLinux(bool is_host)
127 : PlatformPOSIX(is_host) // This is the local host platform
128{
129 if (is_host) {
130 ArchSpec hostArch = HostInfo::GetArchitecture(arch_kind: HostInfo::eArchKindDefault);
131 m_supported_architectures.push_back(x: hostArch);
132 if (hostArch.GetTriple().isArch64Bit()) {
133 m_supported_architectures.push_back(
134 x: HostInfo::GetArchitecture(arch_kind: HostInfo::eArchKind32));
135 }
136 } else {
137 m_supported_architectures = CreateArchList(
138 archs: {llvm::Triple::x86_64, llvm::Triple::x86, llvm::Triple::arm,
139 llvm::Triple::aarch64, llvm::Triple::mips64, llvm::Triple::mips64,
140 llvm::Triple::hexagon, llvm::Triple::mips, llvm::Triple::mips64el,
141 llvm::Triple::mipsel, llvm::Triple::msp430, llvm::Triple::systemz,
142 llvm::Triple::loongarch64, llvm::Triple::ppc64le,
143 llvm::Triple::riscv64},
144 os: llvm::Triple::Linux);
145 }
146}
147
148std::vector<ArchSpec>
149PlatformLinux::GetSupportedArchitectures(const ArchSpec &process_host_arch) {
150 if (m_remote_platform_sp)
151 return m_remote_platform_sp->GetSupportedArchitectures(process_host_arch);
152 return m_supported_architectures;
153}
154
155void PlatformLinux::GetStatus(Stream &strm) {
156 Platform::GetStatus(strm);
157
158#if LLDB_ENABLE_POSIX
159 // Display local kernel information only when we are running in host mode.
160 // Otherwise, we would end up printing non-Linux information (when running on
161 // Mac OS for example).
162 if (IsHost()) {
163 struct utsname un;
164
165 if (uname(name: &un))
166 return;
167
168 strm.Printf(format: " Kernel: %s\n", un.sysname);
169 strm.Printf(format: " Release: %s\n", un.release);
170 strm.Printf(format: " Version: %s\n", un.version);
171 }
172#endif
173}
174
175uint32_t
176PlatformLinux::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) {
177 uint32_t resume_count = 0;
178
179 // Always resume past the initial stop when we use eLaunchFlagDebug
180 if (launch_info.GetFlags().Test(bit: eLaunchFlagDebug)) {
181 // Resume past the stop for the final exec into the true inferior.
182 ++resume_count;
183 }
184
185 // If we're not launching a shell, we're done.
186 const FileSpec &shell = launch_info.GetShell();
187 if (!shell)
188 return resume_count;
189
190 std::string shell_string = shell.GetPath();
191 // We're in a shell, so for sure we have to resume past the shell exec.
192 ++resume_count;
193
194 // Figure out what shell we're planning on using.
195 const char *shell_name = strrchr(s: shell_string.c_str(), c: '/');
196 if (shell_name == nullptr)
197 shell_name = shell_string.c_str();
198 else
199 shell_name++;
200
201 if (strcmp(s1: shell_name, s2: "csh") == 0 || strcmp(s1: shell_name, s2: "tcsh") == 0 ||
202 strcmp(s1: shell_name, s2: "zsh") == 0 || strcmp(s1: shell_name, s2: "sh") == 0) {
203 // These shells seem to re-exec themselves. Add another resume.
204 ++resume_count;
205 }
206
207 return resume_count;
208}
209
210bool PlatformLinux::CanDebugProcess() {
211 if (IsHost()) {
212 return true;
213 } else {
214 // If we're connected, we can debug.
215 return IsConnected();
216 }
217}
218
219void PlatformLinux::CalculateTrapHandlerSymbolNames() {
220 m_trap_handlers.push_back(x: ConstString("_sigtramp"));
221 m_trap_handlers.push_back(x: ConstString("__kernel_rt_sigreturn"));
222 m_trap_handlers.push_back(x: ConstString("__restore_rt"));
223}
224
225static lldb::UnwindPlanSP GetAArch64TrapHandlerUnwindPlan(ConstString name) {
226 UnwindPlanSP unwind_plan_sp;
227 if (name != "__kernel_rt_sigreturn")
228 return unwind_plan_sp;
229
230 UnwindPlan::Row row;
231
232 // In the signal trampoline frame, sp points to an rt_sigframe[1], which is:
233 // - 128-byte siginfo struct
234 // - ucontext struct:
235 // - 8-byte long (uc_flags)
236 // - 8-byte pointer (uc_link)
237 // - 24-byte stack_t
238 // - 128-byte signal set
239 // - 8 bytes of padding because sigcontext has 16-byte alignment
240 // - sigcontext/mcontext_t
241 // [1]
242 // https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/signal.c
243 int32_t offset = 128 + 8 + 8 + 24 + 128 + 8;
244 // Then sigcontext[2] is:
245 // - 8 byte fault address
246 // - 31 8 byte registers
247 // - 8 byte sp
248 // - 8 byte pc
249 // [2]
250 // https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/sigcontext.h
251
252 // Skip fault address
253 offset += 8;
254 row.GetCFAValue().SetIsRegisterPlusOffset(reg_num: arm64_dwarf::sp, offset);
255
256 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x0, offset: 0 * 8, can_replace: false);
257 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x1, offset: 1 * 8, can_replace: false);
258 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x2, offset: 2 * 8, can_replace: false);
259 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x3, offset: 3 * 8, can_replace: false);
260 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x4, offset: 4 * 8, can_replace: false);
261 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x5, offset: 5 * 8, can_replace: false);
262 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x6, offset: 6 * 8, can_replace: false);
263 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x7, offset: 7 * 8, can_replace: false);
264 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x8, offset: 8 * 8, can_replace: false);
265 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x9, offset: 9 * 8, can_replace: false);
266 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x10, offset: 10 * 8, can_replace: false);
267 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x11, offset: 11 * 8, can_replace: false);
268 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x12, offset: 12 * 8, can_replace: false);
269 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x13, offset: 13 * 8, can_replace: false);
270 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x14, offset: 14 * 8, can_replace: false);
271 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x15, offset: 15 * 8, can_replace: false);
272 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x16, offset: 16 * 8, can_replace: false);
273 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x17, offset: 17 * 8, can_replace: false);
274 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x18, offset: 18 * 8, can_replace: false);
275 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x19, offset: 19 * 8, can_replace: false);
276 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x20, offset: 20 * 8, can_replace: false);
277 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x21, offset: 21 * 8, can_replace: false);
278 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x22, offset: 22 * 8, can_replace: false);
279 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x23, offset: 23 * 8, can_replace: false);
280 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x24, offset: 24 * 8, can_replace: false);
281 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x25, offset: 25 * 8, can_replace: false);
282 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x26, offset: 26 * 8, can_replace: false);
283 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x27, offset: 27 * 8, can_replace: false);
284 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x28, offset: 28 * 8, can_replace: false);
285 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::fp, offset: 29 * 8, can_replace: false);
286 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::x30, offset: 30 * 8, can_replace: false);
287 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::sp, offset: 31 * 8, can_replace: false);
288 row.SetRegisterLocationToAtCFAPlusOffset(reg_num: arm64_dwarf::pc, offset: 32 * 8, can_replace: false);
289
290 // The sigcontext may also contain floating point and SVE registers.
291 // However this would require a dynamic unwind plan so they are not included
292 // here.
293
294 unwind_plan_sp = std::make_shared<UnwindPlan>(args: eRegisterKindDWARF);
295 unwind_plan_sp->AppendRow(row: std::move(row));
296 unwind_plan_sp->SetSourceName("AArch64 Linux sigcontext");
297 unwind_plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
298 // Because sp is the same throughout the function
299 unwind_plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
300 unwind_plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolYes);
301
302 return unwind_plan_sp;
303}
304
305lldb::UnwindPlanSP
306PlatformLinux::GetTrapHandlerUnwindPlan(const llvm::Triple &triple,
307 ConstString name) {
308 if (triple.isAArch64())
309 return GetAArch64TrapHandlerUnwindPlan(name);
310
311 return {};
312}
313
314MmapArgList PlatformLinux::GetMmapArgumentList(const ArchSpec &arch,
315 addr_t addr, addr_t length,
316 unsigned prot, unsigned flags,
317 addr_t fd, addr_t offset) {
318 uint64_t flags_platform = 0;
319 uint64_t map_anon = arch.IsMIPS() ? 0x800 : MAP_ANON;
320
321 if (flags & eMmapFlagsPrivate)
322 flags_platform |= MAP_PRIVATE;
323 if (flags & eMmapFlagsAnon)
324 flags_platform |= map_anon;
325
326 MmapArgList args({addr, length, prot, flags_platform, fd, offset});
327 return args;
328}
329
330CompilerType PlatformLinux::GetSiginfoType(const llvm::Triple &triple) {
331 {
332 std::lock_guard<std::mutex> guard(m_mutex);
333 if (!m_type_system)
334 m_type_system = std::make_shared<TypeSystemClang>(args: "siginfo", args: triple);
335 }
336 TypeSystemClang *ast = m_type_system.get();
337
338 bool si_errno_then_code = true;
339
340 switch (triple.getArch()) {
341 case llvm::Triple::mips:
342 case llvm::Triple::mipsel:
343 case llvm::Triple::mips64:
344 case llvm::Triple::mips64el:
345 // mips has si_code and si_errno swapped
346 si_errno_then_code = false;
347 break;
348 default:
349 break;
350 }
351
352 // generic types
353 CompilerType int_type = ast->GetBasicType(type: eBasicTypeInt);
354 CompilerType uint_type = ast->GetBasicType(type: eBasicTypeUnsignedInt);
355 CompilerType short_type = ast->GetBasicType(type: eBasicTypeShort);
356 CompilerType long_type = ast->GetBasicType(type: eBasicTypeLong);
357 CompilerType voidp_type = ast->GetBasicType(type: eBasicTypeVoid).GetPointerType();
358
359 // platform-specific types
360 CompilerType &pid_type = int_type;
361 CompilerType &uid_type = uint_type;
362 CompilerType &clock_type = long_type;
363 CompilerType &band_type = long_type;
364
365 CompilerType sigval_type = ast->CreateRecordType(
366 decl_ctx: nullptr, owning_module: OptionalClangModuleID(), access_type: lldb::eAccessPublic, name: "__lldb_sigval_t",
367 kind: llvm::to_underlying(E: clang::TagTypeKind::Union), language: lldb::eLanguageTypeC);
368 ast->StartTagDeclarationDefinition(type: sigval_type);
369 ast->AddFieldToRecordType(type: sigval_type, name: "sival_int", field_type: int_type,
370 access: lldb::eAccessPublic, bitfield_bit_size: 0);
371 ast->AddFieldToRecordType(type: sigval_type, name: "sival_ptr", field_type: voidp_type,
372 access: lldb::eAccessPublic, bitfield_bit_size: 0);
373 ast->CompleteTagDeclarationDefinition(type: sigval_type);
374
375 CompilerType sigfault_bounds_type = ast->CreateRecordType(
376 decl_ctx: nullptr, owning_module: OptionalClangModuleID(), access_type: lldb::eAccessPublic, name: "",
377 kind: llvm::to_underlying(E: clang::TagTypeKind::Union), language: lldb::eLanguageTypeC);
378 ast->StartTagDeclarationDefinition(type: sigfault_bounds_type);
379 ast->AddFieldToRecordType(
380 type: sigfault_bounds_type, name: "_addr_bnd",
381 field_type: ast->CreateStructForIdentifier(type_name: llvm::StringRef(),
382 type_fields: {
383 {"_lower", voidp_type},
384 {"_upper", voidp_type},
385 }),
386 access: lldb::eAccessPublic, bitfield_bit_size: 0);
387 ast->AddFieldToRecordType(type: sigfault_bounds_type, name: "_pkey", field_type: uint_type,
388 access: lldb::eAccessPublic, bitfield_bit_size: 0);
389 ast->CompleteTagDeclarationDefinition(type: sigfault_bounds_type);
390
391 // siginfo_t
392 CompilerType siginfo_type = ast->CreateRecordType(
393 decl_ctx: nullptr, owning_module: OptionalClangModuleID(), access_type: lldb::eAccessPublic, name: "__lldb_siginfo_t",
394 kind: llvm::to_underlying(E: clang::TagTypeKind::Struct), language: lldb::eLanguageTypeC);
395 ast->StartTagDeclarationDefinition(type: siginfo_type);
396 ast->AddFieldToRecordType(type: siginfo_type, name: "si_signo", field_type: int_type,
397 access: lldb::eAccessPublic, bitfield_bit_size: 0);
398
399 if (si_errno_then_code) {
400 ast->AddFieldToRecordType(type: siginfo_type, name: "si_errno", field_type: int_type,
401 access: lldb::eAccessPublic, bitfield_bit_size: 0);
402 ast->AddFieldToRecordType(type: siginfo_type, name: "si_code", field_type: int_type,
403 access: lldb::eAccessPublic, bitfield_bit_size: 0);
404 } else {
405 ast->AddFieldToRecordType(type: siginfo_type, name: "si_code", field_type: int_type,
406 access: lldb::eAccessPublic, bitfield_bit_size: 0);
407 ast->AddFieldToRecordType(type: siginfo_type, name: "si_errno", field_type: int_type,
408 access: lldb::eAccessPublic, bitfield_bit_size: 0);
409 }
410
411 // the structure is padded on 64-bit arches to fix alignment
412 if (triple.isArch64Bit())
413 ast->AddFieldToRecordType(type: siginfo_type, name: "__pad0", field_type: int_type,
414 access: lldb::eAccessPublic, bitfield_bit_size: 0);
415
416 // union used to hold the signal data
417 CompilerType union_type = ast->CreateRecordType(
418 decl_ctx: nullptr, owning_module: OptionalClangModuleID(), access_type: lldb::eAccessPublic, name: "",
419 kind: llvm::to_underlying(E: clang::TagTypeKind::Union), language: lldb::eLanguageTypeC);
420 ast->StartTagDeclarationDefinition(type: union_type);
421
422 ast->AddFieldToRecordType(
423 type: union_type, name: "_kill",
424 field_type: ast->CreateStructForIdentifier(type_name: llvm::StringRef(),
425 type_fields: {
426 {"si_pid", pid_type},
427 {"si_uid", uid_type},
428 }),
429 access: lldb::eAccessPublic, bitfield_bit_size: 0);
430
431 ast->AddFieldToRecordType(
432 type: union_type, name: "_timer",
433 field_type: ast->CreateStructForIdentifier(type_name: llvm::StringRef(),
434 type_fields: {
435 {"si_tid", int_type},
436 {"si_overrun", int_type},
437 {"si_sigval", sigval_type},
438 }),
439 access: lldb::eAccessPublic, bitfield_bit_size: 0);
440
441 ast->AddFieldToRecordType(
442 type: union_type, name: "_rt",
443 field_type: ast->CreateStructForIdentifier(type_name: llvm::StringRef(),
444 type_fields: {
445 {"si_pid", pid_type},
446 {"si_uid", uid_type},
447 {"si_sigval", sigval_type},
448 }),
449 access: lldb::eAccessPublic, bitfield_bit_size: 0);
450
451 ast->AddFieldToRecordType(
452 type: union_type, name: "_sigchld",
453 field_type: ast->CreateStructForIdentifier(type_name: llvm::StringRef(),
454 type_fields: {
455 {"si_pid", pid_type},
456 {"si_uid", uid_type},
457 {"si_status", int_type},
458 {"si_utime", clock_type},
459 {"si_stime", clock_type},
460 }),
461 access: lldb::eAccessPublic, bitfield_bit_size: 0);
462
463 ast->AddFieldToRecordType(
464 type: union_type, name: "_sigfault",
465 field_type: ast->CreateStructForIdentifier(type_name: llvm::StringRef(),
466 type_fields: {
467 {"si_addr", voidp_type},
468 {"si_addr_lsb", short_type},
469 {"_bounds", sigfault_bounds_type},
470 }),
471 access: lldb::eAccessPublic, bitfield_bit_size: 0);
472
473 ast->AddFieldToRecordType(
474 type: union_type, name: "_sigpoll",
475 field_type: ast->CreateStructForIdentifier(type_name: llvm::StringRef(),
476 type_fields: {
477 {"si_band", band_type},
478 {"si_fd", int_type},
479 }),
480 access: lldb::eAccessPublic, bitfield_bit_size: 0);
481
482 // NB: SIGSYS is not present on ia64 but we don't seem to support that
483 ast->AddFieldToRecordType(
484 type: union_type, name: "_sigsys",
485 field_type: ast->CreateStructForIdentifier(type_name: llvm::StringRef(),
486 type_fields: {
487 {"_call_addr", voidp_type},
488 {"_syscall", int_type},
489 {"_arch", uint_type},
490 }),
491 access: lldb::eAccessPublic, bitfield_bit_size: 0);
492
493 ast->CompleteTagDeclarationDefinition(type: union_type);
494 ast->AddFieldToRecordType(type: siginfo_type, name: "_sifields", field_type: union_type,
495 access: lldb::eAccessPublic, bitfield_bit_size: 0);
496
497 ast->CompleteTagDeclarationDefinition(type: siginfo_type);
498 return siginfo_type;
499}
500
501static std::string GetDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) {
502 if (!siginfo_sp)
503 return "";
504
505 lldb_private::LinuxSignals linux_signals;
506 int code = siginfo_sp->GetChildMemberWithName(name: "si_code")->GetValueAsSigned(fail_value: 0);
507 int signo =
508 siginfo_sp->GetChildMemberWithName(name: "si_signo")->GetValueAsSigned(fail_value: -1);
509
510 auto sifields = siginfo_sp->GetChildMemberWithName(name: "_sifields");
511 if (!sifields)
512 return linux_signals.GetSignalDescription(signo, code);
513
514 // declare everything that we can populate later.
515 std::optional<lldb::addr_t> addr;
516 std::optional<lldb::addr_t> upper;
517 std::optional<lldb::addr_t> lower;
518 std::optional<uint32_t> pid;
519 std::optional<uint32_t> uid;
520
521 // The negative si_codes are special and mean this signal was sent from user
522 // space not the kernel. These take precedence because they break some of the
523 // invariants around kernel sent signals. Such as SIGSEGV won't have an
524 // address.
525 if (code < 0) {
526 auto sikill = sifields->GetChildMemberWithName(name: "_kill");
527 if (sikill) {
528 auto pid_sp = sikill->GetChildMemberWithName(name: "si_pid");
529 if (pid_sp)
530 pid = pid_sp->GetValueAsUnsigned(fail_value: -1);
531 auto uid_sp = sikill->GetChildMemberWithName(name: "si_uid");
532 if (uid_sp)
533 uid = uid_sp->GetValueAsUnsigned(fail_value: -1);
534 }
535 } else {
536
537 switch (signo) {
538 case SIGILL:
539 case SIGFPE:
540 case SIGBUS: {
541 auto sigfault = sifields->GetChildMemberWithName(name: "_sigfault");
542 if (!sigfault)
543 break;
544
545 auto addr_sp = sigfault->GetChildMemberWithName(name: "si_addr");
546 if (addr_sp)
547 addr = addr_sp->GetValueAsUnsigned(fail_value: -1);
548 break;
549 }
550 case SIGSEGV: {
551 auto sigfault = sifields->GetChildMemberWithName(name: "_sigfault");
552 if (!sigfault)
553 break;
554
555 auto addr_sp = sigfault->GetChildMemberWithName(name: "si_addr");
556 if (addr_sp)
557 addr = addr_sp->GetValueAsUnsigned(fail_value: -1);
558
559 auto bounds_sp = sigfault->GetChildMemberWithName(name: "_bounds");
560 if (!bounds_sp)
561 break;
562
563 auto addr_bnds_sp = bounds_sp->GetChildMemberWithName(name: "_addr_bnd");
564 if (!addr_bnds_sp)
565 break;
566
567 auto lower_sp = addr_bnds_sp->GetChildMemberWithName(name: "_lower");
568 if (lower_sp)
569 lower = lower_sp->GetValueAsUnsigned(fail_value: -1);
570
571 auto upper_sp = addr_bnds_sp->GetChildMemberWithName(name: "_upper");
572 if (upper_sp)
573 upper = upper_sp->GetValueAsUnsigned(fail_value: -1);
574
575 break;
576 }
577 default:
578 break;
579 }
580 }
581
582 return linux_signals.GetSignalDescription(signo, code, addr, lower, upper,
583 pid, uid);
584}
585
586lldb::StopInfoSP PlatformLinux::GetStopInfoFromSiginfo(Thread &thread) {
587 ValueObjectSP siginfo_sp = thread.GetSiginfoValue();
588 if (!siginfo_sp)
589 return {};
590 auto signo_sp = siginfo_sp->GetChildMemberWithName(name: "si_signo");
591 auto sicode_sp = siginfo_sp->GetChildMemberWithName(name: "si_code");
592 if (!signo_sp || !sicode_sp)
593 return {};
594
595 std::string siginfo_description = GetDescriptionFromSiginfo(siginfo_sp);
596 if (siginfo_description.empty())
597 return StopInfo::CreateStopReasonWithSignal(
598 thread, signo: signo_sp->GetValueAsUnsigned(fail_value: -1));
599
600 return StopInfo::CreateStopReasonWithSignal(
601 thread, signo: signo_sp->GetValueAsUnsigned(fail_value: -1), description: siginfo_description.c_str(),
602 code: sicode_sp->GetValueAsUnsigned(fail_value: 0));
603}
604

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp