From 2f56276fbfe519913845565f178cfa385da93657 Mon Sep 17 00:00:00 2001 From: "ted.mielczarek" Date: Thu, 19 Jul 2012 22:03:39 +0000 Subject: Allow adding extra memory regions to minidump on linux/windows A=Bill McCloskey R=ted at https://bugzilla.mozilla.org/show_bug.cgi?id=662646 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@989 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/client/windows/handler/exception_handler.cc | 60 +++++++++++++++++-------- src/client/windows/handler/exception_handler.h | 20 +++++++++ 2 files changed, 62 insertions(+), 18 deletions(-) mode change 100644 => 100755 src/client/windows/handler/exception_handler.cc (limited to 'src/client/windows/handler') diff --git a/src/client/windows/handler/exception_handler.cc b/src/client/windows/handler/exception_handler.cc old mode 100644 new mode 100755 index 6e5b724a..9ede97f0 --- a/src/client/windows/handler/exception_handler.cc +++ b/src/client/windows/handler/exception_handler.cc @@ -46,9 +46,7 @@ static const int kExceptionHandlerThreadInitialStackSize = 64 * 1024; // This is passed as the context to the MinidumpWriteDump callback. typedef struct { - ULONG64 memory_base; - ULONG memory_size; - bool finished; + AppMemoryList::const_iterator iter, end; } MinidumpCallbackContext; vector* ExceptionHandler::handler_stack_ = NULL; @@ -220,6 +218,9 @@ void ExceptionHandler::Initialize(const wstring& dump_path, set_dump_path(dump_path); } + // Reserve one element for the instruction memory + app_memory_info_.push_back(AppMemory(0, 0)); + // There is a race condition here. If the first instance has not yet // initialized the critical section, the second (and later) instances may // try to use uninitialized critical section object. The feature of multiple @@ -795,9 +796,6 @@ bool ExceptionHandler::WriteMinidumpWithException( ++user_streams.UserStreamCount; } - MINIDUMP_CALLBACK_INFORMATION callback; - MinidumpCallbackContext context; - MINIDUMP_CALLBACK_INFORMATION* callback_pointer = NULL; // Older versions of DbgHelp.dll don't correctly put the memory around // the faulting instruction pointer into the minidump. This // callback will ensure that it gets included. @@ -822,23 +820,33 @@ bool ExceptionHandler::WriteMinidumpWithException( // pointer, but settle for whatever's available up to the // boundaries of the memory region. const ULONG64 kIPMemorySize = 256; - context.memory_base = + ULONG64 base = (std::max)(reinterpret_cast(info.BaseAddress), instruction_pointer - (kIPMemorySize / 2)); ULONG64 end_of_range = (std::min)(instruction_pointer + (kIPMemorySize / 2), reinterpret_cast(info.BaseAddress) + info.RegionSize); - context.memory_size = - static_cast(end_of_range - context.memory_base); + ULONG size = static_cast(end_of_range - base); - context.finished = false; - callback.CallbackRoutine = MinidumpWriteDumpCallback; - callback.CallbackParam = reinterpret_cast(&context); - callback_pointer = &callback; + AppMemory &elt = app_memory_info_.front(); + elt.ptr = base; + elt.length = size; } } + MinidumpCallbackContext context; + context.iter = app_memory_info_.begin(); + context.end = app_memory_info_.end(); + + // Skip the reserved element if there was no instruction memory + if (context.iter->ptr == 0) + context.iter++; + + MINIDUMP_CALLBACK_INFORMATION callback; + callback.CallbackRoutine = MinidumpWriteDumpCallback; + callback.CallbackParam = reinterpret_cast(&context); + // The explicit comparison to TRUE avoids a warning (C4800). success = (minidump_write_dump_(GetCurrentProcess(), GetCurrentProcessId(), @@ -846,7 +854,7 @@ bool ExceptionHandler::WriteMinidumpWithException( dump_type_, exinfo ? &except_info : NULL, &user_streams, - callback_pointer) == TRUE); + &callback) == TRUE); CloseHandle(dump_file); } @@ -874,13 +882,13 @@ BOOL CALLBACK ExceptionHandler::MinidumpWriteDumpCallback( case MemoryCallback: { MinidumpCallbackContext* callback_context = reinterpret_cast(context); - if (callback_context->finished) + if (callback_context->iter == callback_context->end) return FALSE; // Include the specified memory region. - callback_output->MemoryBase = callback_context->memory_base; - callback_output->MemorySize = callback_context->memory_size; - callback_context->finished = true; + callback_output->MemoryBase = callback_context->iter->ptr; + callback_output->MemorySize = callback_context->iter->length; + callback_context->iter++; return TRUE; } @@ -924,4 +932,20 @@ void ExceptionHandler::UpdateNextID() { next_minidump_path_c_ = next_minidump_path_.c_str(); } +void ExceptionHandler::RegisterAppMemory(void *ptr, size_t length) { + app_memory_info_.push_back(AppMemory(reinterpret_cast(ptr), + static_cast(length))); +} + +void ExceptionHandler::UnregisterAppMemory(void *ptr) { + for (AppMemoryList::iterator iter = app_memory_info_.begin(); + iter != app_memory_info_.end(); + ++iter) { + if (iter->ptr == reinterpret_cast(ptr)) { + app_memory_info_.erase(iter); + return; + } + } +} + } // namespace google_breakpad diff --git a/src/client/windows/handler/exception_handler.h b/src/client/windows/handler/exception_handler.h index 09f5177c..38c2c3ca 100644 --- a/src/client/windows/handler/exception_handler.h +++ b/src/client/windows/handler/exception_handler.h @@ -67,6 +67,7 @@ #include #include +#include #include "client/windows/common/ipc_protocol.h" #include "client/windows/crash_generation/crash_generation_client.h" @@ -78,6 +79,16 @@ namespace google_breakpad { using std::vector; using std::wstring; +// These entries store a list of memory regions that the client wants included +// in the minidump. +struct AppMemory { + AppMemory(ULONG64 ptr, ULONG length) : ptr(ptr), length(length) {} + + ULONG64 ptr; + ULONG length; +}; +typedef std::list AppMemoryList; + class ExceptionHandler { public: // A callback function to run before Breakpad performs any substantial @@ -219,6 +230,11 @@ class ExceptionHandler { // Returns whether out-of-process dump generation is used or not. bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; } + // Calling RegisterAppMemory(p, len) causes len bytes starting + // at address p to be copied to the minidump when a crash happens. + void RegisterAppMemory(void *ptr, size_t length); + void UnregisterAppMemory(void *ptr); + private: friend class AutoExceptionHandler; @@ -404,6 +420,10 @@ class ExceptionHandler { // to not interfere with debuggers. bool handle_debug_exceptions_; + // Callers can request additional memory regions to be included in + // the dump. + AppMemoryList app_memory_info_; + // A stack of ExceptionHandler objects that have installed unhandled // exception filters. This vector is used by HandleException to determine // which ExceptionHandler object to route an exception to. When an -- cgit v1.2.1