aboutsummaryrefslogtreecommitdiff
path: root/src/client/linux/minidump_writer
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/linux/minidump_writer')
-rw-r--r--src/client/linux/minidump_writer/minidump_writer.cc93
1 files changed, 91 insertions, 2 deletions
diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc
index 260ce934..6b55ade0 100644
--- a/src/client/linux/minidump_writer/minidump_writer.cc
+++ b/src/client/linux/minidump_writer/minidump_writer.cc
@@ -46,6 +46,8 @@
#include "client/linux/minidump_writer/minidump_writer.h"
#include "client/minidump_file_writer-inl.h"
+#include <algorithm>
+
#include <errno.h>
#include <fcntl.h>
#include <link.h>
@@ -367,7 +369,8 @@ class MinidumpWriter {
float_state_(NULL),
#endif
crashing_tid_(context->tid),
- dumper_(crashing_pid) {
+ dumper_(crashing_pid),
+ memory_blocks_(dumper_.allocator()) {
}
bool Init() {
@@ -400,7 +403,9 @@ class MinidumpWriter {
// A minidump file contains a number of tagged streams. This is the number
// of stream which we write.
- const unsigned kNumWriters = 11 + !!r_debug;
+ unsigned kNumWriters = 12;
+ if (r_debug)
+ ++kNumWriters;
TypedMDRVA<MDRawHeader> header(&minidump_writer_);
TypedMDRVA<MDRawDirectory> dir(&minidump_writer_);
@@ -427,6 +432,10 @@ class MinidumpWriter {
return false;
dir.CopyIndex(dir_index++, &dirent);
+ if (!WriteMemoryListStream(&dirent))
+ return false;
+ dir.CopyIndex(dir_index++, &dirent);
+
if (!WriteExceptionStream(&dirent))
return false;
dir.CopyIndex(dir_index++, &dirent);
@@ -635,6 +644,50 @@ class MinidumpWriter {
memory.Copy(stack_copy, stack_len);
thread.stack.start_of_memory_range = (uintptr_t) (stack);
thread.stack.memory = memory.location();
+ memory_blocks_.push_back(thread.stack);
+
+ // Copy 256 bytes around crashing instruction pointer to minidump.
+ const size_t kIPMemorySize = 256;
+ u_int64_t ip = GetInstructionPointer();
+ // Bound it to the upper and lower bounds of the memory map
+ // it's contained within. If it's not in mapped memory,
+ // don't bother trying to write it.
+ bool ip_is_mapped = false;
+ MDMemoryDescriptor ip_memory_d;
+ for (unsigned i = 0; i < dumper_.mappings().size(); ++i) {
+ const MappingInfo& mapping = *dumper_.mappings()[i];
+ if (ip >= mapping.start_addr &&
+ ip < mapping.start_addr + mapping.size) {
+ ip_is_mapped = true;
+ // Try to get 128 bytes before and after the IP, but
+ // settle for whatever's available.
+ ip_memory_d.start_of_memory_range =
+ std::min(mapping.start_addr,
+ uintptr_t(ip - (kIPMemorySize / 2)));
+ ip_memory_d.memory.data_size =
+ std::min(ptrdiff_t(kIPMemorySize),
+ ptrdiff_t(mapping.start_addr + mapping.size
+ - ip_memory_d.start_of_memory_range));
+ break;
+ }
+ }
+
+ if (ip_is_mapped) {
+ UntypedMDRVA ip_memory(&minidump_writer_);
+ if (!ip_memory.Allocate(ip_memory_d.memory.data_size))
+ return false;
+ uint8_t* memory_copy =
+ (uint8_t*) dumper_.allocator()->Alloc(ip_memory_d.memory.data_size);
+ dumper_.CopyFromProcess(
+ memory_copy,
+ thread.thread_id,
+ reinterpret_cast<void*>(ip_memory_d.start_of_memory_range),
+ ip_memory_d.memory.data_size);
+ ip_memory.Copy(memory_copy, ip_memory_d.memory.data_size);
+ ip_memory_d.memory = ip_memory.location();
+ memory_blocks_.push_back(ip_memory_d);
+ }
+
TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
if (!cpu.Allocate())
return false;
@@ -657,6 +710,8 @@ class MinidumpWriter {
memory.Copy(stack_copy, info.stack_len);
thread.stack.start_of_memory_range = (uintptr_t)(info.stack);
thread.stack.memory = memory.location();
+ memory_blocks_.push_back(thread.stack);
+
TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
if (!cpu.Allocate())
return false;
@@ -757,6 +812,24 @@ class MinidumpWriter {
return true;
}
+ bool WriteMemoryListStream(MDRawDirectory* dirent) {
+ TypedMDRVA<uint32_t> list(&minidump_writer_);
+ if (!list.AllocateObjectAndArray(memory_blocks_.size(),
+ sizeof(MDMemoryDescriptor)))
+ return false;
+
+ dirent->stream_type = MD_MEMORY_LIST_STREAM;
+ dirent->location = list.location();
+
+ *list.get() = memory_blocks_.size();
+
+ for (size_t i = 0; i < memory_blocks_.size(); ++i) {
+ list.CopyIndexAfterObject(i, &memory_blocks_[i],
+ sizeof(MDMemoryDescriptor));
+ }
+ return true;
+ }
+
bool WriteExceptionStream(MDRawDirectory* dirent) {
TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_);
if (!exc.Allocate())
@@ -872,14 +945,26 @@ class MinidumpWriter {
uintptr_t GetStackPointer() {
return ucontext_->uc_mcontext.gregs[REG_ESP];
}
+
+ uintptr_t GetInstructionPointer() {
+ return ucontext_->uc_mcontext.gregs[REG_EIP];
+ }
#elif defined(__x86_64)
uintptr_t GetStackPointer() {
return ucontext_->uc_mcontext.gregs[REG_RSP];
}
+
+ uintptr_t GetInstructionPointer() {
+ return ucontext_->uc_mcontext.gregs[REG_RIP];
+ }
#elif defined(__ARM_EABI__)
uintptr_t GetStackPointer() {
return ucontext_->uc_mcontext.arm_sp;
}
+
+ uintptr_t GetInstructionPointer() {
+ return ucontext_->uc_mcontext.arm_ip;
+ }
#else
#error "This code has not been ported to your platform yet."
#endif
@@ -1129,6 +1214,10 @@ popline:
LinuxDumper dumper_;
MinidumpFileWriter minidump_writer_;
MDLocationDescriptor crashing_thread_context_;
+ // Blocks of memory written to the dump. These are all currently
+ // written while writing the thread list stream, but saved here
+ // so a memory list stream can be written afterwards.
+ wasteful_vector<MDMemoryDescriptor> memory_blocks_;
};
bool WriteMinidump(const char* filename, pid_t crashing_process,