Index: llvm/docs/CommandGuide/llvm-readobj.rst =================================================================== --- llvm/docs/CommandGuide/llvm-readobj.rst +++ llvm/docs/CommandGuide/llvm-readobj.rst @@ -172,6 +172,10 @@ Display a bucket list histogram for dynamic symbol hash tables. +.. option:: --elf-dependent-libs + + Display the dependent libraries section. + .. option:: --elf-linker-options Display the linker options section. Index: llvm/test/tools/llvm-readobj/elf-dependent-libraries.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-readobj/elf-dependent-libraries.test @@ -0,0 +1,74 @@ +## Check that we can use the --elf-dependent-libs option +## to dump SHT_LLVM_DEPENDENT_LIBRARIES sections. + +## Check how we dump a file that has a single valid SHT_LLVM_DEPENDENT_LIBRARIES +## section with multiple entries. + +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-readobj --elf-dependent-libs %t1 2>&1 | FileCheck %s -DFILE=%t + +# CHECK: DependentLibs [ +# CHECK-NEXT: foo +# CHECK-NEXT: bar +# CHECK-NEXT: foo +# CHECK-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .deplibs + Type: SHT_LLVM_DEPENDENT_LIBRARIES + Libraries: [ foo, bar, foo ] + +## Now, check how we dump a mix of valid, empty and invalid SHT_LLVM_DEPENDENT_LIBRARIES sections. + +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-readobj --elf-dependent-libs %t2 2>&1 | FileCheck %s --check-prefix=MIX -DFILE=%t2 + +# MIX: DependentLibs [ +# MIX-EMPTY: +# MIX-NEXT: warning: '[[FILE]]': SHT_LLVM_DEPENDENT_LIBRARIES section at index 1 is broken: the content is not null-terminated +# MIX-NEXT: abc +# MIX-EMPTY: +# MIX-NEXT: warning: '[[FILE]]': SHT_LLVM_DEPENDENT_LIBRARIES section at index 4 is broken: section [index 4] has a sh_offset (0xffff0000) + sh_size (0x4) that cannot be represented +# MIX-NEXT: bar +# MIX-NEXT: xxx +# MIX-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: +## Case 1: test we report a warning for a non-null-terminated section. + - Name: .deplibs.nonul + Type: SHT_LLVM_DEPENDENT_LIBRARIES + Content: "666f6f" ## 'f', 'o', 'o' +## Case 2: test we can dump an entry from a valid section that has a single entry. + - Name: .deplibs.single + Type: SHT_LLVM_DEPENDENT_LIBRARIES + Libraries: [ abc ] +## Case 3: test we do not display warnings for an empty section. + - Name: .deplibs.empty + Type: SHT_LLVM_DEPENDENT_LIBRARIES + Content: "" +## Case 4: test we report a warning when the section offset is invalid. + - Name: .deplibs.broken.shoffset + Type: SHT_LLVM_DEPENDENT_LIBRARIES + Libraries: [ yyy ] + ShOffset: 0xffff0000 +## Case 5: test we can dump all entries from a valid section that has more than one entry. + - Name: .deplibs.multiple + Type: SHT_LLVM_DEPENDENT_LIBRARIES + Libraries: [ bar, xxx ] + +## llvm-readelf doesn't support --elf-dependent-libs yet. +# RUN: llvm-readelf --elf-dependent-libs %t1 2>&1 | FileCheck %s --check-prefix=READELF + +# READELF: printELFDependentLibs not implemented! Index: llvm/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/ELFDumper.cpp +++ llvm/tools/llvm-readobj/ELFDumper.cpp @@ -185,6 +185,8 @@ void printNotes() override; void printELFLinkerOptions() override; + void printELFDependentLibs() override; + void printStackSizes() override; const object::ELFObjectFile *getElfObject() const { return ObjF; }; @@ -414,6 +416,7 @@ virtual void printAddrsig(const ELFFile *Obj) = 0; virtual void printNotes(const ELFFile *Obj) = 0; virtual void printELFLinkerOptions(const ELFFile *Obj) = 0; + virtual void printELFDependentLibs(const ELFFile *Obj) = 0; virtual void printStackSizes(const ELFObjectFile *Obj) = 0; void printNonRelocatableStackSizes(const ELFObjectFile *Obj, std::function PrintHeader); @@ -480,6 +483,7 @@ void printAddrsig(const ELFFile *Obj) override; void printNotes(const ELFFile *Obj) override; void printELFLinkerOptions(const ELFFile *Obj) override; + void printELFDependentLibs(const ELFFile *Obj) override; void printStackSizes(const ELFObjectFile *Obj) override; void printStackSizeEntry(uint64_t Size, StringRef FuncName) override; void printMipsGOT(const MipsGOTParser &Parser) override; @@ -595,6 +599,7 @@ void printAddrsig(const ELFFile *Obj) override; void printNotes(const ELFFile *Obj) override; void printELFLinkerOptions(const ELFFile *Obj) override; + void printELFDependentLibs(const ELFFile *Obj) override; void printStackSizes(const ELFObjectFile *Obj) override; void printStackSizeEntry(uint64_t Size, StringRef FuncName) override; void printMipsGOT(const MipsGOTParser &Parser) override; @@ -1919,6 +1924,10 @@ ELFDumperStyle->printELFLinkerOptions(ObjF->getELFFile()); } +template void ELFDumper::printELFDependentLibs() { + ELFDumperStyle->printELFDependentLibs(ObjF->getELFFile()); +} + template void ELFDumper::printStackSizes() { ELFDumperStyle->printStackSizes(ObjF); } @@ -4741,6 +4750,11 @@ OS << "printELFLinkerOptions not implemented!\n"; } +template +void GNUStyle::printELFDependentLibs(const ELFFile *Obj) { + OS << "printELFDependentLibs not implemented!\n"; +} + // Used for printing section names in places where possible errors can be // ignored. static StringRef getSectionName(const SectionRef &Sec) { @@ -6051,6 +6065,42 @@ } } +template +void LLVMStyle::printELFDependentLibs(const ELFFile *Obj) { + ListScope L(W, "DependentLibs"); + + auto Warn = [this](unsigned SecNdx, StringRef Msg) { + this->reportUniqueWarning( + createError("SHT_LLVM_DEPENDENT_LIBRARIES section at index " + + Twine(SecNdx) + " is broken: " + Msg)); + }; + + unsigned I = -1; + for (const Elf_Shdr &Shdr : unwrapOrError(this->FileName, Obj->sections())) { + ++I; + if (Shdr.sh_type != ELF::SHT_LLVM_DEPENDENT_LIBRARIES) + continue; + + Expected> ContentsOrErr = Obj->getSectionContents(&Shdr); + if (!ContentsOrErr) { + Warn(I, toString(ContentsOrErr.takeError())); + continue; + } + + ArrayRef Contents = *ContentsOrErr; + if (!Contents.empty() && Contents.back() != 0) { + Warn(I, "the content is not null-terminated"); + continue; + } + + for (const uint8_t *I = Contents.begin(), *E = Contents.end(); I < E;) { + StringRef Lib((const char *)I); + W.printString(Lib); + I += Lib.size() + 1; + } + } +} + template void LLVMStyle::printStackSizes(const ELFObjectFile *Obj) { ListScope L(W, "StackSizes"); Index: llvm/tools/llvm-readobj/ObjDumper.h =================================================================== --- llvm/tools/llvm-readobj/ObjDumper.h +++ llvm/tools/llvm-readobj/ObjDumper.h @@ -68,6 +68,7 @@ virtual void printAddrsig() {} virtual void printNotes() {} virtual void printELFLinkerOptions() {} + virtual void printELFDependentLibs() {} virtual void printStackSizes() {} virtual void printArchSpecificInfo() { } Index: llvm/tools/llvm-readobj/llvm-readobj.cpp =================================================================== --- llvm/tools/llvm-readobj/llvm-readobj.cpp +++ llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -269,6 +269,11 @@ COFFLoadConfig("coff-load-config", cl::desc("Display the PE/COFF load config")); + // --elf-dependent-libs + cl::opt + ELFDependentLibs("elf-dependent-libs", + cl::desc("Display the dependent libraries section")); + // --elf-linker-options cl::opt ELFLinkerOptions("elf-linker-options", @@ -489,6 +494,8 @@ if (opts::VersionInfo) Dumper->printVersionInfo(); if (Obj->isELF()) { + if (opts::ELFDependentLibs) + Dumper->printELFDependentLibs(); if (opts::ELFLinkerOptions) Dumper->printELFLinkerOptions(); if (opts::ArchSpecificInfo)