46
46
#include " llvm/Support/MipsABIFlags.h"
47
47
#include " lldb/Target/Process.h"
48
48
49
-
50
49
#define CASE_AND_STREAM (s, def, width ) \
51
50
case def: \
52
51
s->Printf (" %-*s" , width, #def); \
@@ -2992,21 +2991,20 @@ void ObjectFileELF::ParseSymtab(Symtab &lldb_symtab) {
2992
2991
// section, nomatter if .symtab was already parsed or not. This is because
2993
2992
// minidebuginfo normally removes the .symtab symbols which have their
2994
2993
// matching .dynsym counterparts.
2995
- bool found_dynsym = false ;
2994
+ Section *dynsym = nullptr ;
2996
2995
if (!symtab ||
2997
2996
GetSectionList ()->FindSectionByName (ConstString (" .gnu_debugdata" ))) {
2998
- Section * dynsym =
2997
+ dynsym =
2999
2998
section_list->FindSectionByType (eSectionTypeELFDynamicSymbols, true )
3000
2999
.get ();
3001
3000
if (dynsym) {
3002
- found_dynsym = true ;
3003
3001
auto [num_symbols, address_class_map] =
3004
3002
ParseSymbolTable (&lldb_symtab, symbol_id, dynsym);
3005
3003
symbol_id += num_symbols;
3006
3004
m_address_class_map.merge (address_class_map);
3007
3005
}
3008
3006
}
3009
- if (!found_dynsym ) {
3007
+ if (!dynsym ) {
3010
3008
// Try and read the dynamic symbol table from the .dynamic section.
3011
3009
uint32_t num_symbols = 0 ;
3012
3010
std::optional<DataExtractor> symtab_data =
@@ -3883,9 +3881,9 @@ std::optional<DataExtractor> ObjectFileELF::GetDynstrData() {
3883
3881
// and represent the dynamic symbol tables's string table. These are needed
3884
3882
// by the dynamic loader and we can read them from a process' address space.
3885
3883
//
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.
3889
3887
const ELFDynamic *strtab = FindDynamicSymbol (DT_STRTAB);
3890
3888
const ELFDynamic *strsz = FindDynamicSymbol (DT_STRSZ);
3891
3889
if (strtab == nullptr || strsz == nullptr )
@@ -3925,6 +3923,86 @@ std::optional<lldb_private::DataExtractor> ObjectFileELF::GetDynamicData() {
3925
3923
return std::nullopt;
3926
3924
}
3927
3925
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
+ }
3928
4006
3929
4007
std::optional<DataExtractor>
3930
4008
ObjectFileELF::GetDynsymDataFromDynamic (uint32_t &num_symbols) {
@@ -3943,83 +4021,16 @@ ObjectFileELF::GetDynsymDataFromDynamic(uint32_t &num_symbols) {
3943
4021
ProcessSP process_sp (m_process_wp.lock ());
3944
4022
const ELFDynamic *symtab = FindDynamicSymbol (DT_SYMTAB);
3945
4023
const ELFDynamic *syment = FindDynamicSymbol (DT_SYMENT);
3946
- const ELFDynamic *hash = FindDynamicSymbol (DT_HASH);
3947
- const ELFDynamic *gnu_hash = FindDynamicSymbol (DT_GNU_HASH);
3948
4024
// DT_SYMTAB and DT_SYMENT are mandatory.
3949
4025
if (symtab == nullptr || syment == nullptr )
3950
4026
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.
3959
4027
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;
4023
4034
if (num_symbols == 0 )
4024
4035
return std::nullopt;
4025
4036
return ReadDataFromDynamic (symtab, syment->d_val * num_symbols);
0 commit comments