aboutsummaryrefslogtreecommitdiff
path: root/src/client/linux/minidump_writer
diff options
context:
space:
mode:
authorprimiano@chromium.org <primiano@chromium.org>2014-10-17 10:58:23 +0000
committerprimiano@chromium.org <primiano@chromium.org>2014-10-17 10:58:23 +0000
commit719546275aa9a9c1a2811341b178ac689a9d85d5 (patch)
tree15691157498b8de5eb3f0c42e52b3e892c4b81da /src/client/linux/minidump_writer
parentThe process uptime computation when the Windows out-of-process Crash Generation (diff)
downloadbreakpad-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.cc46
-rw-r--r--src/client/linux/minidump_writer/linux_dumper.h21
-rw-r--r--src/client/linux/minidump_writer/minidump_writer.cc57
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;