[dump_syms/Mac] New -x option to prefer extern names when there's a mismatch

When built with -gmlt, .dSYMs are (by design) missing the
`DW_AT_linkage_name` which Breakpad uses to fill out the
(name-mangled) function names.

Thankfully, the .dSYM contains both the old-school LC_SYMTAB command
containing the STABS-format symbols (which include the fully-qualified
C++ symbol names we want, but no actual compilation unit data), as
well as the LC_SEGMENT_64 containing the __DWARF segment with the
minimal -gmlt debug information (which excludes the name-mangled C++
symbols).

Unfortunately, since the .dSYM's STABS does not define compilation
units, the usual path in `StabsReader` ignores all the fully-qualified
C++ symbol names for the functions:

https://chromium.googlesource.com/breakpad/breakpad/+/bd9d94c70843620adeebcd73c243001237c6d426/src/common/stabs_reader.cc#100

Fortunately, when built for macOS platforms (`HAVE_MACH_O_NLIST_H`),
`StabsReader` supports storing all the STABS-format symbols as
`Extern`s, regardless of whether or not they're in a compilation unit:

https://chromium.googlesource.com/breakpad/breakpad/+/bd9d94c70843620adeebcd73c243001237c6d426/src/common/stabs_reader.cc#119

Currently, when there's both a `Function` and an `Extern` with the same address, `Module` discards the `Extern`:

https://chromium.googlesource.com/breakpad/breakpad/+/bd9d94c70843620adeebcd73c243001237c6d426/src/common/module.cc#161

This CL adds a new `-x` option to the Mac `dump_syms` which prefers
the Extern function name if there's a mismatch.

Bug: https://bugs.chromium.org/p/google-breakpad/issues/detail?id=883
Change-Id: I0d32adc64fbf567600b0a5ca63c71c422b7f0f8c
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/4453650
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Ben Hamilton 2023-04-21 12:02:42 -06:00 committed by Joshua Peraza
parent 16cee17997
commit f548d75c9f
8 changed files with 123 additions and 18 deletions

View file

@ -105,14 +105,16 @@ Module::Module(const string& name,
const string& architecture,
const string& id,
const string& code_id /* = "" */,
bool enable_multiple_field /* = false*/)
bool enable_multiple_field /* = false*/,
bool prefer_extern_name /* = false*/)
: name_(name),
os_(os),
architecture_(architecture),
id_(id),
code_id_(code_id),
load_address_(0),
enable_multiple_field_(enable_multiple_field) {}
enable_multiple_field_(enable_multiple_field),
prefer_extern_name_(prefer_extern_name) {}
Module::~Module() {
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
@ -152,11 +154,14 @@ bool Module::AddFunction(Function* function) {
it_ext = externs_.find(&arm_thumb_ext);
}
if (it_ext != externs_.end()) {
Extern* found_ext = it_ext->get();
bool name_mismatch = found_ext->name != function->name;
if (enable_multiple_field_) {
Extern* found_ext = it_ext->get();
// If the PUBLIC is for the same symbol as the FUNC, don't mark multiple.
function->is_multiple |=
found_ext->name != function->name || found_ext->is_multiple;
function->is_multiple |= name_mismatch || found_ext->is_multiple;
}
if (name_mismatch && prefer_extern_name_) {
function->name = AddStringToPool(it_ext->get()->name);
}
externs_.erase(it_ext);
}