aboutsummaryrefslogtreecommitdiff
path: root/src/client/linux/minidump_writer/minidump_writer.cc
diff options
context:
space:
mode:
authorbenchan@chromium.org <benchan@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-01-19 07:14:51 +0000
committerbenchan@chromium.org <benchan@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-01-19 07:14:51 +0000
commit30566abed8d95b752f31f67fde94c0ae0a1502d2 (patch)
tree90f98f074cebf21102ad8f8717a2e70e9f4438a9 /src/client/linux/minidump_writer/minidump_writer.cc
parentSkip ElfCoreDumpTest.ValidCoreFile test if no core dump is generated. (diff)
downloadbreakpad-30566abed8d95b752f31f67fde94c0ae0a1502d2.tar.xz
Implement core dump to minidump conversion.
This patch is part of a bigger patch that helps merging the breakpad code with the modified version in Chromium OS. Specifically, this patch makes the following changes: 1. Turn the LinuxDumper class into a base class and move ptrace related code into a new derived class, LinuxPtraceDumper. 2. Add a LinuxCoreDumper class, which is derived from LinuxDumper, to extract information from a crashed process via a core dump file instead of ptrace. 3. Add a WriteMinidumpFromCore function to src/client/linux/minidump_writer/minidump_writer.h, which uses LinuxCoreDumper to extract information from a core dump file. 4. Add a core2md utility, which simply wraps WriteMinidumpFromCore, for converting a core dump to a minidump. BUG=455 TEST=Tested the following: 1. Build on 32-bit and 64-bit Linux with gcc 4.4.3 and gcc 4.6. 2. Build on Mac OS X 10.6.8 with gcc 4.2 and clang 3.0 (with latest gmock). 3. All unit tests pass. 4. Run Chromium OS tests to test core2md. Review URL: http://breakpad.appspot.com/343001 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@905 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/client/linux/minidump_writer/minidump_writer.cc')
-rw-r--r--src/client/linux/minidump_writer/minidump_writer.cc60
1 files changed, 43 insertions, 17 deletions
diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc
index 9a3d37fe..c6feabdd 100644
--- a/src/client/linux/minidump_writer/minidump_writer.cc
+++ b/src/client/linux/minidump_writer/minidump_writer.cc
@@ -74,6 +74,8 @@
#include "client/linux/handler/exception_handler.h"
#include "client/linux/minidump_writer/line_reader.h"
#include "client/linux/minidump_writer/linux_dumper.h"
+#include "client/linux/minidump_writer/linux_core_dumper.h"
+#include "client/linux/minidump_writer/linux_ptrace_dumper.h"
#include "client/linux/minidump_writer/minidump_extension_linux.h"
#include "common/linux/linux_libc_support.h"
#include "third_party/lss/linux_syscall_support.h"
@@ -372,9 +374,9 @@ class MinidumpWriter {
const MappingList& mappings,
LinuxDumper* dumper)
: filename_(filename),
- ucontext_(&context->context),
+ ucontext_(context ? &context->context : NULL),
#if !defined(__ARM_EABI__)
- float_state_(&context->float_state),
+ float_state_(context ? &context->float_state : NULL),
#else
// TODO: fix this after fixing ExceptionHandler
float_state_(NULL),
@@ -401,18 +403,25 @@ class MinidumpWriter {
struct r_debug* r_debug = NULL;
uint32_t dynamic_length = 0;
#if !defined(__ANDROID__)
- // The Android NDK is missing structure definitions for most of this.
- // For now, it's simpler just to skip it.
- for (int i = 0;;) {
- ElfW(Dyn) dyn;
- dynamic_length += sizeof(dyn);
- dumper_->CopyFromProcess(&dyn, GetCrashThread(), _DYNAMIC+i++,
- sizeof(dyn));
- if (dyn.d_tag == DT_DEBUG) {
- r_debug = (struct r_debug*)dyn.d_un.d_ptr;
- continue;
- } else if (dyn.d_tag == DT_NULL) {
- break;
+ // This code assumes the crashing process is the same as this process and
+ // may hang or take a long time to complete if not so.
+ // Thus, we skip this code for a post-mortem based dump.
+ if (!dumper_->IsPostMortem()) {
+ // The Android NDK is missing structure definitions for most of this.
+ // For now, it's simpler just to skip it.
+ for (int i = 0;;) {
+ ElfW(Dyn) dyn;
+ dynamic_length += sizeof(dyn);
+ // NOTE: Use of _DYNAMIC assumes this is the same process as the
+ // crashing process. This loop will go forever if it's out of bounds.
+ dumper_->CopyFromProcess(&dyn, GetCrashThread(), _DYNAMIC+i++,
+ sizeof(dyn));
+ if (dyn.d_tag == DT_DEBUG) {
+ r_debug = (struct r_debug*)dyn.d_un.d_ptr;
+ continue;
+ } else if (dyn.d_tag == DT_NULL) {
+ break;
+ }
}
}
#endif
@@ -647,7 +656,8 @@ class MinidumpWriter {
// we used the actual state of the thread we would find it running in the
// signal handler with the alternative stack, which would be deeply
// unhelpful.
- if ((pid_t)thread.thread_id == GetCrashThread()) {
+ if (static_cast<pid_t>(thread.thread_id) == GetCrashThread() &&
+ !dumper_->IsPostMortem()) {
const void* stack;
size_t stack_len;
if (!dumper_->GetStackInfo(&stack, &stack_len, GetStackPointer()))
@@ -736,6 +746,10 @@ class MinidumpWriter {
CPUFillFromThreadInfo(cpu.get(), info);
PopSeccompStackFrame(cpu.get(), thread, stack_copy);
thread.thread_context = cpu.location();
+ if (dumper_->threads()[i] == GetCrashThread()) {
+ assert(dumper_->IsPostMortem());
+ crashing_thread_context_ = cpu.location();
+ }
}
list.CopyIndexAfterObject(i, &thread, sizeof(thread));
@@ -1281,7 +1295,8 @@ class MinidumpWriter {
bool WriteProcFile(MDLocationDescriptor* result, pid_t pid,
const char* filename) {
char buf[NAME_MAX];
- dumper_->BuildProcPath(buf, pid, filename);
+ if (!dumper_->BuildProcPath(buf, pid, filename))
+ return false;
return WriteFile(result, buf);
}
@@ -1312,7 +1327,7 @@ bool WriteMinidump(const char* filename, pid_t crashing_process,
return false;
const ExceptionHandler::CrashContext* context =
reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
- LinuxDumper dumper(crashing_process);
+ LinuxPtraceDumper dumper(crashing_process);
dumper.set_crash_address(
reinterpret_cast<uintptr_t>(context->siginfo.si_addr));
dumper.set_crash_signal(context->siginfo.si_signo);
@@ -1323,4 +1338,15 @@ bool WriteMinidump(const char* filename, pid_t crashing_process,
return writer.Dump();
}
+bool WriteMinidumpFromCore(const char* filename,
+ const char* core_path,
+ const char* procfs_override) {
+ MappingList mappings;
+ LinuxCoreDumper dumper(0, core_path, procfs_override);
+ MinidumpWriter writer(filename, NULL, mappings, &dumper);
+ if (!writer.Init())
+ return false;
+ return writer.Dump();
+}
+
} // namespace google_breakpad