aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoshua Peraza <jperaza@chromium.org>2019-10-24 11:41:44 -0700
committerJoshua Peraza <jperaza@chromium.org>2019-10-24 18:59:59 +0000
commit3e56ef9d4e328142c07605a0bde1dfd2ed122611 (patch)
tree8f822543c79d3f6947f72e5b8b5d52f40a320e05 /src
parentconvert_UTF: rewrite in C++ (diff)
downloadbreakpad-3e56ef9d4e328142c07605a0bde1dfd2ed122611.tar.xz
linux, dump_syms: set module name from DT_SONAME
The Breakpad and Crashpad clients will use an object's DT_SONAME as the name for a module if it exists. Previously, linux dump_syms would assume the basename of an input elf file matches that value, causing symbol lookups to fail if they were mismatched. This patch updates dump_syms to use DT_SONAME as the module name, if present. Bug: 1016924 Change-Id: I5eff0cf06c703841df3fb552cb5a8e1e50a20c64 Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/1876763 Reviewed-by: Mike Frysinger <vapier@chromium.org>
Diffstat (limited to 'src')
-rw-r--r--src/client/linux/minidump_writer/linux_dumper.cc43
-rw-r--r--src/common/linux/dump_symbols.cc10
-rw-r--r--src/common/linux/elfutils.cc61
-rw-r--r--src/common/linux/elfutils.h8
4 files changed, 78 insertions, 44 deletions
diff --git a/src/client/linux/minidump_writer/linux_dumper.cc b/src/client/linux/minidump_writer/linux_dumper.cc
index dbedecd5..5653133e 100644
--- a/src/client/linux/minidump_writer/linux_dumper.cc
+++ b/src/client/linux/minidump_writer/linux_dumper.cc
@@ -439,49 +439,6 @@ bool LinuxDumper::GetMappingAbsolutePath(const MappingInfo& mapping,
}
namespace {
-bool ElfFileSoNameFromMappedFile(
- const void* elf_base, char* soname, size_t soname_size) {
- if (!IsValidElf(elf_base)) {
- // Not ELF
- return false;
- }
-
- const void* segment_start;
- size_t segment_size;
- if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC, &segment_start,
- &segment_size)) {
- // No dynamic section
- return false;
- }
-
- const void* dynstr_start;
- size_t dynstr_size;
- if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB, &dynstr_start,
- &dynstr_size)) {
- // No dynstr section
- return false;
- }
-
- const ElfW(Dyn)* dynamic = static_cast<const ElfW(Dyn)*>(segment_start);
- size_t dcount = segment_size / sizeof(ElfW(Dyn));
- for (const ElfW(Dyn)* dyn = dynamic; dyn < dynamic + dcount; ++dyn) {
- if (dyn->d_tag == DT_SONAME) {
- const char* dynstr = static_cast<const char*>(dynstr_start);
- if (dyn->d_un.d_val >= dynstr_size) {
- // Beyond the end of the dynstr section
- return false;
- }
- const char* str = dynstr + dyn->d_un.d_val;
- const size_t maxsize = dynstr_size - dyn->d_un.d_val;
- my_strlcpy(soname, str, maxsize < soname_size ? maxsize : soname_size);
- return true;
- }
- }
-
- // Did not find SONAME
- return false;
-}
-
// 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|.
diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
index 1110cb9d..40bb3ff2 100644
--- a/src/common/linux/dump_symbols.cc
+++ b/src/common/linux/dump_symbols.cc
@@ -38,6 +38,7 @@
#include <elf.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <link.h>
#include <stdint.h>
#include <stdio.h>
@@ -936,7 +937,14 @@ bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header,
return false;
}
- string name = google_breakpad::BaseName(obj_filename);
+ string name;
+ char name_buf[NAME_MAX];
+ memset(name_buf, 0, sizeof(name_buf));
+ name = google_breakpad::ElfFileSoNameFromMappedFile(elf_header, name_buf,
+ sizeof(name_buf))
+ ? name_buf
+ : google_breakpad::BaseName(obj_filename);
+
string os = "Linux";
// Add an extra "0" at the end. PDB files on Windows have an 'age'
// number appended to the end of the file identifier; this isn't
diff --git a/src/common/linux/elfutils.cc b/src/common/linux/elfutils.cc
index 3bb8ff12..9532d5ad 100644
--- a/src/common/linux/elfutils.cc
+++ b/src/common/linux/elfutils.cc
@@ -173,4 +173,65 @@ bool FindElfSegments(const void* elf_mapped_base,
return false;
}
+template <typename ElfClass>
+bool FindElfSoNameFromDynamicSection(const void* section_start,
+ size_t section_size,
+ const void* dynstr_start,
+ size_t dynstr_size,
+ char* soname,
+ size_t soname_size) {
+ typedef typename ElfClass::Dyn Dyn;
+
+ auto* dynamic = static_cast<const Dyn*>(section_start);
+ size_t dcount = section_size / sizeof(Dyn);
+ for (const Dyn* dyn = dynamic; dyn < dynamic + dcount; ++dyn) {
+ if (dyn->d_tag == DT_SONAME) {
+ const char* dynstr = static_cast<const char*>(dynstr_start);
+ if (dyn->d_un.d_val >= dynstr_size) {
+ // Beyond the end of the dynstr section
+ return false;
+ }
+ const char* str = dynstr + dyn->d_un.d_val;
+ const size_t maxsize = dynstr_size - dyn->d_un.d_val;
+ my_strlcpy(soname, str, maxsize < soname_size ? maxsize : soname_size);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ElfFileSoNameFromMappedFile(const void* elf_base,
+ char* soname,
+ size_t soname_size) {
+ if (!IsValidElf(elf_base)) {
+ // Not ELF
+ return false;
+ }
+
+ const void* segment_start;
+ size_t segment_size;
+ if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC, &segment_start,
+ &segment_size)) {
+ // No dynamic section
+ return false;
+ }
+
+ const void* dynstr_start;
+ size_t dynstr_size;
+ if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB, &dynstr_start,
+ &dynstr_size)) {
+ // No dynstr section
+ return false;
+ }
+
+ int cls = ElfClass(elf_base);
+ return cls == ELFCLASS32 ? FindElfSoNameFromDynamicSection<ElfClass32>(
+ segment_start, segment_size, dynstr_start,
+ dynstr_size, soname, soname_size)
+ : FindElfSoNameFromDynamicSection<ElfClass64>(
+ segment_start, segment_size, dynstr_start,
+ dynstr_size, soname, soname_size);
+}
+
} // namespace google_breakpad
diff --git a/src/common/linux/elfutils.h b/src/common/linux/elfutils.h
index 8fcb6a96..aefb6cf5 100644
--- a/src/common/linux/elfutils.h
+++ b/src/common/linux/elfutils.h
@@ -45,6 +45,7 @@ namespace google_breakpad {
// with specific ELF bits.
struct ElfClass32 {
typedef Elf32_Addr Addr;
+ typedef Elf32_Dyn Dyn;
typedef Elf32_Ehdr Ehdr;
typedef Elf32_Nhdr Nhdr;
typedef Elf32_Phdr Phdr;
@@ -62,6 +63,7 @@ struct ElfClass32 {
struct ElfClass64 {
typedef Elf64_Addr Addr;
+ typedef Elf64_Dyn Dyn;
typedef Elf64_Ehdr Ehdr;
typedef Elf64_Nhdr Nhdr;
typedef Elf64_Phdr Phdr;
@@ -122,6 +124,12 @@ const T*
GetOffset(const typename ElfClass::Ehdr* elf_header,
typename ElfClass::Off offset);
+// Read the value of DT_SONAME from the elf file mapped at |elf_base|. Returns
+// true and fills |soname| with the result if found.
+bool ElfFileSoNameFromMappedFile(const void* elf_base,
+ char* soname,
+ size_t soname_size);
+
} // namespace google_breakpad
#endif // COMMON_LINUX_ELFUTILS_H_