aboutsummaryrefslogtreecommitdiff
path: root/src/client/windows
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/windows')
-rwxr-xr-x[-rw-r--r--]src/client/windows/handler/exception_handler.cc60
-rw-r--r--src/client/windows/handler/exception_handler.h20
-rwxr-xr-x[-rw-r--r--]src/client/windows/unittests/exception_handler_test.cc46
3 files changed, 108 insertions, 18 deletions
diff --git a/src/client/windows/handler/exception_handler.cc b/src/client/windows/handler/exception_handler.cc
index 6e5b724a..9ede97f0 100644..100755
--- 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*>* 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<ULONG64>(info.BaseAddress),
instruction_pointer - (kIPMemorySize / 2));
ULONG64 end_of_range =
(std::min)(instruction_pointer + (kIPMemorySize / 2),
reinterpret_cast<ULONG64>(info.BaseAddress)
+ info.RegionSize);
- context.memory_size =
- static_cast<ULONG>(end_of_range - context.memory_base);
+ ULONG size = static_cast<ULONG>(end_of_range - base);
- context.finished = false;
- callback.CallbackRoutine = MinidumpWriteDumpCallback;
- callback.CallbackParam = reinterpret_cast<void*>(&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<void*>(&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<MinidumpCallbackContext*>(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<ULONG64>(ptr),
+ static_cast<ULONG>(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<ULONG64>(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 <string>
#include <vector>
+#include <list>
#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<AppMemory> 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
diff --git a/src/client/windows/unittests/exception_handler_test.cc b/src/client/windows/unittests/exception_handler_test.cc
index 74d9a9be..08960015 100644..100755
--- a/src/client/windows/unittests/exception_handler_test.cc
+++ b/src/client/windows/unittests/exception_handler_test.cc
@@ -374,4 +374,50 @@ TEST_F(ExceptionHandlerTest, WriteMinidumpTest) {
//TODO(ted): more comprehensive tests...
}
+TEST_F(ExceptionHandlerTest, AdditionalMemory) {
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ const u_int32_t kMemorySize = si.dwPageSize;
+ // Get some heap memory.
+ u_int8_t* memory = new u_int8_t[kMemorySize];
+ const uintptr_t kMemoryAddress = reinterpret_cast<uintptr_t>(memory);
+ ASSERT_TRUE(memory);
+ // Stick some data into the memory so the contents can be verified.
+ for (unsigned int i = 0; i < kMemorySize; ++i) {
+ memory[i] = i % 255;
+ }
+
+ ExceptionHandler handler(temp_path_,
+ NULL,
+ DumpCallback,
+ NULL,
+ ExceptionHandler::HANDLER_ALL);
+ // Add the memory region to the list of memory to be included.
+ handler.RegisterAppMemory(memory, kMemorySize);
+ ASSERT_TRUE(handler.WriteMinidump());
+ ASSERT_FALSE(dump_file.empty());
+
+ string minidump_filename;
+ ASSERT_TRUE(WindowsStringUtils::safe_wcstombs(dump_file,
+ &minidump_filename));
+
+ // Read the minidump. Ensure that the memory region is present
+ Minidump minidump(minidump_filename);
+ ASSERT_TRUE(minidump.Read());
+
+ MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList();
+ ASSERT_TRUE(dump_memory_list);
+ const MinidumpMemoryRegion* region =
+ dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress);
+ ASSERT_TRUE(region);
+
+ EXPECT_EQ(kMemoryAddress, region->GetBase());
+ EXPECT_EQ(kMemorySize, region->GetSize());
+
+ // Verify memory contents.
+ EXPECT_EQ(0, memcmp(region->GetMemory(), memory, kMemorySize));
+
+ delete[] memory;
+}
+
} // namespace