From ef7262d4775bf6de750bc2a26dbf98368d7ec0c3 Mon Sep 17 00:00:00 2001 From: "ted.mielczarek" Date: Mon, 13 Dec 2010 22:10:23 +0000 Subject: 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 --- src/client/linux/handler/exception_handler.cc | 26 ++++++- src/client/linux/handler/exception_handler.h | 18 ++++- .../linux/handler/exception_handler_unittest.cc | 86 ++++++++++++++++++++++ 3 files changed, 127 insertions(+), 3 deletions(-) (limited to 'src/client/linux/handler') 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 #include +#include #include #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 #include +#include #include #include +#include #include #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//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(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(mmap(NULL, + kMemorySize, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, + -1, + 0)); + const u_int64_t kMemoryAddress = reinterpret_cast(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)); -- cgit v1.2.1