mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2024-11-24 04:25:42 +01:00
linux_core_dumper: support setting exception_information
Many signals in Linux support additional metadata on a per-signal basis. We can extract that from NT_SIGINFO and pass it through in the exception_information fields. The current core dumper logic doesn't set exception_information at all, so this is an improvement. Bug: google-breakpad:791 Change-Id: I38b78d6494e9bc682441750d98ac9be5b0656f5a Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/1497662 Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
57f420bf7c
commit
3ee9a0b274
@ -241,6 +241,16 @@ bool LinuxCoreDumper::EnumerateThreads() {
|
|||||||
crash_address_ = reinterpret_cast<uintptr_t>(info->si_addr);
|
crash_address_ = reinterpret_cast<uintptr_t>(info->si_addr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set crash_exception_info for common signals.
|
||||||
|
switch (info->si_signo) {
|
||||||
|
case MD_EXCEPTION_CODE_LIN_SIGKILL:
|
||||||
|
set_crash_exception_info({info->si_pid, info->si_uid});
|
||||||
|
break;
|
||||||
|
case MD_EXCEPTION_CODE_LIN_SIGSYS:
|
||||||
|
set_crash_exception_info({info->si_syscall, info->si_arch});
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#if defined(__i386) || defined(__x86_64)
|
#if defined(__i386) || defined(__x86_64)
|
||||||
|
@ -109,7 +109,7 @@ TEST(LinuxCoreDumperTest, VerifyDumpWithMultipleThreads) {
|
|||||||
EXPECT_TRUE(dumper.ThreadsSuspend());
|
EXPECT_TRUE(dumper.ThreadsSuspend());
|
||||||
EXPECT_TRUE(dumper.ThreadsResume());
|
EXPECT_TRUE(dumper.ThreadsResume());
|
||||||
|
|
||||||
// LinuxCoreDumper cannot determine the crash address and thus it always
|
// Linux does not set the crash address with SIGABRT, so make sure it always
|
||||||
// sets the crash address to 0.
|
// sets the crash address to 0.
|
||||||
EXPECT_EQ(0U, dumper.crash_address());
|
EXPECT_EQ(0U, dumper.crash_address());
|
||||||
EXPECT_EQ(kCrashSignal, dumper.crash_signal());
|
EXPECT_EQ(kCrashSignal, dumper.crash_signal());
|
||||||
@ -126,3 +126,48 @@ TEST(LinuxCoreDumperTest, VerifyDumpWithMultipleThreads) {
|
|||||||
EXPECT_EQ(getpid(), info.ppid);
|
EXPECT_EQ(getpid(), info.ppid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(LinuxCoreDumperTest, VerifyExceptionDetails) {
|
||||||
|
CrashGenerator crash_generator;
|
||||||
|
if (!crash_generator.HasDefaultCorePattern()) {
|
||||||
|
fprintf(stderr, "LinuxCoreDumperTest.VerifyDumpWithMultipleThreads test "
|
||||||
|
"is skipped due to non-default core pattern\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned kNumOfThreads = 2;
|
||||||
|
const unsigned kCrashThread = 1;
|
||||||
|
const int kCrashSignal = SIGSYS;
|
||||||
|
pid_t child_pid;
|
||||||
|
ASSERT_TRUE(crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread,
|
||||||
|
kCrashSignal, &child_pid));
|
||||||
|
|
||||||
|
const string core_file = crash_generator.GetCoreFilePath();
|
||||||
|
const string procfs_path = crash_generator.GetDirectoryOfProcFilesCopy();
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
struct stat st;
|
||||||
|
if (stat(core_file.c_str(), &st) != 0) {
|
||||||
|
fprintf(stderr, "LinuxCoreDumperTest.VerifyExceptionDetails test is "
|
||||||
|
"skipped due to no core file being generated");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LinuxCoreDumper dumper(child_pid, core_file.c_str(), procfs_path.c_str());
|
||||||
|
|
||||||
|
EXPECT_TRUE(dumper.Init());
|
||||||
|
|
||||||
|
EXPECT_TRUE(dumper.IsPostMortem());
|
||||||
|
|
||||||
|
// Check the exception details.
|
||||||
|
EXPECT_NE(0U, dumper.crash_address());
|
||||||
|
EXPECT_EQ(kCrashSignal, dumper.crash_signal());
|
||||||
|
EXPECT_EQ(crash_generator.GetThreadId(kCrashThread),
|
||||||
|
dumper.crash_thread());
|
||||||
|
|
||||||
|
// We check the length, but not the actual fields. We sent SIGSYS ourselves
|
||||||
|
// instead of the kernel, so the extended fields are garbage.
|
||||||
|
const std::vector<uint64_t> info(dumper.crash_exception_info());
|
||||||
|
EXPECT_EQ(2U, info.size());
|
||||||
|
}
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
|
#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
|
||||||
#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
|
#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
#include <link.h>
|
#include <link.h>
|
||||||
@ -47,6 +48,8 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/user.h>
|
#include <sys/user.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "client/linux/dump_writer_common/mapping_info.h"
|
#include "client/linux/dump_writer_common/mapping_info.h"
|
||||||
#include "client/linux/dump_writer_common/thread_info.h"
|
#include "client/linux/dump_writer_common/thread_info.h"
|
||||||
#include "common/linux/file_id.h"
|
#include "common/linux/file_id.h"
|
||||||
@ -184,6 +187,14 @@ class LinuxDumper {
|
|||||||
void set_crash_signal_code(int code) { crash_signal_code_ = code; }
|
void set_crash_signal_code(int code) { crash_signal_code_ = code; }
|
||||||
int crash_signal_code() const { return crash_signal_code_; }
|
int crash_signal_code() const { return crash_signal_code_; }
|
||||||
|
|
||||||
|
void set_crash_exception_info(const std::vector<uint64_t>& exception_info) {
|
||||||
|
assert(exception_info.size() <= MD_EXCEPTION_MAXIMUM_PARAMETERS);
|
||||||
|
crash_exception_info_ = exception_info;
|
||||||
|
}
|
||||||
|
const std::vector<uint64_t>& crash_exception_info() const {
|
||||||
|
return crash_exception_info_;
|
||||||
|
}
|
||||||
|
|
||||||
pid_t crash_thread() const { return crash_thread_; }
|
pid_t crash_thread() const { return crash_thread_; }
|
||||||
void set_crash_thread(pid_t crash_thread) { crash_thread_ = crash_thread; }
|
void set_crash_thread(pid_t crash_thread) { crash_thread_ = crash_thread; }
|
||||||
|
|
||||||
@ -236,6 +247,9 @@ class LinuxDumper {
|
|||||||
// The code associated with |crash_signal_|.
|
// The code associated with |crash_signal_|.
|
||||||
int crash_signal_code_;
|
int crash_signal_code_;
|
||||||
|
|
||||||
|
// The additional fields associated with |crash_signal_|.
|
||||||
|
std::vector<uint64_t> crash_exception_info_;
|
||||||
|
|
||||||
// ID of the crashed thread.
|
// ID of the crashed thread.
|
||||||
pid_t crash_thread_;
|
pid_t crash_thread_;
|
||||||
|
|
||||||
|
@ -713,6 +713,12 @@ class MinidumpWriter {
|
|||||||
stream->exception_record.exception_code = dumper_->crash_signal();
|
stream->exception_record.exception_code = dumper_->crash_signal();
|
||||||
stream->exception_record.exception_flags = dumper_->crash_signal_code();
|
stream->exception_record.exception_flags = dumper_->crash_signal_code();
|
||||||
stream->exception_record.exception_address = dumper_->crash_address();
|
stream->exception_record.exception_address = dumper_->crash_address();
|
||||||
|
const std::vector<uint64_t> crash_exception_info =
|
||||||
|
dumper_->crash_exception_info();
|
||||||
|
stream->exception_record.number_parameters = crash_exception_info.size();
|
||||||
|
memcpy(stream->exception_record.exception_information,
|
||||||
|
crash_exception_info.data(),
|
||||||
|
sizeof(uint64_t) * crash_exception_info.size());
|
||||||
stream->thread_context = crashing_thread_context_;
|
stream->thread_context = crashing_thread_context_;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
Loading…
Reference in New Issue
Block a user