Skip to content

Commit c9ff87a

Browse files
committed
Respond to user feedback.
1 parent 0ff6ba4 commit c9ff87a

File tree

2 files changed

+106
-88
lines changed

2 files changed

+106
-88
lines changed

lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp

Lines changed: 92 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
#include "llvm/Support/MipsABIFlags.h"
4747
#include "lldb/Target/Process.h"
4848

49-
5049
#define CASE_AND_STREAM(s, def, width) \
5150
case def: \
5251
s->Printf("%-*s", width, #def); \
@@ -2992,21 +2991,20 @@ void ObjectFileELF::ParseSymtab(Symtab &lldb_symtab) {
29922991
// section, nomatter if .symtab was already parsed or not. This is because
29932992
// minidebuginfo normally removes the .symtab symbols which have their
29942993
// matching .dynsym counterparts.
2995-
bool found_dynsym = false;
2994+
Section *dynsym = nullptr;
29962995
if (!symtab ||
29972996
GetSectionList()->FindSectionByName(ConstString(".gnu_debugdata"))) {
2998-
Section *dynsym =
2997+
dynsym =
29992998
section_list->FindSectionByType(eSectionTypeELFDynamicSymbols, true)
30002999
.get();
30013000
if (dynsym) {
3002-
found_dynsym = true;
30033001
auto [num_symbols, address_class_map] =
30043002
ParseSymbolTable(&lldb_symtab, symbol_id, dynsym);
30053003
symbol_id += num_symbols;
30063004
m_address_class_map.merge(address_class_map);
30073005
}
30083006
}
3009-
if (!found_dynsym) {
3007+
if (!dynsym) {
30103008
// Try and read the dynamic symbol table from the .dynamic section.
30113009
uint32_t num_symbols = 0;
30123010
std::optional<DataExtractor> symtab_data =
@@ -3883,9 +3881,9 @@ std::optional<DataExtractor> ObjectFileELF::GetDynstrData() {
38833881
// and represent the dynamic symbol tables's string table. These are needed
38843882
// by the dynamic loader and we can read them from a process' address space.
38853883
//
3886-
// When loading and ELF file from memory, only the program headers end up
3887-
// being mapped into memory, and we can find these values in the PT_DYNAMIC
3888-
// segment.
3884+
// When loading and ELF file from memory, only the program headers are
3885+
// guaranteed end up being mapped into memory, and we can find these values in
3886+
// the PT_DYNAMIC segment.
38893887
const ELFDynamic *strtab = FindDynamicSymbol(DT_STRTAB);
38903888
const ELFDynamic *strsz = FindDynamicSymbol(DT_STRSZ);
38913889
if (strtab == nullptr || strsz == nullptr)
@@ -3925,6 +3923,86 @@ std::optional<lldb_private::DataExtractor> ObjectFileELF::GetDynamicData() {
39253923
return std::nullopt;
39263924
}
39273925

3926+
std::optional<uint32_t> ObjectFileELF::GetNumSymbolsFromDynamicHash() {
3927+
const ELFDynamic *hash = FindDynamicSymbol(DT_HASH);
3928+
if (hash == nullptr)
3929+
return std::nullopt;
3930+
3931+
// The DT_HASH header looks like this:
3932+
struct DtHashHeader {
3933+
uint32_t nbucket;
3934+
uint32_t nchain;
3935+
};
3936+
if (auto data = ReadDataFromDynamic(hash, 8)) {
3937+
// We don't need the number of buckets value "nbucket", we just need the
3938+
// "nchain" value which contains the number of symbols.
3939+
offset_t offset = offsetof(DtHashHeader, nchain);
3940+
return data->GetU32(&offset);
3941+
}
3942+
3943+
return std::nullopt;
3944+
}
3945+
3946+
std::optional<uint32_t> ObjectFileELF::GetNumSymbolsFromDynamicGnuHash() {
3947+
const ELFDynamic *gnu_hash = FindDynamicSymbol(DT_GNU_HASH);
3948+
if (gnu_hash == nullptr)
3949+
return std::nullopt;
3950+
3951+
// Create a DT_GNU_HASH header
3952+
// https://flapenguin.me/elf-dt-gnu-hash
3953+
struct DtGnuHashHeader {
3954+
uint32_t nbuckets = 0;
3955+
uint32_t symoffset = 0;
3956+
uint32_t bloom_size = 0;
3957+
uint32_t bloom_shift = 0;
3958+
};
3959+
uint32_t num_symbols = 0;
3960+
// Read enogh data for the DT_GNU_HASH header so we can extract the values.
3961+
if (auto data = ReadDataFromDynamic(gnu_hash, sizeof(DtGnuHashHeader))) {
3962+
offset_t offset = 0;
3963+
DtGnuHashHeader header;
3964+
header.nbuckets = data->GetU32(&offset);
3965+
header.symoffset = data->GetU32(&offset);
3966+
header.bloom_size = data->GetU32(&offset);
3967+
header.bloom_shift = data->GetU32(&offset);
3968+
const size_t addr_size = GetAddressByteSize();
3969+
const addr_t buckets_offset =
3970+
sizeof(DtGnuHashHeader) + addr_size * header.bloom_size;
3971+
std::vector<uint32_t> buckets;
3972+
if (auto bucket_data = ReadDataFromDynamic(gnu_hash, header.nbuckets * 4, buckets_offset)) {
3973+
offset = 0;
3974+
for (uint32_t i = 0; i < header.nbuckets; ++i)
3975+
buckets.push_back(bucket_data->GetU32(&offset));
3976+
// Locate the chain that handles the largest index bucket.
3977+
uint32_t last_symbol = 0;
3978+
for (uint32_t bucket_value : buckets)
3979+
last_symbol = std::max(bucket_value, last_symbol);
3980+
if (last_symbol < header.symoffset) {
3981+
num_symbols = header.symoffset;
3982+
} else {
3983+
// Walk the bucket's chain to add the chain length to the total.
3984+
const addr_t chains_base_offset = buckets_offset + header.nbuckets * 4;
3985+
for (;;) {
3986+
if (auto chain_entry_data = ReadDataFromDynamic(gnu_hash, 4, chains_base_offset + (last_symbol - header.symoffset) * 4)) {
3987+
offset = 0;
3988+
uint32_t chain_entry = chain_entry_data->GetU32(&offset);
3989+
++last_symbol;
3990+
// If the low bit is set, this entry is the end of the chain.
3991+
if (chain_entry & 1)
3992+
break;
3993+
} else {
3994+
break;
3995+
}
3996+
}
3997+
num_symbols = last_symbol;
3998+
}
3999+
}
4000+
}
4001+
if (num_symbols > 0)
4002+
return ++num_symbols; // First symbol is always all zeros
4003+
4004+
return std::nullopt;
4005+
}
39284006

39294007
std::optional<DataExtractor>
39304008
ObjectFileELF::GetDynsymDataFromDynamic(uint32_t &num_symbols) {
@@ -3943,83 +4021,16 @@ ObjectFileELF::GetDynsymDataFromDynamic(uint32_t &num_symbols) {
39434021
ProcessSP process_sp(m_process_wp.lock());
39444022
const ELFDynamic *symtab = FindDynamicSymbol(DT_SYMTAB);
39454023
const ELFDynamic *syment = FindDynamicSymbol(DT_SYMENT);
3946-
const ELFDynamic *hash = FindDynamicSymbol(DT_HASH);
3947-
const ELFDynamic *gnu_hash = FindDynamicSymbol(DT_GNU_HASH);
39484024
// DT_SYMTAB and DT_SYMENT are mandatory.
39494025
if (symtab == nullptr || syment == nullptr)
39504026
return std::nullopt;
3951-
// We must have either a DT_HASH or a DT_GNU_HASH.
3952-
if (hash == nullptr && gnu_hash == nullptr)
3953-
return std::nullopt;
3954-
// The number of symbols in the symbol table is the number of entries in the
3955-
// symbol table divided by the size of each symbol table entry.
3956-
// We must figure out the number of symbols in the symbol table using the
3957-
// DT_HASH or the DT_GNU_HASH as the number of symbols isn't stored anywhere
3958-
// in the .dynamic section.
39594027

3960-
lldb::offset_t offset;
3961-
if (hash) {
3962-
// The DT_HASH header contains the number of symbols in the "nchain"
3963-
// member. The header looks like this:
3964-
// struct DT_HASH_HEADER {
3965-
// uint32_t nbucket;
3966-
// uint32_t nchain;
3967-
// };
3968-
if (auto data = ReadDataFromDynamic(hash, 8)) {
3969-
offset = 4;
3970-
num_symbols = data->GetU32(&offset);
3971-
}
3972-
}
3973-
if (num_symbols == 0 && gnu_hash) {
3974-
struct DT_GNU_HASH_HEADER {
3975-
uint32_t nbuckets = 0;
3976-
uint32_t symoffset = 0;
3977-
uint32_t bloom_size = 0;
3978-
uint32_t bloom_shift = 0;
3979-
};
3980-
if (auto data = ReadDataFromDynamic(gnu_hash, sizeof(DT_GNU_HASH_HEADER))) {
3981-
offset = 0;
3982-
DT_GNU_HASH_HEADER header;
3983-
header.nbuckets = data->GetU32(&offset);
3984-
header.symoffset = data->GetU32(&offset);
3985-
header.bloom_size = data->GetU32(&offset);
3986-
header.bloom_shift = data->GetU32(&offset);
3987-
const size_t addr_size = GetAddressByteSize();
3988-
const addr_t buckets_offset =
3989-
sizeof(DT_GNU_HASH_HEADER) + addr_size * header.bloom_size;
3990-
std::vector<uint32_t> buckets;
3991-
if (auto bucket_data = ReadDataFromDynamic(gnu_hash, header.nbuckets * 4, buckets_offset)) {
3992-
offset = 0;
3993-
for (uint32_t i = 0; i < header.nbuckets; ++i)
3994-
buckets.push_back(bucket_data->GetU32(&offset));
3995-
// Locate the chain that handles the largest index bucket.
3996-
uint32_t last_symbol = 0;
3997-
for (uint32_t bucket_value : buckets)
3998-
last_symbol = std::max(bucket_value, last_symbol);
3999-
if (last_symbol < header.symoffset) {
4000-
num_symbols = header.symoffset;
4001-
} else {
4002-
// Walk the bucket's chain to add the chain length to the total.
4003-
const addr_t chains_base_offset = buckets_offset + header.nbuckets * 4;
4004-
for (;;) {
4005-
if (auto chain_entry_data = ReadDataFromDynamic(gnu_hash, 4, chains_base_offset + (last_symbol - header.symoffset) * 4)) {
4006-
offset = 0;
4007-
uint32_t chain_entry = chain_entry_data->GetU32(&offset);
4008-
++last_symbol;
4009-
// If the low bit is set, this entry is the end of the chain.
4010-
if (chain_entry & 1)
4011-
break;
4012-
} else {
4013-
break;
4014-
}
4015-
}
4016-
num_symbols = last_symbol;
4017-
}
4018-
}
4019-
}
4020-
if (num_symbols > 0)
4021-
++num_symbols; // First symbol is always all zeros
4022-
}
4028+
if (std::optional<uint32_t> syms = GetNumSymbolsFromDynamicHash())
4029+
num_symbols = *syms;
4030+
else if (std::optional<uint32_t> syms = GetNumSymbolsFromDynamicGnuHash())
4031+
num_symbols = *syms;
4032+
else
4033+
return std::nullopt;
40234034
if (num_symbols == 0)
40244035
return std::nullopt;
40254036
return ReadDataFromDynamic(symtab, syment->d_val * num_symbols);

lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -447,28 +447,35 @@ class ObjectFileELF : public lldb_private::ObjectFile {
447447
///
448448
/// \param[in] length The number of bytes to read.
449449
///
450-
/// \param[in] offset The number of bytes to skip after the d_ptr value
450+
/// \param[in] offset The number of bytes to skip after the d_ptr value
451451
/// before reading data.
452452
///
453-
/// \return The bytes that represent the dynanic entries data or
453+
/// \return The bytes that represent the dynanic entries data or
454454
/// \c std::nullopt if an error occured or the data is not available.
455-
std::optional<lldb_private::DataExtractor>
456-
ReadDataFromDynamic(const elf::ELFDynamic *dyn, uint64_t length,
455+
std::optional<lldb_private::DataExtractor>
456+
ReadDataFromDynamic(const elf::ELFDynamic *dyn, uint64_t length,
457457
uint64_t offset = 0);
458458

459459
/// Get the bytes that represent the dynamic symbol table from the .dynamic
460460
/// section from process memory.
461461
///
462462
/// This functon uses the DT_SYMTAB value from the .dynamic section to read
463463
/// the symbols table data from process memory. The number of symbols in the
464-
/// symbol table is calculated by looking at the DT_HASH or DT_GNU_HASH
464+
/// symbol table is calculated by looking at the DT_HASH or DT_GNU_HASH
465465
/// values as the symbol count isn't stored in the .dynamic section.
466466
///
467467
/// \return The bytes that represent the symbol table data from the .dynamic
468-
/// section or section headers or \c std::nullopt if an error
468+
/// section or section headers or \c std::nullopt if an error
469469
/// occured or if there is no dynamic symbol data available.
470-
std::optional<lldb_private::DataExtractor>
470+
std::optional<lldb_private::DataExtractor>
471471
GetDynsymDataFromDynamic(uint32_t &num_symbols);
472+
473+
/// Get the number of symbols from the DT_HASH dynamic entry.
474+
std::optional<uint32_t> GetNumSymbolsFromDynamicHash();
475+
476+
/// Get the number of symbols from the DT_GNU_HASH dynamic entry.
477+
std::optional<uint32_t> GetNumSymbolsFromDynamicGnuHash();
478+
472479
};
473480

474481
#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H

0 commit comments

Comments
 (0)