Index: llvm/test/tools/llvm-elfabi/binary-read-arch.test =================================================================== --- llvm/test/tools/llvm-elfabi/binary-read-arch.test +++ llvm/test/tools/llvm-elfabi/binary-read-arch.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s > %t -# RUN: llvm-elfabi %t --emit-tbe=- | FileCheck %s +# RUN: llvm-elfabi %t --elf --emit-tbe=- | FileCheck %s !ELF FileHeader: @@ -12,9 +12,9 @@ Type: SHT_DYNAMIC Flags: [ SHF_ALLOC ] Address: 0x1000 - Content: "0a0000000000000001000000000000000500000000000000600200000000000000000000000000000000000000000000" + Content: "0a0000000000000001000000000000000500000000000000a00200000000000000000000000000000000000000000000" # DT_STRSZ 1 (0x1) - # DT_STRTAB 0x0260 + # DT_STRTAB 0x02a0 # DT_NULL 0x0 Size: 48 - Name: .dynstr @@ -23,6 +23,13 @@ Address: 0x3000 # \0 Content: "00" + - Name: .dynsym + Type: SHT_DYNSYM + Flags: [ SHF_ALLOC ] + Address: 0x3000 + EntSize: 0x18 + Content: "000000000000000000000000000000000000000000000000" + Link: .dynstr ProgramHeaders: - Type: PT_LOAD VAddr: 0x0000 Index: llvm/test/tools/llvm-elfabi/binary-read-bad-soname.test =================================================================== --- llvm/test/tools/llvm-elfabi/binary-read-bad-soname.test +++ llvm/test/tools/llvm-elfabi/binary-read-bad-soname.test @@ -23,7 +23,7 @@ Flags: [ SHF_ALLOC ] Address: 0x2000 EntSize: 24 - Size: 0 + Content: "000000000000000000000000000000000000000000000000" Link: .dynstr - Name: .dynstr Type: SHT_STRTAB Index: llvm/test/tools/llvm-elfabi/binary-read-neededlibs.test =================================================================== --- llvm/test/tools/llvm-elfabi/binary-read-neededlibs.test +++ llvm/test/tools/llvm-elfabi/binary-read-neededlibs.test @@ -12,12 +12,12 @@ Type: SHT_DYNAMIC Flags: [ SHF_ALLOC ] Address: 0x1000 - Content: "010000000000000001000000000000000e00000000000000150000000000000001000000000000000b000000000000000a0000000000000024000000000000000500000000000000d00200000000000000000000000000000000000000000000" + Content: "010000000000000001000000000000000e00000000000000150000000000000001000000000000000b000000000000000a0000000000000024000000000000000500000000000000e80200000000000000000000000000000000000000000000" # DT_NEEDED 1 (0x01) # DT_SONAME 21 (0x15) # DT_NEEDED 11 (0x0b) # DT_STRSZ 36 (0x24) - # DT_STRTAB 0x2d0 + # DT_STRTAB 0x2e8 # DT_NULL 0x0 Size: 96 - Name: .dynsym @@ -25,7 +25,7 @@ Flags: [ SHF_ALLOC ] Address: 0x2000 EntSize: 24 - Size: 0 + Content: "000000000000000000000000000000000000000000000000" Link: .dynstr - Name: .dynstr Type: SHT_STRTAB Index: llvm/test/tools/llvm-elfabi/binary-read-soname-no-null.test =================================================================== --- llvm/test/tools/llvm-elfabi/binary-read-soname-no-null.test +++ llvm/test/tools/llvm-elfabi/binary-read-soname-no-null.test @@ -12,10 +12,10 @@ Type: SHT_DYNAMIC Flags: [ SHF_ALLOC ] Address: 0x1000 - Content: "0e000000000000000d000000000000000a0000000000000017000000000000000500000000000000b00200000000000000000000000000000000000000000000" + Content: "0e000000000000000d000000000000000a0000000000000017000000000000000500000000000000c80200000000000000000000000000000000000000000000" # DT_SONAME 13 (0x0d) # DT_STRSZ 23 (0x17) - # DT_STRTAB 0x2b0 + # DT_STRTAB 0x2c8 # DT_NULL 0x0 Size: 64 - Name: .dynsym @@ -23,7 +23,7 @@ Flags: [ SHF_ALLOC ] Address: 0x2000 EntSize: 24 - Size: 0 + Content: "000000000000000000000000000000000000000000000000" Link: .dynstr - Name: .dynstr Type: SHT_STRTAB Index: llvm/test/tools/llvm-elfabi/binary-read-soname.test =================================================================== --- llvm/test/tools/llvm-elfabi/binary-read-soname.test +++ llvm/test/tools/llvm-elfabi/binary-read-soname.test @@ -12,10 +12,10 @@ Type: SHT_DYNAMIC Flags: [ SHF_ALLOC ] Address: 0x1000 - Content: "0e000000000000000d000000000000000a000000000000001c000000000000000500000000000000b00200000000000000000000000000000000000000000000" + Content: "0e000000000000000d000000000000000a000000000000001c000000000000000500000000000000c80200000000000000000000000000000000000000000000" # DT_SONAME 13 (0x0d) # DT_STRSZ 28 (0x1c) - # DT_STRTAB 0x2b0 + # DT_STRTAB 0x2c8 # DT_NULL 0x0 Size: 64 - Name: .dynsym @@ -23,7 +23,7 @@ Flags: [ SHF_ALLOC ] Address: 0x2000 EntSize: 24 - Size: 0 + Content: "000000000000000000000000000000000000000000000000" Link: .dynstr - Name: .dynstr Type: SHT_STRTAB Index: llvm/test/tools/llvm-elfabi/binary-read-syms.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-elfabi/binary-read-syms.test @@ -0,0 +1,62 @@ +# RUN: yaml2obj %s > %t +# RUN: llvm-elfabi --elf %t --emit-tbe=- | FileCheck %s + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .dynamic + Type: SHT_DYNAMIC + Flags: [ SHF_ALLOC ] + Address: 0x1000 + Content: "0a000000000000001c000000000000000500000000000000900300000000000000000000000000000000000000000000" + # DT_STRSZ 21 (0x15) + # DT_STRTAB 0x390 + # DT_NULL 0x0 + Size: 64 +ProgramHeaders: + - Type: PT_LOAD + VAddr: 0x0000 + PAddr: 0x0000 + - Type: PT_DYNAMIC + Flags: [ PF_X, PF_R ] + VAddr: 0x1000 + PAddr: 0x1000 + Sections: + - Section: .dynamic +DynamicSymbols: + Global: + - Name: foo + Type: STT_NOTYPE + Size: 42 + Section: .dynsym + - Name: bar + Type: STT_OBJECT + Size: 42 + Section: .dynsym + - Name: baz + Type: STT_TLS + Size: 7 + Section: .dynsym + - Name: not + Type: STT_COMMON + Size: 16 + Weak: + - Name: nor + Type: STT_FUNC + Size: 10 + Section: .dynsym + +# CHECK: --- !tapi-tbe +# CHECK-NEXT: TbeVersion: {{[1-9]\d*\.(0|([1-9]\d*))}} +# CHECK-NEXT: Arch: x86_64 +# CHECK-NEXT: Symbols: +# CHECK-NEXT: bar: { Type: Object, Size: 42 } +# CHECK-NEXT: baz: { Type: TLS, Size: 7 } +# CHECK-NEXT: foo: { Type: NoType, Size: 42 } +# CHECK-NEXT: nor: { Type: Func, Weak: true } +# CHECK-NEXT: not: { Type: Unknown, Size: 16, Undefined: true } +# CHECK-NEXT: ... Index: llvm/test/tools/llvm-elfabi/replace-soname-tbe.test =================================================================== --- llvm/test/tools/llvm-elfabi/replace-soname-tbe.test +++ llvm/test/tools/llvm-elfabi/replace-soname-tbe.test @@ -12,9 +12,9 @@ Type: SHT_DYNAMIC Flags: [ SHF_ALLOC ] Address: 0x1000 - Content: "0a0000000000000001000000000000000500000000000000600200000000000000000000000000000000000000000000" + Content: "0a0000000000000001000000000000000500000000000000a00200000000000000000000000000000000000000000000" # DT_STRSZ 1 (0x1) - # DT_STRTAB 0x0260 + # DT_STRTAB 0x02a0 # DT_NULL 0x0 Size: 48 - Name: .dynstr @@ -23,6 +23,13 @@ Address: 0x3000 # \0 Content: "00" + - Name: .dynsym + Type: SHT_DYNSYM + Flags: [ SHF_ALLOC ] + Address: 0x3000 + EntSize: 0x18 + Content: "000000000000000000000000000000000000000000000000" + Link: .dynstr ProgramHeaders: - Type: PT_LOAD VAddr: 0x0000 Index: llvm/tools/llvm-elfabi/ELFObjHandler.cpp =================================================================== --- llvm/tools/llvm-elfabi/ELFObjHandler.cpp +++ llvm/tools/llvm-elfabi/ELFObjHandler.cpp @@ -8,6 +8,7 @@ //===-----------------------------------------------------------------------===/ #include "ELFObjHandler.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Object/Binary.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ELFTypes.h" @@ -34,6 +35,12 @@ std::vector NeededLibNames; }; +// Simple struct to hold references to section header contents. +template struct SectionContents { + typename ELFT::SymRange DynSym; + // TODO: Store references to symbol warnings. +}; + /// This function behaves similarly to StringRef::substr(), but attempts to /// terminate the returned StringRef at the first null terminator. If no null /// terminator is found, the new StringRef ends at the end of the source @@ -112,6 +119,118 @@ return Error::success(); } +/// This function populates a SectionHeaders struct using a binary +/// ELFT::ShdrRange. +/// +/// @param Shdrs Target SectionHeaders struct to populate. +/// @param BinaryShdrs Source binary section headers. +template +static Error fetchSectionContents(SectionContents &Shdrs, + const ELFFile &ElfFile) { + using Elf_Shdr_Range = typename ELFT::ShdrRange; + using Elf_Sym_Range = typename ELFT::SymRange; + Expected BinShdrs = ElfFile.sections(); + if (!BinShdrs) + return BinShdrs.takeError(); + if (BinShdrs->empty()) + return createError("No section headers found"); + + // Search .dynamic for relevant entries. + for (auto &Sec : *BinShdrs) { + if (Sec.sh_type == SHT_DYNSYM) { + Expected DynSyms = ElfFile.symbols(&Sec); + if (!DynSyms) + return DynSyms.takeError(); + Shdrs.DynSym = *DynSyms; + } + // TODO: Store references to symbol warning section contents in + // SectionContents. + } + + // A valid dynamic symbol table with no symbols still has a null entry. + if (Shdrs.DynSym.empty()) { + return createError("Dynamic symbol table is empty"); + } + return Error::success(); +} + +/// This function extracts symbol type from a symbol's st_info member and +/// maps it to an ELFSymbolType enum. +/// Currently, STT_NOTYPE, STT_OBJECT, STT_FUNC, and STT_TLS are supported. +/// Other symbol types are mapped to ELFSymbolType::Unknown. +/// @param Info Binary symbol st_info to extract symbol type from. +static ELFSymbolType convertInfoToType(uint8_t Info) { + Info = Info & 0xf; + switch (Info) { + case ELF::STT_NOTYPE: + return ELFSymbolType::NoType; + case ELF::STT_OBJECT: + return ELFSymbolType::Object; + case ELF::STT_FUNC: + return ELFSymbolType::Func; + case ELF::STT_TLS: + return ELFSymbolType::TLS; + default: + return ELFSymbolType::Unknown; + } +} + +/// This function populates all members of an ELFSymbol from a binary ELFT::Sym. +/// @param TargetSym ELFSymbol to populate. +/// @param RawSym Source binary ELFT::Sym to extract information from. +template +static void populateSymbol(ELFSymbol &TargetSym, + const typename ELFT::Sym &RawSym) { + // Initialize to zero since Size might not be set later. + TargetSym.Size = 0; + + uint8_t Binding = RawSym.st_info >> 4; + if (Binding == STB_WEAK) + TargetSym.Weak = true; + else + TargetSym.Weak = false; + + if (RawSym.st_shndx == 0) + TargetSym.Undefined = true; + else + TargetSym.Undefined = false; + + TargetSym.Type = convertInfoToType(RawSym.st_info); + + if (TargetSym.Type != ELFSymbolType::Func) { + TargetSym.Size = RawSym.st_size; + } +} + +/// This function populates an ELFStub with symbols using information read +/// from an ELF binary. +/// @param TargetStub ELFStub to add symbols to. +/// @param Sections Refs to contents of source sections (.dynsym, warnings). +/// @param DynStr StringRef to the dynamic string table. +template +static void populateSymbols(ELFStub &TargetStub, + SectionContents &Sections, + StringRef DynStr) { + // This loop deliberately skips the first element, + // which is the NULL symbol that initiates a symbol table. + auto RawSym = Sections.DynSym.begin(); + while (++RawSym < Sections.DynSym.end()) { + // If a symbol does not have global or weak binding, ignore it. + uint8_t Binding = RawSym->st_info >> 4; + if (!(Binding == STB_GLOBAL || Binding == STB_WEAK)) + continue; + // If a symbol doesn't have default or protected visibility, ignore it. + uint8_t Visibility = RawSym->st_other & 0x3; + if (!(Visibility == STV_DEFAULT || Visibility == STV_PROTECTED)) + continue; + // Create an ELFSymbol from the binary symbol table entry. + ELFSymbol Sym(terminatedSubstr(DynStr, RawSym->st_name)); + populateSymbol(Sym, *RawSym); + // TODO: Implement symbol warnings. + TargetStub.Symbols.insert(std::move(Sym)); + } +} + /// Returns a new ELFStub with all members populated from an ELFObjectFile. /// @param ElfObj Source ELFObjectFile. template @@ -148,7 +267,11 @@ DestStub->NeededLibs.push_back(terminatedSubstr(DynStr, NeededStrOffset)); } - // TODO: Populate Symbols from .dynsym table and linked string table. + // Populate Symbols from .dynsym table and dynamic string table. + SectionContents Sections; + if (Error Err = fetchSectionContents(Sections, *ElfFile)) + return std::move(Err); + populateSymbols(*DestStub, Sections, DynStr); return std::move(DestStub); }