diff --git a/llvm/docs/CommandGuide/llvm-readobj.rst b/llvm/docs/CommandGuide/llvm-readobj.rst --- a/llvm/docs/CommandGuide/llvm-readobj.rst +++ b/llvm/docs/CommandGuide/llvm-readobj.rst @@ -152,6 +152,10 @@ Display demangled symbol names in the output. +.. option:: --dependent-libraries + + Display the dependent libraries section. + .. option:: --dyn-relocations Display the dynamic relocation entries. diff --git a/llvm/test/tools/llvm-readobj/elf-dependent-libraries.test b/llvm/test/tools/llvm-readobj/elf-dependent-libraries.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/elf-dependent-libraries.test @@ -0,0 +1,74 @@ +## Check that we can use the --dependent-libraries 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 --dependent-libraries %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 --dependent-libraries %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 is greater than the file size (0x2c0) +# 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 --dependent-libraries yet. +# RUN: llvm-readelf --dependent-libraries %t1 2>&1 | FileCheck %s --check-prefix=READELF + +# READELF: printDependentLibs not implemented! diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -193,6 +193,7 @@ void printFileHeaders() override; void printSectionHeaders() override; void printRelocations() override; + void printDependentLibs() override; void printDynamicRelocations() override; void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override; void printHashSymbols() override; @@ -617,6 +618,7 @@ virtual void printSymbols(const ELFFile *Obj, bool PrintSymbols, bool PrintDynamicSymbols) = 0; virtual void printHashSymbols(const ELFFile *Obj) {} + virtual void printDependentLibs(const ELFFile *Obj) = 0; virtual void printDynamic(const ELFFile *Obj) {} virtual void printDynamicRelocations(const ELFFile *Obj) = 0; virtual void printSymtabMessage(const ELFFile *Obj, StringRef Name, @@ -687,6 +689,7 @@ void printSymbols(const ELFO *Obj, bool PrintSymbols, bool PrintDynamicSymbols) override; void printHashSymbols(const ELFO *Obj) override; + void printDependentLibs(const ELFFile *Obj) override; void printDynamic(const ELFFile *Obj) override; void printDynamicRelocations(const ELFO *Obj) override; void printSymtabMessage(const ELFO *Obj, StringRef Name, size_t Offset, @@ -807,6 +810,7 @@ void printSectionHeaders(const ELFO *Obj) override; void printSymbols(const ELFO *Obj, bool PrintSymbols, bool PrintDynamicSymbols) override; + void printDependentLibs(const ELFFile *Obj) override; void printDynamic(const ELFFile *Obj) override; void printDynamicRelocations(const ELFO *Obj) override; void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders, @@ -2054,6 +2058,10 @@ SymbolVersionNeedSection); } +template void ELFDumper::printDependentLibs() { + ELFDumperStyle->printDependentLibs(ObjF->getELFFile()); +} + template void ELFDumper::printDynamicRelocations() { ELFDumperStyle->printDynamicRelocations(ObjF->getELFFile()); } @@ -4873,6 +4881,11 @@ OS << "printELFLinkerOptions not implemented!\n"; } +template +void GNUStyle::printDependentLibs(const ELFFile *Obj) { + OS << "printDependentLibs not implemented!\n"; +} + // Used for printing section names in places where possible errors can be // ignored. static StringRef getSectionName(const SectionRef &Sec) { @@ -6144,6 +6157,42 @@ } template +void LLVMStyle::printDependentLibs(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"); if (Obj->isRelocatableObject()) diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -53,6 +53,7 @@ virtual void printUnwindInfo() = 0; // Only implemented for ELF at this time. + virtual void printDependentLibs() {} virtual void printDynamicRelocations() { } virtual void printDynamicTable() { } virtual void printNeededLibraries() { } diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -58,6 +58,11 @@ "--section-groups and --elf-hash-histogram.")); cl::alias AllShort("a", cl::desc("Alias for --all"), cl::aliasopt(All)); + // --dependent-libraries + cl::opt + DependentLibraries("dependent-libraries", + cl::desc("Display the dependent libraries section")); + // --headers -e cl::opt Headers("headers", @@ -489,6 +494,8 @@ if (opts::VersionInfo) Dumper->printVersionInfo(); if (Obj->isELF()) { + if (opts::DependentLibraries) + Dumper->printDependentLibs(); if (opts::ELFLinkerOptions) Dumper->printELFLinkerOptions(); if (opts::ArchSpecificInfo)