aboutsummaryrefslogtreecommitdiff
path: root/src/client/linux/handler
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/linux/handler')
-rw-r--r--src/client/linux/handler/exception_handler.cc28
-rw-r--r--src/client/linux/handler/exception_handler.h11
-rw-r--r--src/client/linux/handler/exception_handler_unittest.cc81
3 files changed, 117 insertions, 3 deletions
diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc
index 490b6eb9..6f0b8de4 100644
--- a/src/client/linux/handler/exception_handler.cc
+++ b/src/client/linux/handler/exception_handler.cc
@@ -495,13 +495,15 @@ bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
crashing_process,
context,
context_size,
- mapping_list_);
+ mapping_list_,
+ app_memory_list_);
}
return google_breakpad::WriteMinidump(minidump_descriptor_.path(),
crashing_process,
context,
context_size,
- mapping_list_);
+ mapping_list_,
+ app_memory_list_);
}
// static
@@ -562,4 +564,26 @@ void ExceptionHandler::AddMappingInfo(const string& name,
mapping_list_.push_back(mapping);
}
+void ExceptionHandler::RegisterAppMemory(void* ptr, size_t length) {
+ AppMemoryList::iterator iter =
+ std::find(app_memory_list_.begin(), app_memory_list_.end(), ptr);
+ if (iter != app_memory_list_.end()) {
+ // Don't allow registering the same pointer twice.
+ return;
+ }
+
+ AppMemory app_memory;
+ app_memory.ptr = ptr;
+ app_memory.length = length;
+ app_memory_list_.push_back(app_memory);
+}
+
+void ExceptionHandler::UnregisterAppMemory(void* ptr) {
+ AppMemoryList::iterator iter =
+ std::find(app_memory_list_.begin(), app_memory_list_.end(), ptr);
+ if (iter != app_memory_list_.end()) {
+ app_memory_list_.erase(iter);
+ }
+}
+
} // namespace google_breakpad
diff --git a/src/client/linux/handler/exception_handler.h b/src/client/linux/handler/exception_handler.h
index 95817424..68953adf 100644
--- a/src/client/linux/handler/exception_handler.h
+++ b/src/client/linux/handler/exception_handler.h
@@ -193,6 +193,13 @@ class ExceptionHandler {
size_t mapping_size,
size_t file_offset);
+ // Register a block of memory of length bytes starting at address ptr
+ // to be copied to the minidump when a crash happens.
+ void RegisterAppMemory(void* ptr, size_t length);
+
+ // Unregister a block of memory that was registered with RegisterAppMemory.
+ void UnregisterAppMemory(void* ptr);
+
// Force signal handling for the specified signal.
bool SimulateSignalDelivery(int sig);
private:
@@ -238,6 +245,10 @@ class ExceptionHandler {
// Callers can add extra info about mappings for cases where the
// dumper code cannot extract enough information from /proc/<pid>/maps.
MappingList mapping_list_;
+
+ // Callers can request additional memory regions to be included in
+ // the dump.
+ AppMemoryList app_memory_list_;
};
} // namespace google_breakpad
diff --git a/src/client/linux/handler/exception_handler_unittest.cc b/src/client/linux/handler/exception_handler_unittest.cc
index 6de9b8d4..341d2fb0 100644
--- a/src/client/linux/handler/exception_handler_unittest.cc
+++ b/src/client/linux/handler/exception_handler_unittest.cc
@@ -939,6 +939,85 @@ TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithPath) {
ASSERT_TRUE(minidump2.Read());
unlink(minidump_2.path());
- // We expect 2 distinct files.
+ // 2 distinct files should be produced.
ASSERT_STRNE(minidump_1_path.c_str(), minidump_2_path.c_str());
}
+
+// Test that an additional memory region can be added to the minidump.
+TEST(ExceptionHandlerTest, AdditionalMemory) {
+ const u_int32_t kMemorySize = sysconf(_SC_PAGESIZE);
+
+ // 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 (u_int32_t i = 0; i < kMemorySize; ++i) {
+ memory[i] = i % 255;
+ }
+
+ AutoTempDir temp_dir;
+ ExceptionHandler handler(
+ MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
+
+ // Add the memory region to the list of memory to be included.
+ handler.RegisterAppMemory(memory, kMemorySize);
+ handler.WriteMinidump();
+
+ const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor();
+
+ // Read the minidump. Ensure that the memory region is present
+ Minidump minidump(minidump_desc.path());
+ 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;
+}
+
+// Test that a memory region that was previously registered
+// can be unregistered.
+TEST(ExceptionHandlerTest, AdditionalMemoryRemove) {
+ const u_int32_t kMemorySize = sysconf(_SC_PAGESIZE);
+
+ // 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);
+
+ AutoTempDir temp_dir;
+ ExceptionHandler handler(
+ MinidumpDescriptor(temp_dir.path()), NULL, NULL, NULL, true, -1);
+
+ // Add the memory region to the list of memory to be included.
+ handler.RegisterAppMemory(memory, kMemorySize);
+
+ // ...and then remove it
+ handler.UnregisterAppMemory(memory);
+ handler.WriteMinidump();
+
+ const MinidumpDescriptor& minidump_desc = handler.minidump_descriptor();
+
+ // Read the minidump. Ensure that the memory region is not present.
+ Minidump minidump(minidump_desc.path());
+ ASSERT_TRUE(minidump.Read());
+
+ MinidumpMemoryList* dump_memory_list = minidump.GetMemoryList();
+ ASSERT_TRUE(dump_memory_list);
+ const MinidumpMemoryRegion* region =
+ dump_memory_list->GetMemoryRegionForAddress(kMemoryAddress);
+ EXPECT_FALSE(region);
+
+ delete[] memory;
+}