44
44
#include " llvm/Support/MathExtras.h"
45
45
#include " llvm/Support/MemoryBuffer.h"
46
46
#include " llvm/Support/MipsABIFlags.h"
47
+ #include " lldb/Target/Process.h"
47
48
48
49
#define CASE_AND_STREAM (s, def, width ) \
49
50
case def: \
@@ -3007,9 +3008,10 @@ void ObjectFileELF::ParseSymtab(Symtab &lldb_symtab) {
3007
3008
// section, nomatter if .symtab was already parsed or not. This is because
3008
3009
// minidebuginfo normally removes the .symtab symbols which have their
3009
3010
// matching .dynsym counterparts.
3011
+ Section *dynsym = nullptr ;
3010
3012
if (!symtab ||
3011
3013
GetSectionList ()->FindSectionByName (ConstString (" .gnu_debugdata" ))) {
3012
- Section * dynsym =
3014
+ dynsym =
3013
3015
section_list->FindSectionByType (eSectionTypeELFDynamicSymbols, true )
3014
3016
.get ();
3015
3017
if (dynsym) {
@@ -3019,6 +3021,20 @@ void ObjectFileELF::ParseSymtab(Symtab &lldb_symtab) {
3019
3021
m_address_class_map.merge (address_class_map);
3020
3022
}
3021
3023
}
3024
+ if (!dynsym) {
3025
+ // Try and read the dynamic symbol table from the .dynamic section.
3026
+ uint32_t num_symbols = 0 ;
3027
+ std::optional<DataExtractor> symtab_data =
3028
+ GetDynsymDataFromDynamic (num_symbols);
3029
+ std::optional<DataExtractor> strtab_data = GetDynstrData ();
3030
+ if (symtab_data && strtab_data) {
3031
+ auto [num_symbols_parsed, address_class_map] =
3032
+ ParseSymbols (&lldb_symtab, symbol_id, section_list, num_symbols,
3033
+ symtab_data.value (), strtab_data.value ());
3034
+ symbol_id += num_symbols_parsed;
3035
+ m_address_class_map.merge (address_class_map);
3036
+ }
3037
+ }
3022
3038
3023
3039
// DT_JMPREL
3024
3040
// If present, this entry's d_ptr member holds the address of
@@ -3828,6 +3844,33 @@ ObjectFileELF::MapFileDataWritable(const FileSpec &file, uint64_t Size,
3828
3844
Offset);
3829
3845
}
3830
3846
3847
+ std::optional<DataExtractor>
3848
+ ObjectFileELF::ReadDataFromDynamic (const ELFDynamic *dyn, uint64_t length,
3849
+ uint64_t offset) {
3850
+ // ELFDynamic values contain a "d_ptr" member that will be a load address if
3851
+ // we have an ELF file read from memory, or it will be a file address if it
3852
+ // was read from a ELF file. This function will correctly fetch data pointed
3853
+ // to by the ELFDynamic::d_ptr, or return std::nullopt if the data isn't
3854
+ // available.
3855
+ const lldb::addr_t d_ptr_addr = dyn->d_ptr + offset;
3856
+ if (ProcessSP process_sp = m_process_wp.lock ()) {
3857
+ if (DataBufferSP data_sp = ReadMemory (process_sp, d_ptr_addr, length))
3858
+ return DataExtractor (data_sp, GetByteOrder (), GetAddressByteSize ());
3859
+ } else {
3860
+ // We have an ELF file with no section headers or we didn't find the
3861
+ // .dynamic section. Try and find the .dynstr section.
3862
+ Address addr;
3863
+ if (!addr.ResolveAddressUsingFileSections (d_ptr_addr, GetSectionList ()))
3864
+ return std::nullopt;
3865
+ DataExtractor data;
3866
+ addr.GetSection ()->GetSectionData (data);
3867
+ return DataExtractor (data,
3868
+ d_ptr_addr - addr.GetSection ()->GetFileAddress (),
3869
+ length);
3870
+ }
3871
+ return std::nullopt;
3872
+ }
3873
+
3831
3874
std::optional<DataExtractor> ObjectFileELF::GetDynstrData () {
3832
3875
if (SectionList *section_list = GetSectionList ()) {
3833
3876
// Find the SHT_DYNAMIC section.
@@ -3855,31 +3898,15 @@ std::optional<DataExtractor> ObjectFileELF::GetDynstrData() {
3855
3898
// and represent the dynamic symbol tables's string table. These are needed
3856
3899
// by the dynamic loader and we can read them from a process' address space.
3857
3900
//
3858
- // When loading and ELF file from memory, only the program headers end up
3859
- // being mapped into memory, and we can find these values in the PT_DYNAMIC
3860
- // segment.
3901
+ // When loading and ELF file from memory, only the program headers are
3902
+ // guaranteed end up being mapped into memory, and we can find these values in
3903
+ // the PT_DYNAMIC segment.
3861
3904
const ELFDynamic *strtab = FindDynamicSymbol (DT_STRTAB);
3862
3905
const ELFDynamic *strsz = FindDynamicSymbol (DT_STRSZ);
3863
3906
if (strtab == nullptr || strsz == nullptr )
3864
3907
return std::nullopt;
3865
3908
3866
- if (ProcessSP process_sp = m_process_wp.lock ()) {
3867
- if (DataBufferSP data_sp =
3868
- ReadMemory (process_sp, strtab->d_ptr , strsz->d_val ))
3869
- return DataExtractor (data_sp, GetByteOrder (), GetAddressByteSize ());
3870
- } else {
3871
- // We have an ELF file with no section headers or we didn't find the
3872
- // .dynamic section. Try and find the .dynstr section.
3873
- Address addr;
3874
- if (addr.ResolveAddressUsingFileSections (strtab->d_ptr , GetSectionList ())) {
3875
- DataExtractor data;
3876
- addr.GetSection ()->GetSectionData (data);
3877
- return DataExtractor (data,
3878
- strtab->d_ptr - addr.GetSection ()->GetFileAddress (),
3879
- strsz->d_val );
3880
- }
3881
- }
3882
- return std::nullopt;
3909
+ return ReadDataFromDynamic (strtab, strsz->d_val , /* offset=*/ 0 );
3883
3910
}
3884
3911
3885
3912
std::optional<lldb_private::DataExtractor> ObjectFileELF::GetDynamicData () {
@@ -3912,3 +3939,116 @@ std::optional<lldb_private::DataExtractor> ObjectFileELF::GetDynamicData() {
3912
3939
}
3913
3940
return std::nullopt;
3914
3941
}
3942
+
3943
+ std::optional<uint32_t > ObjectFileELF::GetNumSymbolsFromDynamicHash () {
3944
+ const ELFDynamic *hash = FindDynamicSymbol (DT_HASH);
3945
+ if (hash == nullptr )
3946
+ return std::nullopt;
3947
+
3948
+ // The DT_HASH header looks like this:
3949
+ struct DtHashHeader {
3950
+ uint32_t nbucket;
3951
+ uint32_t nchain;
3952
+ };
3953
+ if (auto data = ReadDataFromDynamic (hash, 8 )) {
3954
+ // We don't need the number of buckets value "nbucket", we just need the
3955
+ // "nchain" value which contains the number of symbols.
3956
+ offset_t offset = offsetof (DtHashHeader, nchain);
3957
+ return data->GetU32 (&offset);
3958
+ }
3959
+
3960
+ return std::nullopt;
3961
+ }
3962
+
3963
+ std::optional<uint32_t > ObjectFileELF::GetNumSymbolsFromDynamicGnuHash () {
3964
+ const ELFDynamic *gnu_hash = FindDynamicSymbol (DT_GNU_HASH);
3965
+ if (gnu_hash == nullptr )
3966
+ return std::nullopt;
3967
+
3968
+ // Create a DT_GNU_HASH header
3969
+ // https://flapenguin.me/elf-dt-gnu-hash
3970
+ struct DtGnuHashHeader {
3971
+ uint32_t nbuckets = 0 ;
3972
+ uint32_t symoffset = 0 ;
3973
+ uint32_t bloom_size = 0 ;
3974
+ uint32_t bloom_shift = 0 ;
3975
+ };
3976
+ uint32_t num_symbols = 0 ;
3977
+ // Read enogh data for the DT_GNU_HASH header so we can extract the values.
3978
+ if (auto data = ReadDataFromDynamic (gnu_hash, sizeof (DtGnuHashHeader))) {
3979
+ offset_t offset = 0 ;
3980
+ DtGnuHashHeader header;
3981
+ header.nbuckets = data->GetU32 (&offset);
3982
+ header.symoffset = data->GetU32 (&offset);
3983
+ header.bloom_size = data->GetU32 (&offset);
3984
+ header.bloom_shift = data->GetU32 (&offset);
3985
+ const size_t addr_size = GetAddressByteSize ();
3986
+ const addr_t buckets_offset =
3987
+ sizeof (DtGnuHashHeader) + addr_size * header.bloom_size ;
3988
+ std::vector<uint32_t > buckets;
3989
+ if (auto bucket_data = ReadDataFromDynamic (gnu_hash, header.nbuckets * 4 , buckets_offset)) {
3990
+ offset = 0 ;
3991
+ for (uint32_t i = 0 ; i < header.nbuckets ; ++i)
3992
+ buckets.push_back (bucket_data->GetU32 (&offset));
3993
+ // Locate the chain that handles the largest index bucket.
3994
+ uint32_t last_symbol = 0 ;
3995
+ for (uint32_t bucket_value : buckets)
3996
+ last_symbol = std::max (bucket_value, last_symbol);
3997
+ if (last_symbol < header.symoffset ) {
3998
+ num_symbols = header.symoffset ;
3999
+ } else {
4000
+ // Walk the bucket's chain to add the chain length to the total.
4001
+ const addr_t chains_base_offset = buckets_offset + header.nbuckets * 4 ;
4002
+ for (;;) {
4003
+ if (auto chain_entry_data = ReadDataFromDynamic (gnu_hash, 4 , chains_base_offset + (last_symbol - header.symoffset ) * 4 )) {
4004
+ offset = 0 ;
4005
+ uint32_t chain_entry = chain_entry_data->GetU32 (&offset);
4006
+ ++last_symbol;
4007
+ // If the low bit is set, this entry is the end of the chain.
4008
+ if (chain_entry & 1 )
4009
+ break ;
4010
+ } else {
4011
+ break ;
4012
+ }
4013
+ }
4014
+ num_symbols = last_symbol;
4015
+ }
4016
+ }
4017
+ }
4018
+ if (num_symbols > 0 )
4019
+ return num_symbols;
4020
+
4021
+ return std::nullopt;
4022
+ }
4023
+
4024
+ std::optional<DataExtractor>
4025
+ ObjectFileELF::GetDynsymDataFromDynamic (uint32_t &num_symbols) {
4026
+ // Every ELF file which represents an executable or shared library has
4027
+ // mandatory .dynamic entries. The DT_SYMTAB value contains a pointer to the
4028
+ // symbol table, and DT_SYMENT contains the size of a symbol table entry.
4029
+ // We then can use either the DT_HASH or DT_GNU_HASH to find the number of
4030
+ // symbols in the symbol table as the symbol count is not stored in the
4031
+ // .dynamic section as a key/value pair.
4032
+ //
4033
+ // When loading and ELF file from memory, only the program headers end up
4034
+ // being mapped into memory, and we can find these values in the PT_DYNAMIC
4035
+ // segment.
4036
+ num_symbols = 0 ;
4037
+ // Get the process in case this is an in memory ELF file.
4038
+ ProcessSP process_sp (m_process_wp.lock ());
4039
+ const ELFDynamic *symtab = FindDynamicSymbol (DT_SYMTAB);
4040
+ const ELFDynamic *syment = FindDynamicSymbol (DT_SYMENT);
4041
+ // DT_SYMTAB and DT_SYMENT are mandatory.
4042
+ if (symtab == nullptr || syment == nullptr )
4043
+ return std::nullopt;
4044
+
4045
+ if (std::optional<uint32_t > syms = GetNumSymbolsFromDynamicHash ())
4046
+ num_symbols = *syms;
4047
+ else if (std::optional<uint32_t > syms = GetNumSymbolsFromDynamicGnuHash ())
4048
+ num_symbols = *syms;
4049
+ else
4050
+ return std::nullopt;
4051
+ if (num_symbols == 0 )
4052
+ return std::nullopt;
4053
+ return ReadDataFromDynamic (symtab, syment->d_val * num_symbols);
4054
+ }
0 commit comments