aboutsummaryrefslogtreecommitdiff
path: root/src/client/linux/handler
diff options
context:
space:
mode:
authorted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-12-13 22:10:23 +0000
committerted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-12-13 22:10:23 +0000
commitef7262d4775bf6de750bc2a26dbf98368d7ec0c3 (patch)
treea85d6b8c2b66f2da9fdbef3fd0a936dd7f566ac4 /src/client/linux/handler
parentReuse code and fix inconsistent array boundaries. (diff)
downloadbreakpad-ef7262d4775bf6de750bc2a26dbf98368d7ec0c3.tar.xz
allow passing info about known memory mappings to MinidumpWriter and ExceptionHandler
r=thestig at http://breakpad.appspot.com/242001/show git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@741 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/client/linux/handler')
-rw-r--r--src/client/linux/handler/exception_handler.cc26
-rw-r--r--src/client/linux/handler/exception_handler.h18
-rw-r--r--src/client/linux/handler/exception_handler_unittest.cc86
3 files changed, 127 insertions, 3 deletions
diff --git a/src/client/linux/handler/exception_handler.cc b/src/client/linux/handler/exception_handler.cc
index 592c9e5b..4c7436ea 100644
--- a/src/client/linux/handler/exception_handler.cc
+++ b/src/client/linux/handler/exception_handler.cc
@@ -88,10 +88,12 @@
#include <unistd.h>
#include <algorithm>
+#include <utility>
#include <vector>
#include "common/linux/linux_libc_support.h"
#include "common/memory.h"
+#include "client/linux/minidump_writer/linux_dumper.h"
#include "client/linux/minidump_writer/minidump_writer.h"
#include "common/linux/guid_creator.h"
#include "common/linux/eintr_wrapper.h"
@@ -449,8 +451,11 @@ void ExceptionHandler::WaitForContinueSignal() {
// Runs on the cloned process.
bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
size_t context_size) {
- return google_breakpad::WriteMinidump(
- next_minidump_path_c_, crashing_process, context, context_size);
+ return google_breakpad::WriteMinidump(next_minidump_path_c_,
+ crashing_process,
+ context,
+ context_size,
+ mapping_list_);
}
// static
@@ -482,4 +487,21 @@ bool ExceptionHandler::WriteMinidump() {
#endif // !defined(__ARM_EABI__)
}
+void ExceptionHandler::AddMappingInfo(const std::string& name,
+ const u_int8_t identifier[sizeof(MDGUID)],
+ uintptr_t start_address,
+ size_t mapping_size,
+ size_t file_offset) {
+ MappingInfo info;
+ info.start_addr = start_address;
+ info.size = mapping_size;
+ info.offset = file_offset;
+ strncpy(info.name, name.c_str(), std::min(name.size(), sizeof(info)));
+
+ MappingEntry mapping;
+ mapping.first = info;
+ memcpy(mapping.second, identifier, sizeof(MDGUID));
+ mapping_list_.push_back(mapping);
+}
+
} // namespace google_breakpad
diff --git a/src/client/linux/handler/exception_handler.h b/src/client/linux/handler/exception_handler.h
index 82f7fb4c..e75517ea 100644
--- a/src/client/linux/handler/exception_handler.h
+++ b/src/client/linux/handler/exception_handler.h
@@ -30,17 +30,20 @@
#ifndef CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
#define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
-#include <vector>
#include <string>
+#include <vector>
#include <pthread.h>
#include <signal.h>
+#include <stdint.h>
#include <stdio.h>
#if defined(__ANDROID__)
#include "client/linux/android_ucontext.h"
#endif
#include "client/linux/crash_generation/crash_generation_client.h"
+#include "client/linux/minidump_writer/minidump_writer.h"
+#include "google_breakpad/common/minidump_format.h"
#include "processor/scoped_ptr.h"
struct sigaction;
@@ -181,6 +184,15 @@ class ExceptionHandler {
return crash_generation_client_.get() != NULL;
}
+ // Add information about a memory mapping. This can be used if
+ // a custom library loader is used that maps things in a way
+ // that the linux dumper can't handle by reading the maps file.
+ void AddMappingInfo(const std::string& name,
+ const u_int8_t identifier[sizeof(MDGUID)],
+ uintptr_t start_address,
+ size_t mapping_size,
+ size_t file_offset);
+
private:
void Init(const std::string &dump_path,
const int server_fd);
@@ -236,6 +248,10 @@ class ExceptionHandler {
// cloned process after creating it, until we have explicitly enabled
// ptrace. This is used to store the file descriptors for the pipe
int fdes[2];
+
+ // Callers can add extra info about mappings for cases where the
+ // dumper code cannot extract enough information from /proc/<pid>/maps.
+ MappingList mapping_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 988de063..67c05f6b 100644
--- a/src/client/linux/handler/exception_handler_unittest.cc
+++ b/src/client/linux/handler/exception_handler_unittest.cc
@@ -42,6 +42,7 @@
#include "client/linux/handler/exception_handler.h"
#include "client/linux/minidump_writer/minidump_writer.h"
#include "common/linux/eintr_wrapper.h"
+#include "common/linux/file_id.h"
#include "common/linux/linux_libc_support.h"
#include "third_party/lss/linux_syscall_support.h"
#include "google_breakpad/processor/minidump.h"
@@ -54,6 +55,10 @@ using namespace google_breakpad;
#define TEMPDIR "/data/local/tmp"
#endif
+// Length of a formatted GUID string =
+// sizeof(MDGUID) * 2 + 4 (for dashes) + 1 (null terminator)
+const int kGUIDStringSize = 37;
+
static void sigchld_handler(int signo) { }
class ExceptionHandlerTest : public ::testing::Test {
@@ -573,6 +578,87 @@ TEST(ExceptionHandlerTest, InstructionPointerMemoryNullPointer) {
free(filename);
}
+static bool SimpleCallback(const char* dump_path,
+ const char* minidump_id,
+ void* context,
+ bool succeeded) {
+ if (!succeeded)
+ return succeeded;
+
+ string* minidump_file = reinterpret_cast<string*>(context);
+ minidump_file->append(dump_path);
+ minidump_file->append("/");
+ minidump_file->append(minidump_id);
+ minidump_file->append(".dmp");
+ return true;
+}
+
+// Test that anonymous memory maps can be annotated with names and IDs.
+TEST(ExceptionHandlerTest, ModuleInfo) {
+ // These are defined here so the parent can use them to check the
+ // data from the minidump afterwards.
+ const u_int32_t kMemorySize = sysconf(_SC_PAGESIZE);
+ const char* kMemoryName = "a fake module";
+ const u_int8_t kModuleGUID[sizeof(MDGUID)] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
+ };
+ char module_identifier_buffer[kGUIDStringSize];
+ FileID::ConvertIdentifierToString(kModuleGUID,
+ module_identifier_buffer,
+ sizeof(module_identifier_buffer));
+ string module_identifier(module_identifier_buffer);
+ // Strip out dashes
+ size_t pos;
+ while ((pos = module_identifier.find('-')) != string::npos) {
+ module_identifier.erase(pos, 1);
+ }
+ // And append a zero, because module IDs include an "age" field
+ // which is always zero on Linux.
+ module_identifier += "0";
+
+ // Get some memory.
+ char* memory =
+ reinterpret_cast<char*>(mmap(NULL,
+ kMemorySize,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON,
+ -1,
+ 0));
+ const u_int64_t kMemoryAddress = reinterpret_cast<u_int64_t>(memory);
+ ASSERT_TRUE(memory);
+
+ string minidump_filename;
+ ExceptionHandler handler(TEMPDIR, NULL, SimpleCallback,
+ (void*)&minidump_filename, true);
+ // Add info about the anonymous memory mapping.
+ handler.AddMappingInfo(kMemoryName,
+ kModuleGUID,
+ kMemoryAddress,
+ kMemorySize,
+ 0);
+ handler.WriteMinidump();
+
+ // Read the minidump. Load the module list, and ensure that
+ // the mmap'ed |memory| is listed with the given module name
+ // and debug ID.
+ Minidump minidump(minidump_filename);
+ ASSERT_TRUE(minidump.Read());
+
+ MinidumpModuleList* module_list = minidump.GetModuleList();
+ ASSERT_TRUE(module_list);
+ const MinidumpModule* module =
+ module_list->GetModuleForAddress(kMemoryAddress);
+ ASSERT_TRUE(module);
+
+ EXPECT_EQ(kMemoryAddress, module->base_address());
+ EXPECT_EQ(kMemorySize, module->size());
+ EXPECT_EQ(kMemoryName, module->code_file());
+ EXPECT_EQ(module_identifier, module->debug_identifier());
+
+ unlink(minidump_filename.c_str());
+}
+
static const unsigned kControlMsgSize =
CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));