From 59d89be2d67621d818879701dcf8cfcb3291520f Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sat, 2 Mar 2019 02:02:12 -0500 Subject: [PATCH] linux_core_dumper: support NT_SIGINFO for reading crashing address The current core dumper only parses NT_PRSTATUS notes. With signal details, this note only includes three fields: signo, code, and errno. We set exception_code to signo and exception_flag to code. The errno value isn't set by the kernel, so there's no need to save it. However, we never fill in exception_address which means all converted crashes look like they happen at address 0. This implies a NULL jump which is usually not the case, so it's just confusing. The prstatus structure doesn't offer anything directly that tracks this. Starting with linux-3.7, the kernel writes out the full siginfo structure in the NT_SIGINFO note. So lets support that to pull out si_addr which, for a bunch of common signals, is the value we want in exception_address. The size of the siginfo_t structure should be locked to 128 bytes at build time for all architectures, so this should hopefully be stable. Bug: google-breakpad:790 Change-Id: I458bad4787b1a8b73fad8fe068e9f23bec957599 Reviewed-on: https://chromium-review.googlesource.com/c/1497661 Reviewed-by: Mark Mentovai --- .../minidump_writer/linux_core_dumper.cc | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/client/linux/minidump_writer/linux_core_dumper.cc b/src/client/linux/minidump_writer/linux_core_dumper.cc index 9bf2d2ef..9a2f4d6c 100644 --- a/src/client/linux/minidump_writer/linux_core_dumper.cc +++ b/src/client/linux/minidump_writer/linux_core_dumper.cc @@ -165,6 +165,7 @@ bool LinuxCoreDumper::EnumerateThreads() { // ------------------------------------------------------------------- // 1st thread CORE NT_PRSTATUS // process-wide CORE NT_PRPSINFO + // process-wide CORE NT_SIGINFO // process-wide CORE NT_AUXV // 1st thread CORE NT_FPREGSET // 1st thread LINUX NT_PRXFPREG @@ -219,6 +220,28 @@ bool LinuxCoreDumper::EnumerateThreads() { thread_infos_.push_back(info); break; } + case NT_SIGINFO: { + if (description.length() != sizeof(siginfo_t)) { + fprintf(stderr, "Found NT_SIGINFO descriptor of unexpected size\n"); + return false; + } + + const siginfo_t* info = + reinterpret_cast(description.data()); + + // Set crash_address when si_addr is valid for the signal. + switch (info->si_signo) { + case MD_EXCEPTION_CODE_LIN_SIGBUS: + case MD_EXCEPTION_CODE_LIN_SIGFPE: + case MD_EXCEPTION_CODE_LIN_SIGILL: + case MD_EXCEPTION_CODE_LIN_SIGSEGV: + case MD_EXCEPTION_CODE_LIN_SIGSYS: + case MD_EXCEPTION_CODE_LIN_SIGTRAP: + crash_address_ = reinterpret_cast(info->si_addr); + break; + } + break; + } #if defined(__i386) || defined(__x86_64) case NT_FPREGSET: { if (thread_infos_.empty())