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 --- .../linux/minidump_writer/minidump_writer.cc | 144 +++++++++++++++------ 1 file changed, 101 insertions(+), 43 deletions(-) (limited to 'src/client/linux/minidump_writer/minidump_writer.cc') diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc index 405ec4e8..3eb90953 100644 --- a/src/client/linux/minidump_writer/minidump_writer.cc +++ b/src/client/linux/minidump_writer/minidump_writer.cc @@ -368,7 +368,8 @@ class MinidumpWriter { public: MinidumpWriter(const char* filename, pid_t crashing_pid, - const ExceptionHandler::CrashContext* context) + const ExceptionHandler::CrashContext* context, + const MappingList& mappings) : filename_(filename), siginfo_(&context->siginfo), ucontext_(&context->context), @@ -380,7 +381,8 @@ class MinidumpWriter { #endif crashing_tid_(context->tid), dumper_(crashing_pid), - memory_blocks_(dumper_.allocator()) { + memory_blocks_(dumper_.allocator()), + mapping_list_(mappings) { } bool Init() { @@ -752,17 +754,34 @@ class MinidumpWriter { return true; } + // If there is caller-provided information about this mapping + // in the mapping_list_ list, return true. Otherwise, return false. + bool HaveMappingInfo(const MappingInfo& mapping) { + for (MappingList::const_iterator iter = mapping_list_.begin(); + iter != mapping_list_.end(); + ++iter) { + // Ignore any mappings that are wholly contained within + // mappings in the mapping_info_ list. + if (mapping.start_addr >= iter->first.start_addr && + (mapping.start_addr + mapping.size) <= + (iter->first.start_addr + iter->first.size)) { + return true; + } + } + return false; + } + // Write information about the mappings in effect. Because we are using the // minidump format, the information about the mappings is pretty limited. // Because of this, we also include the full, unparsed, /proc/$x/maps file in // another stream in the file. bool WriteMappings(MDRawDirectory* dirent) { const unsigned num_mappings = dumper_.mappings().size(); - unsigned num_output_mappings = 0; + unsigned num_output_mappings = mapping_list_.size(); for (unsigned i = 0; i < dumper_.mappings().size(); ++i) { const MappingInfo& mapping = *dumper_.mappings()[i]; - if (ShouldIncludeMapping(mapping)) + if (ShouldIncludeMapping(mapping) && !HaveMappingInfo(mapping)) num_output_mappings++; } @@ -774,56 +793,86 @@ class MinidumpWriter { dirent->location = list.location(); *list.get() = num_output_mappings; - for (unsigned i = 0, j = 0; i < num_mappings; ++i) { + // First write all the mappings from the dumper + unsigned int j = 0; + for (unsigned i = 0; i < num_mappings; ++i) { const MappingInfo& mapping = *dumper_.mappings()[i]; - if (!ShouldIncludeMapping(mapping)) + if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping)) continue; MDRawModule mod; - my_memset(&mod, 0, MD_MODULE_SIZE); - mod.base_of_image = mapping.start_addr; - mod.size_of_image = mapping.size; - const size_t filepath_len = my_strlen(mapping.name); - - // Figure out file name from path - const char* filename_ptr = mapping.name + filepath_len - 1; - while (filename_ptr >= mapping.name) { - if (*filename_ptr == '/') - break; - filename_ptr--; - } - filename_ptr++; - const size_t filename_len = mapping.name + filepath_len - filename_ptr; - - uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX]; - uint8_t* cv_ptr = cv_buf; - UntypedMDRVA cv(&minidump_writer_); - if (!cv.Allocate(MDCVInfoPDB70_minsize + filename_len + 1)) + if (!FillRawModule(mapping, i, mod, NULL)) return false; + list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); + } + // Next write all the mappings provided by the caller + for (MappingList::const_iterator iter = mapping_list_.begin(); + iter != mapping_list_.end(); + ++iter) { + MDRawModule mod; + if (!FillRawModule(iter->first, -1, mod, iter->second)) + return false; + list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); + } - const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE; - memcpy(cv_ptr, &cv_signature, sizeof(cv_signature)); - cv_ptr += sizeof(cv_signature); - uint8_t* signature = cv_ptr; - cv_ptr += sizeof(MDGUID); - dumper_.ElfFileIdentifierForMapping(i, signature); - my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux. - cv_ptr += sizeof(uint32_t); + return true; + } - // Write pdb_file_name - memcpy(cv_ptr, filename_ptr, filename_len + 1); - cv.Copy(cv_buf, MDCVInfoPDB70_minsize + filename_len + 1); + // Fill the MDRawModule |mod| with information about the provided + // |mapping|. If |identifier| is non-NULL, use it instead of calculating + // a file ID from the mapping. |mapping_id| can be -1 if this mapping + // is not from the LinuxDumper. + bool FillRawModule(const MappingInfo& mapping, + unsigned int mapping_id, + MDRawModule& mod, + const u_int8_t* identifier) { + my_memset(&mod, 0, MD_MODULE_SIZE); + + mod.base_of_image = mapping.start_addr; + mod.size_of_image = mapping.size; + const size_t filepath_len = my_strlen(mapping.name); + + // Figure out file name from path + const char* filename_ptr = mapping.name + filepath_len - 1; + while (filename_ptr >= mapping.name) { + if (*filename_ptr == '/') + break; + filename_ptr--; + } + filename_ptr++; - mod.cv_record = cv.location(); + const size_t filename_len = mapping.name + filepath_len - filename_ptr; - MDLocationDescriptor ld; - if (!minidump_writer_.WriteString(mapping.name, filepath_len, &ld)) - return false; - mod.module_name_rva = ld.rva; + uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX]; + uint8_t* cv_ptr = cv_buf; + UntypedMDRVA cv(&minidump_writer_); + if (!cv.Allocate(MDCVInfoPDB70_minsize + filename_len + 1)) + return false; - list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); + const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE; + memcpy(cv_ptr, &cv_signature, sizeof(cv_signature)); + cv_ptr += sizeof(cv_signature); + uint8_t* signature = cv_ptr; + cv_ptr += sizeof(MDGUID); + if (identifier) { + // GUID was provided by caller. + memcpy(signature, identifier, sizeof(MDGUID)); + } else { + dumper_.ElfFileIdentifierForMapping(mapping, mapping_id, signature); } + my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux. + cv_ptr += sizeof(uint32_t); + // Write pdb_file_name + memcpy(cv_ptr, filename_ptr, filename_len + 1); + cv.Copy(cv_buf, MDCVInfoPDB70_minsize + filename_len + 1); + + mod.cv_record = cv.location(); + + MDLocationDescriptor ld; + if (!minidump_writer_.WriteString(mapping.name, filepath_len, &ld)) + return false; + mod.module_name_rva = ld.rva; return true; } @@ -1233,15 +1282,24 @@ class MinidumpWriter { // written while writing the thread list stream, but saved here // so a memory list stream can be written afterwards. wasteful_vector memory_blocks_; + // Additional information about some mappings provided by the caller. + const MappingList& mapping_list_; }; bool WriteMinidump(const char* filename, pid_t crashing_process, const void* blob, size_t blob_size) { + MappingList m; + return WriteMinidump(filename, crashing_process, blob, blob_size, m); +} + +bool WriteMinidump(const char* filename, pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings) { if (blob_size != sizeof(ExceptionHandler::CrashContext)) return false; const ExceptionHandler::CrashContext* context = reinterpret_cast(blob); - MinidumpWriter writer(filename, crashing_process, context); + MinidumpWriter writer(filename, crashing_process, context, mappings); if (!writer.Init()) return false; return writer.Dump(); -- cgit v1.2.1