From f06e6564a1554338ca00a4b9c3acdcffa212c743 Mon Sep 17 00:00:00 2001 From: James Henderson Date: Thu, 14 May 2020 13:48:13 +0100 Subject: [PATCH] [llvm-readobj] Implement --dependent-libraries for GNU output Previously, the option was only implemented for LLVM output. This fixes https://bugs.llvm.org/show_bug.cgi?id=45695. At the current time, GNU readelf does not support this option. Consequently, this patch simply attempts to roughly follow the output style for similar options like --syms/--notes etc, combined with --string-dump output. Reviewed by: MaskRay, grimar Differential Revision: https://reviews.llvm.org/D79939 --- .../llvm-readobj/ELF/dependent-libraries.test | 77 ++++++++++--- llvm/tools/llvm-readobj/ELFDumper.cpp | 120 +++++++++++++++------ 2 files changed, 148 insertions(+), 49 deletions(-) diff --git a/llvm/test/tools/llvm-readobj/ELF/dependent-libraries.test b/llvm/test/tools/llvm-readobj/ELF/dependent-libraries.test index 724f108..97f8a75 100644 --- a/llvm/test/tools/llvm-readobj/ELF/dependent-libraries.test +++ b/llvm/test/tools/llvm-readobj/ELF/dependent-libraries.test @@ -5,13 +5,21 @@ ## section with multiple entries. # RUN: yaml2obj --docnum=1 %s -o %t1 -# RUN: llvm-readobj --dependent-libraries %t1 2>&1 | FileCheck %s -DFILE=%t +# RUN: llvm-readobj --dependent-libraries %t1 | \ +# RUN: FileCheck %s --check-prefix=LLVM --strict-whitespace --match-full-lines +# RUN: llvm-readelf --dependent-libraries %t1 | \ +# RUN: FileCheck %s --check-prefix=GNU --strict-whitespace --match-full-lines --implicit-check-not="Dependent libraries" -# CHECK: DependentLibs [ -# CHECK-NEXT: foo -# CHECK-NEXT: bar -# CHECK-NEXT: foo -# CHECK-NEXT: ] +# LLVM:DependentLibs [ +# LLVM-NEXT: foo +# LLVM-NEXT: bar +# LLVM-NEXT: foo +# LLVM-NEXT:] + +# GNU:Dependent libraries section .deplibs at offset 0x40 contains 3 entries: +# GNU-NEXT: [ 0] foo +# GNU-NEXT: [ 4] bar +# GNU-NEXT: [ 8] foo --- !ELF FileHeader: @@ -27,15 +35,36 @@ Sections: ## 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 +# RUN: llvm-readobj --dependent-libraries %t2 2>&1 | FileCheck %s --check-prefix=MIX-LLVM -DFILE=%t2 +# RUN: llvm-readelf --dependent-libraries %t2 2>&1 | FileCheck %s --check-prefix=MIX-GNU -DFILE=%t2 + +# MIX-LLVM: DependentLibs [ +# MIX-LLVM-NEXT: warning: '[[FILE]]': SHT_LLVM_DEPENDENT_LIBRARIES section at index 1 is broken: the content is not null-terminated +# MIX-LLVM-NEXT: abc +# MIX-LLVM-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 (0x308) +# MIX-LLVM-NEXT: bar +# MIX-LLVM-NEXT: xxx +# MIX-LLVM-NEXT: baz +# MIX-LLVM-NEXT: ] -# MIX: DependentLibs [ -# MIX-NEXT: warning: '[[FILE]]': SHT_LLVM_DEPENDENT_LIBRARIES section at index 1 is broken: the content is not null-terminated -# MIX-NEXT: abc -# 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: ] +# MIX-GNU: warning: '[[FILE]]': SHT_LLVM_DEPENDENT_LIBRARIES section at index 1 is broken: the content is not null-terminated +# MIX-GNU-NEXT: Dependent libraries section .deplibs.nonul at offset 0x40 contains 0 entries: +# MIX-GNU-EMPTY: +# MIX-GNU-NEXT: Dependent libraries section .deplibs.single at offset 0x43 contains 1 entries: +# MIX-GNU-NEXT: [ 0] abc +# MIX-GNU-EMPTY: +# MIX-GNU-NEXT: Dependent libraries section .deplibs.empty at offset 0x47 contains 0 entries: +# MIX-GNU-EMPTY: +# MIX-GNU-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 (0x308) +# MIX-GNU-NEXT: Dependent libraries section .deplibs.broken.shoffset at offset 0xffff0000 contains 0 entries: +# MIX-GNU-EMPTY: +# MIX-GNU-NEXT: Dependent libraries section .deplibs.multiple at offset 0x4b contains 2 entries: +# MIX-GNU-NEXT: [ 0] bar +# MIX-GNU-NEXT: [ 4] xxx +# MIX-GNU-EMPTY: +# MIX-GNU-NEXT: warning: '[[FILE]]': cannot get section name of SHT_LLVM_DEPENDENT_LIBRARIES section: a section [index 6] has an invalid sh_name (0x10000) offset which goes past the end of the section name string table +# MIX-GNU-NEXT: Dependent libraries section at offset 0x53 contains 1 entries: +# MIX-GNU-NEXT: [ 0] baz --- !ELF FileHeader: @@ -65,8 +94,22 @@ Sections: - Name: .deplibs.multiple Type: SHT_LLVM_DEPENDENT_LIBRARIES Libraries: [ bar, xxx ] +## Case 6: test we report a warning in GNU mode if the section name can't be read. + - ShName: 0x10000 + Type: SHT_LLVM_DEPENDENT_LIBRARIES + Libraries: [ baz ] -## llvm-readelf doesn't support --dependent-libraries yet. -# RUN: llvm-readelf --dependent-libraries %t1 2>&1 | FileCheck %s --check-prefix=READELF +## Show the output when there are no dependent library sections. +# RUN: yaml2obj --docnum=3 %s -o %t3 +# RUN: llvm-readobj --dependent-libraries %t3 2>&1 | FileCheck %s --check-prefix=NONE +# RUN: llvm-readelf --dependent-libraries %t3 2>&1 | FileCheck %s --allow-empty --implicit-check-not={{.}} -# READELF: printDependentLibs not implemented! +# NONE: DependentLibs [ +# NONE-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 21ba0f0..a0ac37a 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -767,6 +767,11 @@ public: const ELFDumper *dumper() const { return Dumper; } protected: + void printDependentLibsHelper( + const ELFFile *Obj, + function_ref OnSectionStart, + function_ref OnSectionEntry); + void reportUniqueWarning(Error Err) const; StringRef FileName; @@ -5311,8 +5316,87 @@ void GNUStyle::printELFLinkerOptions(const ELFFile *Obj) { } template +void DumpStyle::printDependentLibsHelper( + const ELFFile *Obj, + function_ref OnSectionStart, + function_ref OnLibEntry) { + 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; + + OnSectionStart(Shdr); + + 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); + OnLibEntry(Lib, I - Contents.begin()); + I += Lib.size() + 1; + } + } +} + +template void GNUStyle::printDependentLibs(const ELFFile *Obj) { - OS << "printDependentLibs not implemented!\n"; + bool SectionStarted = false; + struct NameOffset { + StringRef Name; + uint64_t Offset; + }; + std::vector SecEntries; + NameOffset Current; + auto PrintSection = [&]() { + OS << "Dependent libraries section " << Current.Name << " at offset " + << format_hex(Current.Offset, 1) << " contains " << SecEntries.size() + << " entries:\n"; + for (NameOffset Entry : SecEntries) + OS << " [" << format("%6tx", Entry.Offset) << "] " << Entry.Name + << "\n"; + OS << "\n"; + SecEntries.clear(); + }; + + auto OnSectionStart = [&](const Elf_Shdr &Shdr) { + if (SectionStarted) + PrintSection(); + SectionStarted = true; + Current.Offset = Shdr.sh_offset; + Expected Name = Obj->getSectionName(&Shdr); + if (!Name) { + Current.Name = ""; + this->reportUniqueWarning( + createError("cannot get section name of " + "SHT_LLVM_DEPENDENT_LIBRARIES section: " + + toString(Name.takeError()))); + } else { + Current.Name = *Name; + } + }; + auto OnLibEntry = [&](StringRef Lib, uint64_t Offset) { + SecEntries.push_back(NameOffset{Lib, Offset}); + }; + + printDependentLibsHelper(Obj, OnSectionStart, OnLibEntry); + if (SectionStarted) + PrintSection(); } // Used for printing section names in places where possible errors can be @@ -6582,37 +6666,9 @@ void LLVMStyle::printELFLinkerOptions(const ELFFile *Obj) { 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; - } - } + printDependentLibsHelper( + Obj, [](const Elf_Shdr &) {}, + [this](StringRef Lib, uint64_t) { W.printString(Lib); }); } template -- 2.7.4