Merge pull request #33264 from azat/symbols-from-resources-fix

Fix parsing symbols from resources (for shared builds)
This commit is contained in:
alexey-milovidov 2021-12-29 21:06:51 +03:00 committed by GitHub
commit 3655965b39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 13 deletions

View File

@ -86,7 +86,7 @@ namespace
/// https://stackoverflow.com/questions/32088140/multiple-string-tables-in-elf-object /// https://stackoverflow.com/questions/32088140/multiple-string-tables-in-elf-object
void updateResources(std::string_view name, const void * address, SymbolIndex::Resources & resources) void updateResources(ElfW(Addr) base_address, std::string_view object_name, std::string_view name, const void * address, SymbolIndex::Resources & resources)
{ {
const char * char_address = static_cast<const char *>(address); const char * char_address = static_cast<const char *>(address);
@ -97,18 +97,23 @@ void updateResources(std::string_view name, const void * address, SymbolIndex::R
name = name.substr((name[0] == '_') + strlen("binary_")); name = name.substr((name[0] == '_') + strlen("binary_"));
name = name.substr(0, name.size() - strlen("_start")); name = name.substr(0, name.size() - strlen("_start"));
resources.emplace(name, std::string_view{char_address, 0}); // NOLINT resources.emplace(name, SymbolIndex::ResourcesBlob{
base_address,
object_name,
std::string_view{char_address, 0}, // NOLINT
});
} }
else if (name.ends_with("_end")) else if (name.ends_with("_end"))
{ {
name = name.substr((name[0] == '_') + strlen("binary_")); name = name.substr((name[0] == '_') + strlen("binary_"));
name = name.substr(0, name.size() - strlen("_end")); name = name.substr(0, name.size() - strlen("_end"));
if (auto it = resources.find(name); it != resources.end() && it->second.empty()) auto it = resources.find(name);
if (it != resources.end() && it->second.base_address == base_address && it->second.data.empty())
{ {
const char * start = it->second.data(); const char * start = it->second.data.data();
assert(char_address >= start); assert(char_address >= start);
it->second = std::string_view{start, static_cast<size_t>(char_address - start)}; it->second.data = std::string_view{start, static_cast<size_t>(char_address - start)};
} }
} }
} }
@ -153,10 +158,12 @@ void collectSymbolsFromProgramHeaders(
size_t sym_cnt = 0; size_t sym_cnt = 0;
for (const auto * it = dyn_begin; it->d_tag != DT_NULL; ++it) for (const auto * it = dyn_begin; it->d_tag != DT_NULL; ++it)
{ {
ElfW(Addr) base_address = correct_address(info->dlpi_addr, it->d_un.d_ptr);
// TODO: this branch leads to invalid address of the hash table. Need further investigation. // TODO: this branch leads to invalid address of the hash table. Need further investigation.
// if (it->d_tag == DT_HASH) // if (it->d_tag == DT_HASH)
// { // {
// const ElfW(Word) * hash = reinterpret_cast<const ElfW(Word) *>(correct_address(info->dlpi_addr, it->d_un.d_ptr)); // const ElfW(Word) * hash = reinterpret_cast<const ElfW(Word) *>(base_address);
// sym_cnt = hash[1]; // sym_cnt = hash[1];
// break; // break;
// } // }
@ -167,7 +174,7 @@ void collectSymbolsFromProgramHeaders(
const uint32_t * buckets = nullptr; const uint32_t * buckets = nullptr;
const uint32_t * hashval = nullptr; const uint32_t * hashval = nullptr;
const ElfW(Word) * hash = reinterpret_cast<const ElfW(Word) *>(correct_address(info->dlpi_addr, it->d_un.d_ptr)); const ElfW(Word) * hash = reinterpret_cast<const ElfW(Word) *>(base_address);
buckets = hash + 4 + (hash[2] * sizeof(size_t) / 4); buckets = hash + 4 + (hash[2] * sizeof(size_t) / 4);
@ -196,9 +203,11 @@ void collectSymbolsFromProgramHeaders(
const char * strtab = nullptr; const char * strtab = nullptr;
for (const auto * it = dyn_begin; it->d_tag != DT_NULL; ++it) for (const auto * it = dyn_begin; it->d_tag != DT_NULL; ++it)
{ {
ElfW(Addr) base_address = correct_address(info->dlpi_addr, it->d_un.d_ptr);
if (it->d_tag == DT_STRTAB) if (it->d_tag == DT_STRTAB)
{ {
strtab = reinterpret_cast<const char *>(correct_address(info->dlpi_addr, it->d_un.d_ptr)); strtab = reinterpret_cast<const char *>(base_address);
break; break;
} }
} }
@ -208,10 +217,12 @@ void collectSymbolsFromProgramHeaders(
for (const auto * it = dyn_begin; it->d_tag != DT_NULL; ++it) for (const auto * it = dyn_begin; it->d_tag != DT_NULL; ++it)
{ {
ElfW(Addr) base_address = correct_address(info->dlpi_addr, it->d_un.d_ptr);
if (it->d_tag == DT_SYMTAB) if (it->d_tag == DT_SYMTAB)
{ {
/* Get the pointer to the first entry of the symbol table */ /* Get the pointer to the first entry of the symbol table */
const ElfW(Sym) * elf_sym = reinterpret_cast<const ElfW(Sym) *>(correct_address(info->dlpi_addr, it->d_un.d_ptr)); const ElfW(Sym) * elf_sym = reinterpret_cast<const ElfW(Sym) *>(base_address);
/* Iterate over the symbol table */ /* Iterate over the symbol table */
for (ElfW(Word) sym_index = 0; sym_index < ElfW(Word)(sym_cnt); ++sym_index) for (ElfW(Word) sym_index = 0; sym_index < ElfW(Word)(sym_cnt); ++sym_index)
@ -236,7 +247,7 @@ void collectSymbolsFromProgramHeaders(
symbols.push_back(symbol); symbols.push_back(symbol);
/// But resources can be represented by a pair of empty symbols (indicating their boundaries). /// But resources can be represented by a pair of empty symbols (indicating their boundaries).
updateResources(symbol.name, symbol.address_begin, resources); updateResources(base_address, info->dlpi_name, symbol.name, symbol.address_begin, resources);
} }
break; break;
@ -299,7 +310,7 @@ void collectSymbolsFromELFSymbolTable(
if (symbol_table_entry->st_size) if (symbol_table_entry->st_size)
symbols.push_back(symbol); symbols.push_back(symbol);
updateResources(symbol.name, symbol.address_begin, resources); updateResources(info->dlpi_addr, info->dlpi_name, symbol.name, symbol.address_begin, resources);
} }
} }

View File

@ -51,7 +51,7 @@ public:
std::string_view getResource(String name) const std::string_view getResource(String name) const
{ {
if (auto it = data.resources.find(name); it != data.resources.end()) if (auto it = data.resources.find(name); it != data.resources.end())
return it->second; return it->second.data;
return {}; return {};
} }
@ -59,7 +59,17 @@ public:
String getBuildID() const { return data.build_id; } String getBuildID() const { return data.build_id; }
String getBuildIDHex() const; String getBuildIDHex() const;
using Resources = std::unordered_map<std::string_view /* symbol name */, std::string_view /* blob */>; struct ResourcesBlob
{
/// Symbol can be presented in multiple shared objects,
/// base_address will be used to compare only symbols from the same SO.
ElfW(Addr) base_address;
/// Just a human name of the SO.
std::string_view object_name;
/// Data blob.
std::string_view data;
};
using Resources = std::unordered_map<std::string_view /* symbol name */, ResourcesBlob>;
struct Data struct Data
{ {