Commit 01bb02c7 authored by Sasha Goldshtein's avatar Sasha Goldshtein

cc: Handle nested functions correctly when resolving symbols

`ProcSyms::Module::find_addr` incorrectly resolves symbols when
functions are nested in each other. Specifically, this was discovered
with libpthread, where there are multiple symbols for `write`,
where `write_nocancel` is strictly nested inside `write`. Fix by
explicitly going backward until we reach a matching symbol -- see
details in `ProcSyms::Module::find_addr` comments.
parent 7c965b31
...@@ -190,17 +190,32 @@ bool ProcSyms::Module::find_addr(uint64_t addr, struct bcc_symbol *sym) { ...@@ -190,17 +190,32 @@ bool ProcSyms::Module::find_addr(uint64_t addr, struct bcc_symbol *sym) {
sym->offset = offset; sym->offset = offset;
auto it = std::upper_bound(syms_.begin(), syms_.end(), Symbol(nullptr, offset, 0)); auto it = std::upper_bound(syms_.begin(), syms_.end(), Symbol(nullptr, offset, 0));
if (it != syms_.begin()) if (it == syms_.begin())
--it; return false;
else
it = syms_.end();
if (it != syms_.end() // 'it' points to the symbol whose start address is strictly greater than
&& offset >= it->start && offset < it->start + it->size) { // the address we're looking for. Start stepping backwards as long as the
// current symbol is still below the desired address, and see if the end
// of the current symbol (start + size) is above the desired address. Once
// we have a matching symbol, return it. Note that simply looking at '--it'
// is not enough, because symbols can be nested. For example, we could be
// looking for offset 0x12 with the following symbols available:
// SYMBOL START SIZE END
// goo 0x0 0x6 0x0 + 0x6 = 0x6
// foo 0x6 0x10 0x6 + 0x10 = 0x16
// bar 0x8 0x4 0x8 + 0x4 = 0xc
// baz 0x16 0x10 0x16 + 0x10 = 0x26
// The upper_bound lookup will return baz, and then going one symbol back
// brings us to bar, which does not contain offset 0x12 and is nested inside
// foo. Going back one more symbol brings us to foo, which contains 0x12
// and is a match.
for (--it; offset >= it->start; --it) {
if (offset < it->start + it->size) {
sym->name = it->name->c_str(); sym->name = it->name->c_str();
sym->offset = (offset - it->start); sym->offset = (offset - it->start);
return true; return true;
} }
}
return false; return false;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment