aboutsummaryrefslogtreecommitdiff
path: root/src/client/linux/minidump_writer/minidump_writer.cc
diff options
context:
space:
mode:
authorted.mielczarek@gmail.com <ted.mielczarek@gmail.com@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-09-19 12:55:16 +0000
committerted.mielczarek@gmail.com <ted.mielczarek@gmail.com@4c0a9323-5329-0410-9bdc-e9ce6186880e>2012-09-19 12:55:16 +0000
commit0e91d185cac51ed1b2c9163afca998660ebda08e (patch)
treea154d70d8918dd48c9ec161c94fff037d05ea113 /src/client/linux/minidump_writer/minidump_writer.cc
parentAllow generating minidumps from live process on Linux via ExceptionHandler (diff)
downloadbreakpad-0e91d185cac51ed1b2c9163afca998660ebda08e.tar.xz
Minidumps never contain MD_LINUX_DSO_DEBUG info when breakpad is in a shared library
A=Mike Hommey <mh@glandium.org> R=ted at http://breakpad.appspot.com/422002/ git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1044 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.cc100
1 files changed, 56 insertions, 44 deletions
diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc
index 02055640..add2d3f5 100644
--- a/src/client/linux/minidump_writer/minidump_writer.cc
+++ b/src/client/linux/minidump_writer/minidump_writer.cc
@@ -423,40 +423,9 @@ class MinidumpWriter {
}
bool Dump() {
- // The dynamic linker makes information available that helps gdb find all
- // DSOs loaded into the program. If we can access this information, we dump
- // it to a MD_LINUX_DSO_DEBUG stream.
- struct r_debug* r_debug = NULL;
- uint32_t dynamic_length = 0;
-#if !defined(__ANDROID__)
- // 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
-
// A minidump file contains a number of tagged streams. This is the number
// of stream which we write.
- unsigned kNumWriters = 12;
- if (r_debug)
- ++kNumWriters;
+ unsigned kNumWriters = 13;
TypedMDRVA<MDRawHeader> header(&minidump_writer_);
TypedMDRVA<MDRawDirectory> dir(&minidump_writer_);
@@ -533,12 +502,10 @@ class MinidumpWriter {
NullifyDirectoryEntry(&dirent);
dir.CopyIndex(dir_index++, &dirent);
- if (r_debug) {
- dirent.stream_type = MD_LINUX_DSO_DEBUG;
- if (!WriteDSODebugStream(&dirent, r_debug, dynamic_length))
- NullifyDirectoryEntry(&dirent);
- dir.CopyIndex(dir_index++, &dirent);
- }
+ dirent.stream_type = MD_LINUX_DSO_DEBUG;
+ if (!WriteDSODebugStream(&dirent))
+ NullifyDirectoryEntry(&dirent);
+ dir.CopyIndex(dir_index++, &dirent);
// If you add more directory entries, don't forget to update kNumWriters,
// above.
@@ -1000,13 +967,58 @@ class MinidumpWriter {
return true;
}
- bool WriteDSODebugStream(MDRawDirectory* dirent, struct r_debug* r_debug,
- uint32_t dynamic_length) {
+ bool WriteDSODebugStream(MDRawDirectory* dirent) {
#if defined(__ANDROID__)
return false;
#else
- // The caller provided us with a pointer to "struct r_debug". We can
- // look up the "r_map" field to get a linked list of all loaded DSOs.
+ ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr) *>(dumper_->auxv()[AT_PHDR]);
+ char* base;
+ int phnum = dumper_->auxv()[AT_PHNUM];
+ if (!phnum || !phdr)
+ return false;
+
+ // Assume the program base is at the beginning of the same page as the PHDR
+ base = reinterpret_cast<char *>(reinterpret_cast<uintptr_t>(phdr) & ~0xfff);
+
+ // Search for the program PT_DYNAMIC segment
+ ElfW(Addr) dyn_addr = 0;
+ for (; phnum >= 0; phnum--, phdr++) {
+ ElfW(Phdr) ph;
+ dumper_->CopyFromProcess(&ph, GetCrashThread(), phdr, sizeof(ph));
+ // Adjust base address with the virtual address of the PT_LOAD segment
+ // corresponding to offset 0
+ if (ph.p_type == PT_LOAD && ph.p_offset == 0) {
+ base -= ph.p_vaddr;
+ }
+ if (ph.p_type == PT_DYNAMIC) {
+ dyn_addr = ph.p_vaddr;
+ }
+ }
+ if (!dyn_addr)
+ return false;
+
+ ElfW(Dyn) *dynamic = reinterpret_cast<ElfW(Dyn) *>(dyn_addr + base);
+
+ // The dynamic linker makes information available that helps gdb find all
+ // DSOs loaded into the program. If this information is indeed available,
+ // dump it to a MD_LINUX_DSO_DEBUG stream.
+ struct r_debug* r_debug = NULL;
+ uint32_t dynamic_length = 0;
+
+ 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 = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr);
+ continue;
+ } else if (dyn.d_tag == DT_NULL) {
+ break;
+ }
+ }
+
+ // The "r_map" field of that r_debug struct contains a linked list of all
+ // loaded DSOs.
// Our list of DSOs potentially is different from the ones in the crashing
// process. So, we have to be careful to never dereference pointers
// directly. Instead, we use CopyFromProcess() everywhere.
@@ -1069,10 +1081,10 @@ class MinidumpWriter {
debug.get()->dso_count = dso_count;
debug.get()->brk = (void*)debug_entry.r_brk;
debug.get()->ldbase = (void*)debug_entry.r_ldbase;
- debug.get()->dynamic = (void*)&_DYNAMIC;
+ debug.get()->dynamic = dynamic;
char *dso_debug_data = new char[dynamic_length];
- dumper_->CopyFromProcess(dso_debug_data, GetCrashThread(), &_DYNAMIC,
+ dumper_->CopyFromProcess(dso_debug_data, GetCrashThread(), dynamic,
dynamic_length);
debug.CopyIndexAfterObject(0, dso_debug_data, dynamic_length);
delete[] dso_debug_data;