diff options
author | primiano@chromium.org <primiano@chromium.org> | 2014-10-17 10:58:23 +0000 |
---|---|---|
committer | primiano@chromium.org <primiano@chromium.org> | 2014-10-17 10:58:23 +0000 |
commit | 719546275aa9a9c1a2811341b178ac689a9d85d5 (patch) | |
tree | 15691157498b8de5eb3f0c42e52b3e892c4b81da /src/client/linux/minidump_writer | |
parent | The process uptime computation when the Windows out-of-process Crash Generation (diff) | |
download | breakpad-719546275aa9a9c1a2811341b178ac689a9d85d5.tar.xz |
Refactor .so name detection logic in minidump/linux_dumper.
This is a refactoring of the logic which determines the
module name and path for a given MappingInfo in minidump_writer.cc.
Such logic, which will be soon shared also with the upcoming
microdump_writer.cc, is simply being moved to linux_dumper.cc,
extracting a GetMappingEffectiveNameAndPath method.
No behavioral change is intended.
BUG=chromium:410294
R=thestig@chromium.org
Review URL: https://breakpad.appspot.com/7734002
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1392 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/client/linux/minidump_writer')
-rw-r--r-- | src/client/linux/minidump_writer/linux_dumper.cc | 46 | ||||
-rw-r--r-- | src/client/linux/minidump_writer/linux_dumper.h | 21 | ||||
-rw-r--r-- | src/client/linux/minidump_writer/minidump_writer.cc | 57 |
3 files changed, 70 insertions, 54 deletions
diff --git a/src/client/linux/minidump_writer/linux_dumper.cc b/src/client/linux/minidump_writer/linux_dumper.cc index d565c741..ebb008d6 100644 --- a/src/client/linux/minidump_writer/linux_dumper.cc +++ b/src/client/linux/minidump_writer/linux_dumper.cc @@ -184,10 +184,12 @@ bool ElfFileSoNameFromMappedFile( // Did not find SONAME return false; } -} // namespace -// static -bool LinuxDumper::ElfFileSoName( +// Find the shared object name (SONAME) by examining the ELF information +// for |mapping|. If the SONAME is found copy it into the passed buffer +// |soname| and return true. The size of the buffer is |soname_size|. +// The SONAME will be truncated if it is too long to fit in the buffer. +bool ElfFileSoName( const MappingInfo& mapping, char* soname, size_t soname_size) { if (IsMappedFileOpenUnsafe(mapping)) { // Not safe @@ -214,6 +216,44 @@ bool LinuxDumper::ElfFileSoName( return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size); } +} // namespace + + +// static +void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping, + char* file_path, + size_t file_path_size, + char* file_name, + size_t file_name_size) { + my_strlcpy(file_path, mapping.name, file_path_size); + + // If an executable is mapped from a non-zero offset, this is likely because + // the executable was loaded directly from inside an archive file (e.g., an + // apk on Android). We try to find the name of the shared object (SONAME) by + // looking in the file for ELF sections. + bool mapped_from_archive = false; + if (mapping.exec && mapping.offset != 0) + mapped_from_archive = ElfFileSoName(mapping, file_name, file_name_size); + + if (mapped_from_archive) { + // Some tools (e.g., stackwalk) extract the basename from the pathname. In + // this case, we append the file_name to the mapped archive path as follows: + // file_name := libname.so + // file_path := /path/to/ARCHIVE.APK/libname.so + if (my_strlen(file_path) + 1 + my_strlen(file_name) < file_path_size) { + my_strlcat(file_path, "/", file_path_size); + my_strlcat(file_path, file_name, file_path_size); + } + } else { + // Common case: + // file_path := /path/to/libname.so + // file_name := libname.so + const char* basename = my_strrchr(file_path, '/'); + basename = basename == NULL ? file_path : (basename + 1); + my_strlcpy(file_name, basename, file_name_size); + } +} + bool LinuxDumper::ReadAuxv() { char auxv_path[NAME_MAX]; if (!BuildProcPath(auxv_path, pid_, "auxv")) { diff --git a/src/client/linux/minidump_writer/linux_dumper.h b/src/client/linux/minidump_writer/linux_dumper.h index e37ed179..40678e9c 100644 --- a/src/client/linux/minidump_writer/linux_dumper.h +++ b/src/client/linux/minidump_writer/linux_dumper.h @@ -111,19 +111,13 @@ class LinuxDumper { virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const = 0; // Generate a File ID from the .text section of a mapped entry. - // If not a member, mapping_id is ignored. + // If not a member, mapping_id is ignored. This method can also manipulate the + // |mapping|.name to truncate "(deleted)" from the file name if necessary. bool ElfFileIdentifierForMapping(const MappingInfo& mapping, bool member, unsigned int mapping_id, uint8_t identifier[sizeof(MDGUID)]); - // Find the shared object name (SONAME) by examining the ELF information - // for |mapping|. If the SONAME is found copy it into the passed buffer - // |soname| and return true. The size of the buffer is |soname_size|. - // The SONAME will be truncated if it is too long to fit in the buffer. - static bool ElfFileSoName( - const MappingInfo& mapping, char* soname, size_t soname_size); - uintptr_t crash_address() const { return crash_address_; } void set_crash_address(uintptr_t crash_address) { crash_address_ = crash_address; @@ -135,6 +129,17 @@ class LinuxDumper { pid_t crash_thread() const { return crash_thread_; } void set_crash_thread(pid_t crash_thread) { crash_thread_ = crash_thread; } + // Extracts the effective path and file name of from |mapping|. In most cases + // the effective name/path are just the mapping's path and basename. In some + // other cases, however, a library can be mapped from an archive (e.g., when + // loading .so libs from an apk on Android) and this method is able to + // reconstruct the original file name. + static void GetMappingEffectiveNameAndPath(const MappingInfo& mapping, + char* file_path, + size_t file_path_size, + char* file_name, + size_t file_name_size); + protected: bool ReadAuxv(); diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc index c65fa9c9..8406ffe4 100644 --- a/src/client/linux/minidump_writer/minidump_writer.cc +++ b/src/client/linux/minidump_writer/minidump_writer.cc @@ -540,49 +540,9 @@ class MinidumpWriter { mod.base_of_image = mapping.start_addr; mod.size_of_image = mapping.size; - const char* filepath_ptr = mapping.name; - 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++; - - size_t filename_len = mapping.name + filepath_len - filename_ptr; - - // If an executable is mapped from a non-zero offset, this is likely - // because the executable was loaded directly from inside an archive - // file. We try to find the name of the shared object (SONAME) by - // looking in the file for ELF sections. - - char soname[NAME_MAX]; - char pathname[NAME_MAX]; - if (mapping.exec && mapping.offset != 0 && - LinuxDumper::ElfFileSoName(mapping, soname, sizeof(soname))) { - filename_ptr = soname; - filename_len = my_strlen(soname); - - if (filepath_len + filename_len + 1 < NAME_MAX) { - // It doesn't have a real pathname, but tools such as stackwalk - // extract the basename, so simulating a pathname is helpful. - my_memcpy(pathname, filepath_ptr, filepath_len); - pathname[filepath_len] = '/'; - my_memcpy(pathname + filepath_len + 1, filename_ptr, filename_len); - pathname[filepath_len + filename_len + 1] = '\0'; - filepath_ptr = pathname; - filepath_len = filepath_len + filename_len + 1; - } - } 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; const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE; my_memcpy(cv_ptr, &cv_signature, sizeof(cv_signature)); @@ -593,20 +553,31 @@ class MinidumpWriter { // GUID was provided by caller. my_memcpy(signature, identifier, sizeof(MDGUID)); } else { + // Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|. dumper_->ElfFileIdentifierForMapping(mapping, member, mapping_id, signature); } my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux. cv_ptr += sizeof(uint32_t); + char file_name[NAME_MAX]; + char file_path[NAME_MAX]; + LinuxDumper::GetMappingEffectiveNameAndPath( + mapping, file_path, sizeof(file_path), file_name, sizeof(file_name)); + + const size_t file_name_len = my_strlen(file_name); + UntypedMDRVA cv(&minidump_writer_); + if (!cv.Allocate(MDCVInfoPDB70_minsize + file_name_len + 1)) + return false; + // Write pdb_file_name - my_memcpy(cv_ptr, filename_ptr, filename_len + 1); - cv.Copy(cv_buf, MDCVInfoPDB70_minsize + filename_len + 1); + my_memcpy(cv_ptr, file_name, file_name_len + 1); + cv.Copy(cv_buf, MDCVInfoPDB70_minsize + file_name_len + 1); mod.cv_record = cv.location(); MDLocationDescriptor ld; - if (!minidump_writer_.WriteString(filepath_ptr, filepath_len, &ld)) + if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld)) return false; mod.module_name_rva = ld.rva; return true; |