From 7b4fce12b35bf89db45cbc13329146c58d156b53 Mon Sep 17 00:00:00 2001 From: George Rimar Date: Thu, 28 Feb 2019 08:15:59 +0000 Subject: [PATCH] [llvm-readobj] - Fix the invalid dumping of the dynamic sections without terminating DT_NULL entry. This is https://bugs.llvm.org/show_bug.cgi?id=40861, Previously llvm-readobj would print the DT_NULL sometimes for the dynamic section that has no terminator entry. The logic of printDynamicTable was a bit overcomplicated. I rewrote it slightly to fix the issue and commented. Differential revision: https://reviews.llvm.org/D58716 llvm-svn: 355073 --- .../tools/llvm-readobj/elf-dynamic-table-dtnull.s | 78 ++++++++++++++++++++++ llvm/tools/llvm-readobj/ELFDumper.cpp | 32 ++++----- 2 files changed, 91 insertions(+), 19 deletions(-) create mode 100644 llvm/test/tools/llvm-readobj/elf-dynamic-table-dtnull.s diff --git a/llvm/test/tools/llvm-readobj/elf-dynamic-table-dtnull.s b/llvm/test/tools/llvm-readobj/elf-dynamic-table-dtnull.s new file mode 100644 index 0000000..8bb8d05 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/elf-dynamic-table-dtnull.s @@ -0,0 +1,78 @@ +# Check we are able to dump the dynamic section without a DT_NULL entry correctly. + +# RUN: yaml2obj -docnum=1 %s -o %t.o +# RUN: llvm-readobj --dynamic-table %t.o | FileCheck %s --check-prefix=NONULL +# RUN: llvm-readelf --dynamic-table %t.o | FileCheck %s --check-prefix=NONULL + +# NONULL: DynamicSection [ (1 entries) +# NONULL-NEXT: Tag Type Name/Value +# NONULL-NEXT: 0x0000000000000015 DEBUG 0x0 +# NONULL-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .dynamic + Type: SHT_DYNAMIC + Address: 0x0000000000001010 + AddressAlign: 0x0000000000000010 + EntSize: 0x0000000000000010 + Entries: + - Tag: DT_DEBUG + Value: 0x0000000000000000 +ProgramHeaders: + - Type: PT_LOAD + VAddr: 0x1000 + Sections: + - Section: .dynamic + - Type: PT_DYNAMIC + VAddr: 0x1010 + Sections: + - Section: .dynamic + +# Sometimes .dynamic section content length can be greater than the +# length of its entries. In this case, we should not try to dump anything +# past the DT_NULL entry, which works as a terminator. + +# RUN: yaml2obj -docnum=2 %s -o %t.o +# RUN: llvm-readobj --dynamic-table %t.o | FileCheck %s --check-prefix=LONG +# RUN: llvm-readelf --dynamic-table %t.o | FileCheck %s --check-prefix=LONG + +# LONG: DynamicSection [ (2 entries) +# LONG-NEXT: Tag Type Name/Value +# LONG-NEXT: 0x0000000000000015 DEBUG 0x0 +# LONG-NEXT: 0x0000000000000000 NULL 0x0 +# LONG-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .dynamic + Type: SHT_DYNAMIC + Address: 0x0000000000001010 + AddressAlign: 0x0000000000000010 + EntSize: 0x0000000000000010 + Entries: + - Tag: DT_DEBUG + Value: 0x0000000000000000 + - Tag: DT_NULL + Value: 0x0000000000000000 + - Tag: DT_NULL + Value: 0x0000000000000000 +ProgramHeaders: + - Type: PT_LOAD + VAddr: 0x1000 + Sections: + - Section: .dynamic + - Type: PT_DYNAMIC + VAddr: 0x1010 + Sections: + - Section: .dynamic diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 3597acf..410ab3f 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -1914,35 +1914,29 @@ template <> void ELFDumper::printUnwindInfo() { template void ELFDumper::printDynamicTable() { - auto I = dynamic_table().begin(); - auto E = dynamic_table().end(); - - if (I == E) - return; - - --E; - while (I != E && E->getTag() == ELF::DT_NULL) - --E; - if (E->getTag() != ELF::DT_NULL) - ++E; - ++E; + // A valid .dynamic section contains an array of entries terminated with + // a DT_NULL entry. However, sometimes the section content may continue + // past the DT_NULL entry, so to dump the section correctly, we first find + // the end of the entries by iterating over them. + size_t Size = 0; + Elf_Dyn_Range DynTableEntries = dynamic_table(); + for (; Size < DynTableEntries.size();) + if (DynTableEntries[Size++].getTag() == DT_NULL) + break; - ptrdiff_t Total = std::distance(I, E); - if (Total == 0) + if (!Size) return; raw_ostream &OS = W.getOStream(); - W.startLine() << "DynamicSection [ (" << Total << " entries)\n"; + W.startLine() << "DynamicSection [ (" << Size << " entries)\n"; bool Is64 = ELFT::Is64Bits; - W.startLine() << " Tag" << (Is64 ? " " : " ") << "Type" << " " << "Name/Value\n"; - while (I != E) { - const Elf_Dyn &Entry = *I; + for (size_t I = 0; I < Size; ++I) { + const Elf_Dyn &Entry = DynTableEntries[I]; uintX_t Tag = Entry.getTag(); - ++I; W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, opts::Output != opts::GNU) << " " << format("%-21s", getTypeString(ObjF->getELFFile()->getHeader()->e_machine, Tag)); printValue(Tag, Entry.getVal()); -- 2.7.4