mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-28 16:20:01 +02:00
* Updated breakpad to latest version.
This commit is contained in:
@@ -46,26 +46,24 @@
|
||||
#include "client/linux/minidump_writer/minidump_writer.h"
|
||||
#include "client/minidump_file_writer-inl.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#if !defined(__ANDROID__)
|
||||
#include <link.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#if !defined(__ANDROID__)
|
||||
#include <sys/ucontext.h>
|
||||
#include <sys/user.h>
|
||||
#endif
|
||||
#include <sys/utsname.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "client/minidump_file_writer.h"
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
#include "google_breakpad/common/minidump_cpu_amd64.h"
|
||||
#include "google_breakpad/common/minidump_cpu_x86.h"
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include "client/linux/android_link.h"
|
||||
@@ -74,8 +72,11 @@
|
||||
#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_ptrace_dumper.h"
|
||||
#include "client/linux/minidump_writer/minidump_extension_linux.h"
|
||||
#include "client/minidump_file_writer.h"
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
// Minidump defines register structures which are different from the raw
|
||||
@@ -368,32 +369,30 @@ namespace google_breakpad {
|
||||
class MinidumpWriter {
|
||||
public:
|
||||
MinidumpWriter(const char* filename,
|
||||
pid_t crashing_pid,
|
||||
const ExceptionHandler::CrashContext* context,
|
||||
const MappingList& mappings)
|
||||
const MappingList& mappings,
|
||||
LinuxDumper* dumper)
|
||||
: filename_(filename),
|
||||
siginfo_(&context->siginfo),
|
||||
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),
|
||||
#endif
|
||||
crashing_tid_(context->tid),
|
||||
dumper_(crashing_pid),
|
||||
memory_blocks_(dumper_.allocator()),
|
||||
dumper_(dumper),
|
||||
memory_blocks_(dumper_->allocator()),
|
||||
mapping_list_(mappings) {
|
||||
}
|
||||
|
||||
bool Init() {
|
||||
return dumper_.Init() && minidump_writer_.Open(filename_) &&
|
||||
dumper_.ThreadsSuspend();
|
||||
return dumper_->Init() && minidump_writer_.Open(filename_) &&
|
||||
dumper_->ThreadsSuspend();
|
||||
}
|
||||
|
||||
~MinidumpWriter() {
|
||||
minidump_writer_.Close();
|
||||
dumper_.ThreadsResume();
|
||||
dumper_->ThreadsResume();
|
||||
}
|
||||
|
||||
bool Dump() {
|
||||
@@ -403,17 +402,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, crashing_tid_, _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
|
||||
@@ -467,7 +474,7 @@ class MinidumpWriter {
|
||||
dir.CopyIndex(dir_index++, &dirent);
|
||||
|
||||
dirent.stream_type = MD_LINUX_PROC_STATUS;
|
||||
if (!WriteProcFile(&dirent.location, crashing_tid_, "status"))
|
||||
if (!WriteProcFile(&dirent.location, GetCrashThread(), "status"))
|
||||
NullifyDirectoryEntry(&dirent);
|
||||
dir.CopyIndex(dir_index++, &dirent);
|
||||
|
||||
@@ -477,22 +484,22 @@ class MinidumpWriter {
|
||||
dir.CopyIndex(dir_index++, &dirent);
|
||||
|
||||
dirent.stream_type = MD_LINUX_CMD_LINE;
|
||||
if (!WriteProcFile(&dirent.location, crashing_tid_, "cmdline"))
|
||||
if (!WriteProcFile(&dirent.location, GetCrashThread(), "cmdline"))
|
||||
NullifyDirectoryEntry(&dirent);
|
||||
dir.CopyIndex(dir_index++, &dirent);
|
||||
|
||||
dirent.stream_type = MD_LINUX_ENVIRON;
|
||||
if (!WriteProcFile(&dirent.location, crashing_tid_, "environ"))
|
||||
if (!WriteProcFile(&dirent.location, GetCrashThread(), "environ"))
|
||||
NullifyDirectoryEntry(&dirent);
|
||||
dir.CopyIndex(dir_index++, &dirent);
|
||||
|
||||
dirent.stream_type = MD_LINUX_AUXV;
|
||||
if (!WriteProcFile(&dirent.location, crashing_tid_, "auxv"))
|
||||
if (!WriteProcFile(&dirent.location, GetCrashThread(), "auxv"))
|
||||
NullifyDirectoryEntry(&dirent);
|
||||
dir.CopyIndex(dir_index++, &dirent);
|
||||
|
||||
dirent.stream_type = MD_LINUX_MAPS;
|
||||
if (!WriteProcFile(&dirent.location, crashing_tid_, "maps"))
|
||||
if (!WriteProcFile(&dirent.location, GetCrashThread(), "maps"))
|
||||
NullifyDirectoryEntry(&dirent);
|
||||
dir.CopyIndex(dir_index++, &dirent);
|
||||
|
||||
@@ -506,7 +513,7 @@ class MinidumpWriter {
|
||||
// If you add more directory entries, don't forget to update kNumWriters,
|
||||
// above.
|
||||
|
||||
dumper_.ThreadsResume();
|
||||
dumper_->ThreadsResume();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -629,7 +636,7 @@ class MinidumpWriter {
|
||||
|
||||
// Write information about the threads.
|
||||
bool WriteThreadListStream(MDRawDirectory* dirent) {
|
||||
const unsigned num_threads = dumper_.threads().size();
|
||||
const unsigned num_threads = dumper_->threads().size();
|
||||
|
||||
TypedMDRVA<uint32_t> list(&minidump_writer_);
|
||||
if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThread)))
|
||||
@@ -643,21 +650,23 @@ class MinidumpWriter {
|
||||
for (unsigned i = 0; i < num_threads; ++i) {
|
||||
MDRawThread thread;
|
||||
my_memset(&thread, 0, sizeof(thread));
|
||||
thread.thread_id = dumper_.threads()[i];
|
||||
thread.thread_id = dumper_->threads()[i];
|
||||
// We have a different source of information for the crashing thread. If
|
||||
// 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 == crashing_tid_) {
|
||||
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()))
|
||||
if (!dumper_->GetStackInfo(&stack, &stack_len, GetStackPointer()))
|
||||
return false;
|
||||
UntypedMDRVA memory(&minidump_writer_);
|
||||
if (!memory.Allocate(stack_len))
|
||||
return false;
|
||||
uint8_t* stack_copy = (uint8_t*) dumper_.allocator()->Alloc(stack_len);
|
||||
dumper_.CopyFromProcess(stack_copy, thread.thread_id, stack, stack_len);
|
||||
uint8_t* stack_copy = reinterpret_cast<uint8_t*>(Alloc(stack_len));
|
||||
dumper_->CopyFromProcess(stack_copy, thread.thread_id, stack,
|
||||
stack_len);
|
||||
memory.Copy(stack_copy, stack_len);
|
||||
thread.stack.start_of_memory_range = (uintptr_t) (stack);
|
||||
thread.stack.memory = memory.location();
|
||||
@@ -671,8 +680,8 @@ class MinidumpWriter {
|
||||
// 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];
|
||||
for (unsigned j = 0; j < dumper_->mappings().size(); ++j) {
|
||||
const MappingInfo& mapping = *dumper_->mappings()[j];
|
||||
if (ip >= mapping.start_addr &&
|
||||
ip < mapping.start_addr + mapping.size) {
|
||||
ip_is_mapped = true;
|
||||
@@ -695,12 +704,12 @@ class MinidumpWriter {
|
||||
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);
|
||||
reinterpret_cast<uint8_t*>(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);
|
||||
@@ -716,15 +725,14 @@ class MinidumpWriter {
|
||||
crashing_thread_context_ = cpu.location();
|
||||
} else {
|
||||
ThreadInfo info;
|
||||
if (!dumper_.ThreadInfoGet(dumper_.threads()[i], &info))
|
||||
if (!dumper_->GetThreadInfoByIndex(i, &info))
|
||||
return false;
|
||||
UntypedMDRVA memory(&minidump_writer_);
|
||||
if (!memory.Allocate(info.stack_len))
|
||||
return false;
|
||||
uint8_t* stack_copy =
|
||||
(uint8_t*) dumper_.allocator()->Alloc(info.stack_len);
|
||||
dumper_.CopyFromProcess(stack_copy, thread.thread_id, info.stack,
|
||||
info.stack_len);
|
||||
uint8_t* stack_copy = reinterpret_cast<uint8_t*>(Alloc(info.stack_len));
|
||||
dumper_->CopyFromProcess(stack_copy, thread.thread_id, info.stack,
|
||||
info.stack_len);
|
||||
memory.Copy(stack_copy, info.stack_len);
|
||||
thread.stack.start_of_memory_range = (uintptr_t)(info.stack);
|
||||
thread.stack.memory = memory.location();
|
||||
@@ -737,6 +745,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));
|
||||
@@ -777,11 +789,11 @@ class MinidumpWriter {
|
||||
// Because of this, we also include the full, unparsed, /proc/$x/maps file in
|
||||
// another stream in the file.
|
||||
bool WriteMappings(MDRawDirectory* dirent) {
|
||||
const unsigned num_mappings = dumper_.mappings().size();
|
||||
const unsigned num_mappings = dumper_->mappings().size();
|
||||
unsigned num_output_mappings = mapping_list_.size();
|
||||
|
||||
for (unsigned i = 0; i < dumper_.mappings().size(); ++i) {
|
||||
const MappingInfo& mapping = *dumper_.mappings()[i];
|
||||
for (unsigned i = 0; i < dumper_->mappings().size(); ++i) {
|
||||
const MappingInfo& mapping = *dumper_->mappings()[i];
|
||||
if (ShouldIncludeMapping(mapping) && !HaveMappingInfo(mapping))
|
||||
num_output_mappings++;
|
||||
}
|
||||
@@ -797,7 +809,7 @@ class MinidumpWriter {
|
||||
// First write all the mappings from the dumper
|
||||
unsigned int j = 0;
|
||||
for (unsigned i = 0; i < num_mappings; ++i) {
|
||||
const MappingInfo& mapping = *dumper_.mappings()[i];
|
||||
const MappingInfo& mapping = *dumper_->mappings()[i];
|
||||
if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping))
|
||||
continue;
|
||||
|
||||
@@ -859,8 +871,8 @@ class MinidumpWriter {
|
||||
// GUID was provided by caller.
|
||||
memcpy(signature, identifier, sizeof(MDGUID));
|
||||
} else {
|
||||
dumper_.ElfFileIdentifierForMapping(mapping, member,
|
||||
mapping_id, signature);
|
||||
dumper_->ElfFileIdentifierForMapping(mapping, member,
|
||||
mapping_id, signature);
|
||||
}
|
||||
my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux.
|
||||
cv_ptr += sizeof(uint32_t);
|
||||
@@ -905,10 +917,9 @@ class MinidumpWriter {
|
||||
dirent->stream_type = MD_EXCEPTION_STREAM;
|
||||
dirent->location = exc.location();
|
||||
|
||||
exc.get()->thread_id = crashing_tid_;
|
||||
exc.get()->exception_record.exception_code = siginfo_->si_signo;
|
||||
exc.get()->exception_record.exception_address =
|
||||
(uintptr_t) siginfo_->si_addr;
|
||||
exc.get()->thread_id = GetCrashThread();
|
||||
exc.get()->exception_record.exception_code = dumper_->crash_signal();
|
||||
exc.get()->exception_record.exception_address = dumper_->crash_address();
|
||||
exc.get()->thread_context = crashing_thread_context_;
|
||||
|
||||
return true;
|
||||
@@ -945,11 +956,11 @@ class MinidumpWriter {
|
||||
// Count the number of loaded DSOs
|
||||
int dso_count = 0;
|
||||
struct r_debug debug_entry;
|
||||
dumper_.CopyFromProcess(&debug_entry, crashing_tid_, r_debug,
|
||||
sizeof(debug_entry));
|
||||
dumper_->CopyFromProcess(&debug_entry, GetCrashThread(), r_debug,
|
||||
sizeof(debug_entry));
|
||||
for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
|
||||
struct link_map map;
|
||||
dumper_.CopyFromProcess(&map, crashing_tid_, ptr, sizeof(map));
|
||||
dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map));
|
||||
ptr = map.l_next;
|
||||
dso_count++;
|
||||
}
|
||||
@@ -967,12 +978,12 @@ class MinidumpWriter {
|
||||
// Iterate over DSOs and write their information to mini dump
|
||||
for (struct link_map* ptr = debug_entry.r_map; ptr; ) {
|
||||
struct link_map map;
|
||||
dumper_.CopyFromProcess(&map, crashing_tid_, ptr, sizeof(map));
|
||||
dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map));
|
||||
ptr = map.l_next;
|
||||
char filename[257] = { 0 };
|
||||
if (map.l_name) {
|
||||
dumper_.CopyFromProcess(filename, crashing_tid_, map.l_name,
|
||||
sizeof(filename) - 1);
|
||||
dumper_->CopyFromProcess(filename, GetCrashThread(), map.l_name,
|
||||
sizeof(filename) - 1);
|
||||
}
|
||||
MDLocationDescriptor location;
|
||||
if (!minidump_writer_.WriteString(filename, 0, &location))
|
||||
@@ -1001,8 +1012,8 @@ class MinidumpWriter {
|
||||
debug.get()->dynamic = (void*)&_DYNAMIC;
|
||||
|
||||
char *dso_debug_data = new char[dynamic_length];
|
||||
dumper_.CopyFromProcess(dso_debug_data, crashing_tid_, &_DYNAMIC,
|
||||
dynamic_length);
|
||||
dumper_->CopyFromProcess(dso_debug_data, GetCrashThread(), &_DYNAMIC,
|
||||
dynamic_length);
|
||||
debug.CopyIndexAfterObject(0, dso_debug_data, dynamic_length);
|
||||
delete[] dso_debug_data;
|
||||
|
||||
@@ -1011,6 +1022,14 @@ class MinidumpWriter {
|
||||
}
|
||||
|
||||
private:
|
||||
void* Alloc(unsigned bytes) {
|
||||
return dumper_->allocator()->Alloc(bytes);
|
||||
}
|
||||
|
||||
pid_t GetCrashThread() const {
|
||||
return dumper_->crash_thread();
|
||||
}
|
||||
|
||||
#if defined(__i386)
|
||||
uintptr_t GetStackPointer() {
|
||||
return ucontext_->uc_mcontext.gregs[REG_ESP];
|
||||
@@ -1175,16 +1194,15 @@ class MinidumpWriter {
|
||||
// to read as much as we can into a buffer.
|
||||
static const unsigned kBufSize = 1024 - 2*sizeof(void*);
|
||||
struct Buffers {
|
||||
struct Buffers* next;
|
||||
Buffers* next;
|
||||
size_t len;
|
||||
uint8_t data[kBufSize];
|
||||
} *buffers =
|
||||
(struct Buffers*) dumper_.allocator()->Alloc(sizeof(struct Buffers));
|
||||
} *buffers = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
|
||||
buffers->next = NULL;
|
||||
buffers->len = 0;
|
||||
|
||||
size_t total = 0;
|
||||
for (struct Buffers* bufptr = buffers;;) {
|
||||
for (Buffers* bufptr = buffers;;) {
|
||||
ssize_t r;
|
||||
do {
|
||||
r = sys_read(fd, &bufptr->data[bufptr->len], kBufSize - bufptr->len);
|
||||
@@ -1196,8 +1214,7 @@ class MinidumpWriter {
|
||||
total += r;
|
||||
bufptr->len += r;
|
||||
if (bufptr->len == kBufSize) {
|
||||
bufptr->next =
|
||||
(struct Buffers*) dumper_.allocator()->Alloc(sizeof(struct Buffers));
|
||||
bufptr->next = reinterpret_cast<Buffers*>(Alloc(sizeof(Buffers)));
|
||||
bufptr = bufptr->next;
|
||||
bufptr->next = NULL;
|
||||
bufptr->len = 0;
|
||||
@@ -1277,16 +1294,15 @@ 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);
|
||||
}
|
||||
|
||||
const char* const filename_; // output filename
|
||||
const siginfo_t* const siginfo_; // from the signal handler (see sigaction)
|
||||
const struct ucontext* const ucontext_; // also from the signal handler
|
||||
const struct _libc_fpstate* const float_state_; // ditto
|
||||
const pid_t crashing_tid_; // the process which actually crashed
|
||||
LinuxDumper dumper_;
|
||||
LinuxDumper* dumper_;
|
||||
MinidumpFileWriter minidump_writer_;
|
||||
MDLocationDescriptor crashing_thread_context_;
|
||||
// Blocks of memory written to the dump. These are all currently
|
||||
@@ -1310,7 +1326,21 @@ bool WriteMinidump(const char* filename, pid_t crashing_process,
|
||||
return false;
|
||||
const ExceptionHandler::CrashContext* context =
|
||||
reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
|
||||
MinidumpWriter writer(filename, crashing_process, context, mappings);
|
||||
LinuxPtraceDumper dumper(crashing_process);
|
||||
dumper.set_crash_address(
|
||||
reinterpret_cast<uintptr_t>(context->siginfo.si_addr));
|
||||
dumper.set_crash_signal(context->siginfo.si_signo);
|
||||
dumper.set_crash_thread(context->tid);
|
||||
MinidumpWriter writer(filename, context, mappings, &dumper);
|
||||
if (!writer.Init())
|
||||
return false;
|
||||
return writer.Dump();
|
||||
}
|
||||
|
||||
bool WriteMinidump(const char* filename,
|
||||
const MappingList& mappings,
|
||||
LinuxDumper* dumper) {
|
||||
MinidumpWriter writer(filename, NULL, mappings, dumper);
|
||||
if (!writer.Init())
|
||||
return false;
|
||||
return writer.Dump();
|
||||
|
Reference in New Issue
Block a user