mirror of
git://sourceware.org/git/libabigail.git
synced 2025-03-25 04:38:29 +00:00
symtab-reader: add support for binaries compiled with CFI
Control-Flow-Integrity (CFI) when enabled in clang built binaries introduces an indirection when looking up ELF symbols. For DSO, the symbol table (.dynsym) will still contain the symbols, but additional symbols with suffix .cfi will be added to the full .symtab. Unfortunately, the DWARF debug information refers to CFI symbols by address to the .cfi suffixed variants as they point to the actual implementation. When the dwarf reader is determining whether to suppress variable or function declarations, it does so by identifying if there is an associated ELF symbol at the given address read from DWARF. Unless we know about the alternative address, this will fail and the type information will be suppressed. Hence add the .cfi symbol values to the lookup map to associate their address with the corresponding publicly exported symbol. * src/abg-symtab-reader.cc (symtab::load_): use new add_alternative_address_lookups method. (add_alternative_address_lookups): New method. * src/abg-symtab-reader.h (add_alternative_address_lookups): new function declaration. * tests/data/test-read-dwarf/test-libaaudio.so: New test data. * tests/data/test-read-dwarf/test-libaaudio.so.abi: New test data. * tests/data/Makefile.am: Add the two new tests input to source distribution. * tests/test-read-dwarf.cc: New test case. Reported-by: Dan Albert <danalbert@google.com> Reviewed-by: Giuliano Procida <gprocida@google.com> Signed-off-by: Matthias Maennich <maennich@google.com> Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
parent
3a22dfaff6
commit
578ba12139
@ -376,6 +376,8 @@ symtab::load_(Elf* elf_handle,
|
||||
}
|
||||
}
|
||||
|
||||
add_alternative_address_lookups(elf_handle);
|
||||
|
||||
is_kernel_binary_ = elf_helpers::is_linux_kernel(elf_handle);
|
||||
|
||||
// Now apply the ksymtab_exported attribute to the symbols we collected.
|
||||
@ -564,5 +566,84 @@ symtab::update_function_entry_address_symbol_map(
|
||||
}
|
||||
}
|
||||
|
||||
/// Fill up the lookup maps with alternative keys
|
||||
///
|
||||
/// Due to special features like Control-Flow-Integrity (CFI), the symbol
|
||||
/// lookup could be done indirectly. E.g. enabling CFI causes clang to
|
||||
/// associate the DWARF information with the actual CFI protected function
|
||||
/// (suffix .cfi) instead of with the entry symbol in the symtab.
|
||||
///
|
||||
/// This function adds additional lookup keys to compensate for that.
|
||||
///
|
||||
/// So far, this only implements CFI support, by adding addr->symbol pairs
|
||||
/// where
|
||||
/// addr : symbol value of the <foo>.cfi valyue
|
||||
/// symbol : symbol_sptr looked up via "<foo>"
|
||||
///
|
||||
/// @param elf_handle the ELF handle to operate on
|
||||
void
|
||||
symtab::add_alternative_address_lookups(Elf* elf_handle)
|
||||
{
|
||||
Elf_Scn* symtab_section = elf_helpers::find_symtab_section(elf_handle);
|
||||
if (!symtab_section)
|
||||
return;
|
||||
GElf_Shdr symtab_sheader;
|
||||
gelf_getshdr(symtab_section, &symtab_sheader);
|
||||
|
||||
const size_t number_syms =
|
||||
symtab_sheader.sh_size / symtab_sheader.sh_entsize;
|
||||
|
||||
Elf_Data* symtab = elf_getdata(symtab_section, 0);
|
||||
|
||||
for (size_t i = 0; i < number_syms; ++i)
|
||||
{
|
||||
GElf_Sym *sym, sym_mem;
|
||||
sym = gelf_getsym(symtab, i, &sym_mem);
|
||||
if (!sym)
|
||||
{
|
||||
std::cerr << "Could not load symbol with index " << i
|
||||
<< ": Skipping alternative symbol load.\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* const name_str =
|
||||
elf_strptr(elf_handle, symtab_sheader.sh_link, sym->st_name);
|
||||
|
||||
// no name, no game
|
||||
if (!name_str)
|
||||
continue;
|
||||
|
||||
const std::string name = name_str;
|
||||
if (name.empty())
|
||||
continue;
|
||||
|
||||
// Add alternative lookup addresses for CFI symbols
|
||||
static const std::string cfi = ".cfi";
|
||||
if (name.size() > cfi.size()
|
||||
&& name.compare(name.size() - cfi.size(), cfi.size(), cfi) == 0)
|
||||
// ... name.ends_with(".cfi")
|
||||
{
|
||||
const auto candidate_name = name.substr(0, name.size() - cfi.size());
|
||||
|
||||
auto symbols = lookup_symbol(candidate_name);
|
||||
// lookup_symbol returns a vector of symbols. For this case we handle
|
||||
// only the case that there has been exactly one match. Otherwise we
|
||||
// can't reasonably handle it and need to bail out.
|
||||
ABG_ASSERT(symbols.size() <= 1);
|
||||
if (symbols.size() == 1)
|
||||
{
|
||||
const auto& symbol_sptr = symbols[0];
|
||||
GElf_Addr symbol_value =
|
||||
elf_helpers::maybe_adjust_et_rel_sym_addr_to_abs_addr(
|
||||
elf_handle, sym);
|
||||
|
||||
const auto result =
|
||||
addr_symbol_map_.emplace(symbol_value, symbol_sptr);
|
||||
ABG_ASSERT(result.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace symtab_reader
|
||||
} // end namespace abigail
|
||||
|
@ -293,6 +293,9 @@ private:
|
||||
update_function_entry_address_symbol_map(Elf* elf_handle,
|
||||
GElf_Sym* native_symbol,
|
||||
const elf_symbol_sptr& symbol_sptr);
|
||||
|
||||
void
|
||||
add_alternative_address_lookups(Elf* elf_handle);
|
||||
};
|
||||
|
||||
/// Helper class to allow range-for loops on symtabs for C++11 and later code.
|
||||
|
@ -566,6 +566,8 @@ test-read-dwarf/PR27700/pub-incdir/inc.h \
|
||||
test-read-dwarf/PR27700/test-PR27700.abi \
|
||||
test-read-dwarf/PR27700/test-PR27700.c \
|
||||
test-read-dwarf/PR27700/test-PR27700.o \
|
||||
test-read-dwarf/test-libaaudio.so \
|
||||
test-read-dwarf/test-libaaudio.so.abi \
|
||||
\
|
||||
test-annotate/test0.abi \
|
||||
test-annotate/test1.abi \
|
||||
|
BIN
tests/data/test-read-dwarf/test-libaaudio.so
Normal file
BIN
tests/data/test-read-dwarf/test-libaaudio.so
Normal file
Binary file not shown.
2072
tests/data/test-read-dwarf/test-libaaudio.so.abi
Normal file
2072
tests/data/test-read-dwarf/test-libaaudio.so.abi
Normal file
File diff suppressed because it is too large
Load Diff
@ -488,6 +488,14 @@ InOutSpec in_out_specs[] =
|
||||
"data/test-read-dwarf/PR27700/test-PR27700.abi",
|
||||
"output/test-read-dwarf/PR27700/test-PR27700.abi",
|
||||
},
|
||||
{
|
||||
"data/test-read-dwarf/test-libaaudio.so",
|
||||
"",
|
||||
"",
|
||||
HASH_TYPE_ID_STYLE,
|
||||
"data/test-read-dwarf/test-libaaudio.so.abi",
|
||||
"output/test-read-dwarf/test-libaaudio.so.abi",
|
||||
},
|
||||
// This should be the last entry.
|
||||
{NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user