[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
This commit is contained in:
James Henderson 2020-05-14 13:48:13 +01:00
parent 151ed6aa38
commit f06e6564a1
2 changed files with 148 additions and 49 deletions
llvm
test/tools/llvm-readobj/ELF
tools/llvm-readobj

View File

@ -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: 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-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-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

View File

@ -767,6 +767,11 @@ public:
const ELFDumper<ELFT> *dumper() const { return Dumper; }
protected:
void printDependentLibsHelper(
const ELFFile<ELFT> *Obj,
function_ref<void(const Elf_Shdr &)> OnSectionStart,
function_ref<void(StringRef, uint64_t)> OnSectionEntry);
void reportUniqueWarning(Error Err) const;
StringRef FileName;
@ -5310,9 +5315,88 @@ void GNUStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) {
OS << "printELFLinkerOptions not implemented!\n";
}
template <class ELFT>
void DumpStyle<ELFT>::printDependentLibsHelper(
const ELFFile<ELFT> *Obj,
function_ref<void(const Elf_Shdr &)> OnSectionStart,
function_ref<void(StringRef, uint64_t)> 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<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(&Shdr);
if (!ContentsOrErr) {
Warn(I, toString(ContentsOrErr.takeError()));
continue;
}
ArrayRef<uint8_t> 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 <class ELFT>
void GNUStyle<ELFT>::printDependentLibs(const ELFFile<ELFT> *Obj) {
OS << "printDependentLibs not implemented!\n";
bool SectionStarted = false;
struct NameOffset {
StringRef Name;
uint64_t Offset;
};
std::vector<NameOffset> 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<StringRef> 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<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) {
template <class ELFT>
void LLVMStyle<ELFT>::printDependentLibs(const ELFFile<ELFT> *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<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(&Shdr);
if (!ContentsOrErr) {
Warn(I, toString(ContentsOrErr.takeError()));
continue;
}
ArrayRef<uint8_t> 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 <class ELFT>