mirror of
https://git.suyu.dev/suyu/breakpad.git
synced 2025-12-31 11:44:48 +01:00
Allow generating minidumps from live process on Linux via ExceptionHandler
Original patch by Chris Jones <jones.chris.g@gmail.com> at https://bugzilla.mozilla.org/show_bug.cgi?id=544936 and https://bugzilla.mozilla.org/show_bug.cgi?id=555309 R=mark at https://breakpad.appspot.com/449003/ git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1043 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
6a5ab68d56
commit
67364c1326
9 changed files with 173 additions and 8 deletions
|
|
@ -529,7 +529,7 @@ bool ExceptionHandler::WriteMinidump() {
|
|||
static_cast<void>(ftruncate(minidump_descriptor_.fd(), 0));
|
||||
}
|
||||
|
||||
// Allow ourselves to be dumped.
|
||||
// Allow this process to be dumped.
|
||||
sys_prctl(PR_SET_DUMPABLE, 1);
|
||||
|
||||
CrashContext context;
|
||||
|
|
@ -543,6 +543,22 @@ bool ExceptionHandler::WriteMinidump() {
|
|||
#endif
|
||||
context.tid = sys_gettid();
|
||||
|
||||
// Add an exception stream to the minidump for better reporting.
|
||||
memset(&context.siginfo, 0, sizeof(context.siginfo));
|
||||
context.siginfo.si_signo = MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED;
|
||||
#if defined(__i386__)
|
||||
context.siginfo.si_addr =
|
||||
reinterpret_cast<void*>(context.context.uc_mcontext.gregs[REG_EIP]);
|
||||
#elif defined(__x86_64__)
|
||||
context.siginfo.si_addr =
|
||||
reinterpret_cast<void*>(context.context.uc_mcontext.gregs[REG_RIP]);
|
||||
#elif defined(__arm__)
|
||||
context.siginfo.si_addr =
|
||||
reinterpret_cast<void*>(context.context.uc_mcontext.arm_pc);
|
||||
#else
|
||||
#error "This code has not been ported to your platform yet."
|
||||
#endif
|
||||
|
||||
return GenerateDump(&context);
|
||||
}
|
||||
|
||||
|
|
@ -586,4 +602,21 @@ void ExceptionHandler::UnregisterAppMemory(void* ptr) {
|
|||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool ExceptionHandler::WriteMinidumpForChild(pid_t child,
|
||||
pid_t child_blamed_thread,
|
||||
const string& dump_path,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context) {
|
||||
// This function is not run in a compromised context.
|
||||
MinidumpDescriptor descriptor(dump_path);
|
||||
descriptor.UpdatePath();
|
||||
if (!google_breakpad::WriteMinidump(descriptor.path(),
|
||||
child,
|
||||
child_blamed_thread))
|
||||
return false;
|
||||
|
||||
return callback ? callback(descriptor, callback_context, true) : true;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
|
|
|||
|
|
@ -167,6 +167,23 @@ class ExceptionHandler {
|
|||
MinidumpCallback callback,
|
||||
void* callback_context);
|
||||
|
||||
// Write a minidump of |child| immediately. This can be used to
|
||||
// capture the execution state of |child| independently of a crash.
|
||||
// Pass a meaningful |child_blamed_thread| to make that thread in
|
||||
// the child process the one from which a crash signature is
|
||||
// extracted.
|
||||
//
|
||||
// WARNING: the return of this function *must* happen before
|
||||
// the code that will eventually reap |child| executes.
|
||||
// Otherwise there's a pernicious race condition in which |child|
|
||||
// exits, is reaped, another process created with its pid, then that
|
||||
// new process dumped.
|
||||
static bool WriteMinidumpForChild(pid_t child,
|
||||
pid_t child_blamed_thread,
|
||||
const string& dump_path,
|
||||
MinidumpCallback callback,
|
||||
void* callback_context);
|
||||
|
||||
// This structure is passed to minidump_writer.h:WriteMinidump via an opaque
|
||||
// blob. It shouldn't be needed in any user code.
|
||||
struct CrashContext {
|
||||
|
|
|
|||
|
|
@ -895,6 +895,25 @@ TEST(ExceptionHandlerTest, ExternalDumper) {
|
|||
unlink(templ.c_str());
|
||||
}
|
||||
|
||||
TEST(ExceptionHandlerTest, WriteMinidumpExceptionStream) {
|
||||
AutoTempDir temp_dir;
|
||||
ExceptionHandler handler(MinidumpDescriptor(temp_dir.path()), NULL, NULL,
|
||||
NULL, false, -1);
|
||||
ASSERT_TRUE(handler.WriteMinidump());
|
||||
|
||||
string minidump_path = handler.minidump_descriptor().path();
|
||||
|
||||
// Read the minidump and check the exception stream.
|
||||
Minidump minidump(minidump_path);
|
||||
ASSERT_TRUE(minidump.Read());
|
||||
MinidumpException* exception = minidump.GetException();
|
||||
ASSERT_TRUE(exception);
|
||||
const MDRawExceptionStream* raw = exception->exception();
|
||||
ASSERT_TRUE(raw);
|
||||
EXPECT_EQ(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED,
|
||||
raw->exception_record.exception_code);
|
||||
}
|
||||
|
||||
TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithFD) {
|
||||
AutoTempDir temp_dir;
|
||||
std::string path;
|
||||
|
|
@ -1021,3 +1040,50 @@ TEST(ExceptionHandlerTest, AdditionalMemoryRemove) {
|
|||
|
||||
delete[] memory;
|
||||
}
|
||||
|
||||
static bool SimpleCallback(const MinidumpDescriptor& descriptor,
|
||||
void* context,
|
||||
bool succeeded) {
|
||||
string* filename = reinterpret_cast<string*>(context);
|
||||
*filename = descriptor.path();
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(ExceptionHandlerTest, WriteMinidumpForChild) {
|
||||
int fds[2];
|
||||
ASSERT_NE(-1, pipe(fds));
|
||||
|
||||
const pid_t child = fork();
|
||||
if (child == 0) {
|
||||
close(fds[1]);
|
||||
char b;
|
||||
HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
|
||||
close(fds[0]);
|
||||
syscall(__NR_exit);
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
AutoTempDir temp_dir;
|
||||
string minidump_filename;
|
||||
ASSERT_TRUE(
|
||||
ExceptionHandler::WriteMinidumpForChild(child, child,
|
||||
temp_dir.path(), SimpleCallback,
|
||||
(void*)&minidump_filename));
|
||||
|
||||
Minidump minidump(minidump_filename);
|
||||
ASSERT_TRUE(minidump.Read());
|
||||
// Check that the crashing thread is the main thread of |child|
|
||||
MinidumpException* exception = minidump.GetException();
|
||||
ASSERT_TRUE(exception);
|
||||
u_int32_t thread_id;
|
||||
ASSERT_TRUE(exception->GetThreadID(&thread_id));
|
||||
EXPECT_EQ(child, thread_id);
|
||||
|
||||
const MDRawExceptionStream* raw = exception->exception();
|
||||
ASSERT_TRUE(raw);
|
||||
EXPECT_EQ(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED,
|
||||
raw->exception_record.exception_code);
|
||||
|
||||
close(fds[1]);
|
||||
unlink(minidump_filename.c_str());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue