Skip to content

Commit ff7bb17

Browse files
authored
[LLDB][ELF Core] Support all the Generic (Negative) SI Codes. (#140150)
Recently, I was on an issue that generated a large number of Coredumps, and every time in both LLDB and GDB the signal was just `SIGSEGV`. This was frustrating because we would expect a `SIGSEGV` to have an address, or ideally even bounds. After some digging I found the `si_code` consistently was -6. With some help from [@cdown](https://github.com/cdown), we found neither LLDB or GDB supports the si_codes sent from [user space](https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/siginfo.h#L185). Excerpted from the sigaction man page. ``` For a regular signal, the following list shows the values which can be placed in si_code for any signal, along with the reason that the signal was generated. ``` For which I added all of the si_codes to every Linux signal. Now for the Coredump that triggered this whole investigation we get the accurate and now very informative summary. <img width="524" alt="image" src="https://github.com/user-attachments/assets/5149f781-ef21-4491-a077-8fac862fbc20" /> Additionally from @labath's suggestion to move this to platform and leverage the existing `getSiginfo()` call on thread, we can now inspect the siginfo struct itself via `thread siginfo`. Giving us another towards GDB parity on elf cores.
1 parent f3b404b commit ff7bb17

File tree

10 files changed

+295
-230
lines changed

10 files changed

+295
-230
lines changed

lldb/include/lldb/Target/Platform.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "lldb/Core/UserSettingsController.h"
2222
#include "lldb/Host/File.h"
2323
#include "lldb/Interpreter/Options.h"
24+
#include "lldb/Target/StopInfo.h"
2425
#include "lldb/Utility/ArchSpec.h"
2526
#include "lldb/Utility/ConstString.h"
2627
#include "lldb/Utility/FileSpec.h"
@@ -960,6 +961,8 @@ class Platform : public PluginInterface {
960961

961962
virtual CompilerType GetSiginfoType(const llvm::Triple &triple);
962963

964+
virtual lldb::StopInfoSP GetStopInfoFromSiginfo(Thread &thread) { return {}; }
965+
963966
virtual Args GetExtraStartupCommands();
964967

965968
typedef std::function<Status(const ModuleSpec &module_spec,

lldb/include/lldb/Target/UnixSignals.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ class UnixSignals {
3636
std::optional<int32_t> code = std::nullopt,
3737
std::optional<lldb::addr_t> addr = std::nullopt,
3838
std::optional<lldb::addr_t> lower = std::nullopt,
39-
std::optional<lldb::addr_t> upper = std::nullopt) const;
39+
std::optional<lldb::addr_t> upper = std::nullopt,
40+
std::optional<uint32_t> pid = std::nullopt,
41+
std::optional<uint32_t> uid = std::nullopt) const;
4042

4143
bool SignalIsValid(int32_t signo) const;
4244

@@ -105,7 +107,7 @@ class UnixSignals {
105107
llvm::StringRef description,
106108
llvm::StringRef alias = llvm::StringRef());
107109

108-
enum SignalCodePrintOption { None, Address, Bounds };
110+
enum SignalCodePrintOption { None, Address, Bounds, Sender };
109111

110112
// Instead of calling this directly, use a ADD_SIGCODE macro to get compile
111113
// time checks when on the native platform.

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

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <sys/utsname.h>
1515
#endif
1616

17+
#include "Plugins/Process/Utility/LinuxSignals.h"
1718
#include "Utility/ARM64_DWARF_Registers.h"
1819
#include "lldb/Core/Debugger.h"
1920
#include "lldb/Core/PluginManager.h"
@@ -480,3 +481,107 @@ CompilerType PlatformLinux::GetSiginfoType(const llvm::Triple &triple) {
480481
ast->CompleteTagDeclarationDefinition(siginfo_type);
481482
return siginfo_type;
482483
}
484+
485+
static std::string GetDescriptionFromSiginfo(lldb::ValueObjectSP siginfo_sp) {
486+
if (!siginfo_sp)
487+
return "";
488+
489+
lldb_private::LinuxSignals linux_signals;
490+
int code = siginfo_sp->GetChildMemberWithName("si_code")->GetValueAsSigned(0);
491+
int signo =
492+
siginfo_sp->GetChildMemberWithName("si_signo")->GetValueAsSigned(-1);
493+
494+
auto sifields = siginfo_sp->GetChildMemberWithName("_sifields");
495+
if (!sifields)
496+
return linux_signals.GetSignalDescription(signo, code);
497+
498+
// declare everything that we can populate later.
499+
std::optional<lldb::addr_t> addr;
500+
std::optional<lldb::addr_t> upper;
501+
std::optional<lldb::addr_t> lower;
502+
std::optional<uint32_t> pid;
503+
std::optional<uint32_t> uid;
504+
505+
// The negative si_codes are special and mean this signal was sent from user
506+
// space not the kernel. These take precedence because they break some of the
507+
// invariants around kernel sent signals. Such as SIGSEGV won't have an
508+
// address.
509+
if (code < 0) {
510+
auto sikill = sifields->GetChildMemberWithName("_kill");
511+
if (sikill) {
512+
auto pid_sp = sikill->GetChildMemberWithName("si_pid");
513+
if (pid_sp)
514+
pid = pid_sp->GetValueAsUnsigned(-1);
515+
auto uid_sp = sikill->GetChildMemberWithName("si_uid");
516+
if (uid_sp)
517+
uid = uid_sp->GetValueAsUnsigned(-1);
518+
}
519+
} else {
520+
521+
switch (signo) {
522+
case SIGILL:
523+
case SIGFPE:
524+
case SIGBUS: {
525+
auto sigfault = sifields->GetChildMemberWithName("_sigfault");
526+
if (!sigfault)
527+
break;
528+
529+
auto addr_sp = sigfault->GetChildMemberWithName("si_addr");
530+
if (addr_sp)
531+
addr = addr_sp->GetValueAsUnsigned(-1);
532+
break;
533+
}
534+
case SIGSEGV: {
535+
auto sigfault = sifields->GetChildMemberWithName("_sigfault");
536+
if (!sigfault)
537+
break;
538+
539+
auto addr_sp = sigfault->GetChildMemberWithName("si_addr");
540+
if (addr_sp)
541+
addr = addr_sp->GetValueAsUnsigned(-1);
542+
543+
auto bounds_sp = sigfault->GetChildMemberWithName("_bounds");
544+
if (!bounds_sp)
545+
break;
546+
547+
auto addr_bnds_sp = bounds_sp->GetChildMemberWithName("_addr_bnd");
548+
if (!addr_bnds_sp)
549+
break;
550+
551+
auto lower_sp = addr_bnds_sp->GetChildMemberWithName("_lower");
552+
if (lower_sp)
553+
lower = lower_sp->GetValueAsUnsigned(-1);
554+
555+
auto upper_sp = addr_bnds_sp->GetChildMemberWithName("_upper");
556+
if (upper_sp)
557+
upper = upper_sp->GetValueAsUnsigned(-1);
558+
559+
break;
560+
}
561+
default:
562+
break;
563+
}
564+
}
565+
566+
return linux_signals.GetSignalDescription(signo, code, addr, lower, upper,
567+
uid, pid);
568+
}
569+
570+
lldb::StopInfoSP PlatformLinux::GetStopInfoFromSiginfo(Thread &thread) {
571+
ValueObjectSP siginfo_sp = thread.GetSiginfoValue();
572+
if (!siginfo_sp)
573+
return {};
574+
auto signo_sp = siginfo_sp->GetChildMemberWithName("si_signo");
575+
auto sicode_sp = siginfo_sp->GetChildMemberWithName("si_code");
576+
if (!signo_sp || !sicode_sp)
577+
return {};
578+
579+
std::string siginfo_description = GetDescriptionFromSiginfo(siginfo_sp);
580+
if (siginfo_description.empty())
581+
return StopInfo::CreateStopReasonWithSignal(
582+
thread, signo_sp->GetValueAsUnsigned(-1));
583+
584+
return StopInfo::CreateStopReasonWithSignal(
585+
thread, signo_sp->GetValueAsUnsigned(-1), siginfo_description.c_str(),
586+
sicode_sp->GetValueAsUnsigned(0));
587+
}

lldb/source/Plugins/Platform/Linux/PlatformLinux.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ class PlatformLinux : public PlatformPOSIX {
6262

6363
CompilerType GetSiginfoType(const llvm::Triple &triple) override;
6464

65+
lldb::StopInfoSP GetStopInfoFromSiginfo(Thread &thread) override;
66+
6567
std::vector<ArchSpec> m_supported_architectures;
6668

6769
private:

0 commit comments

Comments
 (0)