Index: llvm/trunk/test/Object/corrupt.test =================================================================== --- llvm/trunk/test/Object/corrupt.test +++ llvm/trunk/test/Object/corrupt.test @@ -38,11 +38,11 @@ PHENTSIZE: invalid e_phentsize -RUN: not llvm-readobj --dynamic-table \ +RUN: llvm-readobj --dynamic-table \ RUN: %p/Inputs/corrupt-invalid-virtual-addr.elf.x86-64 2>&1 | \ RUN: FileCheck --check-prefix=VIRTADDR %s -VIRTADDR: Virtual address is not in any segment +VIRTADDR: warning: Unable to parse DT_STRTAB: Virtual address is not in any segment RUN: not llvm-readobj --dyn-relocations \ Index: llvm/trunk/test/Object/invalid.test =================================================================== --- llvm/trunk/test/Object/invalid.test +++ llvm/trunk/test/Object/invalid.test @@ -40,9 +40,6 @@ RUN: not llvm-readobj --symbols %p/Inputs/invalid-sh_entsize.elf 2>&1 | FileCheck --check-prefix=INVALID-SYM-SIZE %s INVALID-SYM-SIZE: invalid sh_entsize -RUN: not llvm-readobj --dyn-symbols %p/Inputs/invalid-sh_entsize.elf 2>&1 | FileCheck --check-prefix=INVALID-DYNSYM-SIZE %s -INVALID-DYNSYM-SIZE: Invalid entity size - RUN: not llvm-readobj --symbols %p/Inputs/invalid-section-index.elf 2>&1 | FileCheck --check-prefix=INVALID-SECTION-INDEX %s INVALID-SECTION-INDEX: invalid section index Index: llvm/trunk/test/tools/llvm-readobj/elf-dynamic-malformed.test =================================================================== --- llvm/trunk/test/tools/llvm-readobj/elf-dynamic-malformed.test +++ llvm/trunk/test/tools/llvm-readobj/elf-dynamic-malformed.test @@ -114,7 +114,8 @@ # RUN: not llvm-readobj --dynamic-table %t.bad-strtab 2>&1 | FileCheck %s --check-prefix BAD-STRTAB # RUN: not llvm-readelf --dynamic-table %t.bad-strtab 2>&1 | FileCheck %s --check-prefix BAD-STRTAB -# BAD-STRTAB: LLVM ERROR: Virtual address is not in any segment +# BAD-STRTAB: warning: Unable to parse DT_STRTAB: Virtual address is not in any segment +# BAD-STRTAB: error: Invalid dynamic string table reference --- !ELF FileHeader: @@ -147,10 +148,19 @@ # Test handling of other d_ptr tags pointing outside the file's address space. # RUN: yaml2obj %s --docnum=5 -o %t.bad-rela -# RUN: not llvm-readobj --dynamic-table %t.bad-rela 2>&1 | FileCheck %s --check-prefix BAD-RELA -# RUN: not llvm-readelf --dynamic-table %t.bad-rela 2>&1 | FileCheck %s --check-prefix BAD-RELA +# RUN: llvm-readobj --dynamic-table %t.bad-rela 2>&1 | FileCheck %s --check-prefixes=CHECK,BAD-RELA +# RUN: llvm-readelf --dynamic-table %t.bad-rela 2>&1 | FileCheck %s --check-prefixes=CHECK,BAD-RELA-GNU -# BAD-RELA: LLVM ERROR: Virtual address is not in any segment +# CHECK: warning: Unable to parse DT_RELA: Virtual address is not in any segment +# BAD-RELA: DynamicSection [ (2 entries) +# BAD-RELA-NEXT: Tag Type Name/Value +# BAD-RELA-NEXT: 0x0000000000000007 RELA 0x1000000 +# BAD-RELA-NEXT: 0x0000000000000000 NULL 0x0 +# BAD-RELA-NEXT: ] +# BAD-RELA-GNU: Dynamic section at offset 0x1f0 contains 2 entries: +# BAD-RELA-GNU-NEXT: Tag Type Name/Value +# BAD-RELA-GNU-NEXT: 0x0000000000000007 (RELA) 0x1000000 +# BAD-RELA-GNU-NEXT: 0x0000000000000000 (NULL) 0x0 --- !ELF FileHeader: Index: llvm/trunk/test/tools/llvm-readobj/elf-dynamic-no-pt-dynamic.test =================================================================== --- llvm/trunk/test/tools/llvm-readobj/elf-dynamic-no-pt-dynamic.test +++ llvm/trunk/test/tools/llvm-readobj/elf-dynamic-no-pt-dynamic.test @@ -1,16 +1,22 @@ -# Show that no dumping occurs if there is no PT_DYNAMIC header. +## Show that dumping occurs even if there is no PT_DYNAMIC header. +## This is inconsistent with the GNU behavior, but seems to be more reasonable. # RUN: yaml2obj %s -o %t.no-phdr # RUN: llvm-readobj --dynamic-table %t.no-phdr | FileCheck %s --check-prefix=LLVM -# RUN: llvm-readelf --dynamic-table %t.no-phdr | FileCheck %s --check-prefix=GNU --allow-empty +# RUN: llvm-readelf --dynamic-table %t.no-phdr | FileCheck %s --check-prefix=GNU # LLVM: File: {{.*}}.no-phdr # LLVM-NEXT: Format: ELF64-x86-64 # LLVM-NEXT: Arch: x86_64 # LLVM-NEXT: AddressSize: 64bit # LLVM-NEXT: LoadName:{{ *}} -# LLVM-NOT: {{.}} +# LLVM-NEXT: DynamicSection [ (1 entries) +# LLVM-NEXT: Tag Type Name/Value +# LLVM-NEXT: 0x0000000000000000 NULL 0x0 +# LLVM-NEXT: ] -# GNU-NOT: {{.}} +# GNU: Dynamic section at offset 0x1b8 contains 1 entries: +# GNU-NEXT: Tag Type Name/Value +# GNU-NEXT: 0x0000000000000000 (NULL) 0x0 --- !ELF FileHeader: Index: llvm/trunk/test/tools/yaml2obj/dynamic-section-raw-content.yaml =================================================================== --- llvm/trunk/test/tools/yaml2obj/dynamic-section-raw-content.yaml +++ llvm/trunk/test/tools/yaml2obj/dynamic-section-raw-content.yaml @@ -10,10 +10,10 @@ # RAW-NEXT: ] # RAW-NEXT: Address: # RAW-NEXT: Offset: -# RAW-NEXT: Size: 5 +# RAW-NEXT: Size: 16 # RAW: Hex dump of section '.dynamic': -# RAW-NEXT: 0x00000000 01234567 89 {{.*}} +# RAW-NEXT: 0x00000000 01234567 89012345 67890000 00000000 {{.*}} # RUN: not yaml2obj --docnum=2 %s -o %t2 2>&1 | FileCheck %s --check-prefix=ERR # ERR: Cannot specify both raw content and explicit entries for dynamic section '.dynamic'. @@ -27,7 +27,7 @@ Sections: - Name: .dynamic Type: SHT_DYNAMIC - Content: "0123456789" + Content: "01234567890123456789000000000000" --- !ELF FileHeader: Index: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp =================================================================== --- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp +++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp @@ -1346,6 +1346,7 @@ template void ELFDumper::loadDynamicTable(const ELFFile *Obj) { + // Try to locate the PT_DYNAMIC header. const Elf_Phdr *DynamicPhdr = nullptr; for (const Elf_Phdr &Phdr : unwrapOrError(Obj->program_headers())) { if (Phdr.p_type != ELF::PT_DYNAMIC) @@ -1354,11 +1355,6 @@ break; } - // We do not want to dump dynamic section if we have no PT_DYNAMIC header. - // This matches GNU's behavior. - if (!DynamicPhdr) - return; - // Try to locate the .dynamic section in the sections header table. const Elf_Shdr *DynamicSec = nullptr; for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { @@ -1373,9 +1369,16 @@ // Ignore sh_entsize and use the expected value for entry size explicitly. // This allows us to dump the dynamic sections with a broken sh_entsize // field. - if (DynamicSec) + if (DynamicSec) { DynamicTable = checkDRI({ObjF->getELFFile()->base() + DynamicSec->sh_offset, DynamicSec->sh_size, sizeof(Elf_Dyn)}); + parseDynamicTable(); + } + + // If we have a PT_DYNAMIC header, we will either check the found dynamic + // section or take the dynamic table data directly from the header. + if (!DynamicPhdr) + return; if (DynamicPhdr->p_offset + DynamicPhdr->p_filesz > ObjF->getMemoryBufferRef().getBufferSize()) @@ -1389,7 +1392,6 @@ } StringRef Name = unwrapOrError(Obj->getSectionName(DynamicSec)); - if (DynamicSec->sh_addr + DynamicSec->sh_size > DynamicPhdr->p_vaddr + DynamicPhdr->p_memsz || DynamicSec->sh_addr < DynamicPhdr->p_vaddr) @@ -1401,8 +1403,6 @@ reportWarning("The SHT_DYNAMIC section '" + Name + "' is not at the start of " "PT_DYNAMIC segment"); - - parseDynamicTable(); } template @@ -1460,11 +1460,71 @@ ELFDumperStyle.reset(new LLVMStyle(Writer, this)); } +static const char *getTypeString(unsigned Arch, uint64_t Type) { +#define DYNAMIC_TAG(n, v) + switch (Arch) { + case EM_HEXAGON: + switch (Type) { +#define HEXAGON_DYNAMIC_TAG(name, value) \ + case DT_##name: \ + return #name; +#include "llvm/BinaryFormat/DynamicTags.def" +#undef HEXAGON_DYNAMIC_TAG + } + break; + + case EM_MIPS: + switch (Type) { +#define MIPS_DYNAMIC_TAG(name, value) \ + case DT_##name: \ + return #name; +#include "llvm/BinaryFormat/DynamicTags.def" +#undef MIPS_DYNAMIC_TAG + } + break; + + case EM_PPC64: + switch (Type) { +#define PPC64_DYNAMIC_TAG(name, value) \ + case DT_##name: \ + return #name; +#include "llvm/BinaryFormat/DynamicTags.def" +#undef PPC64_DYNAMIC_TAG + } + break; + } +#undef DYNAMIC_TAG + switch (Type) { +// Now handle all dynamic tags except the architecture specific ones +#define MIPS_DYNAMIC_TAG(name, value) +#define HEXAGON_DYNAMIC_TAG(name, value) +#define PPC64_DYNAMIC_TAG(name, value) +// Also ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc. +#define DYNAMIC_TAG_MARKER(name, value) +#define DYNAMIC_TAG(name, value) \ + case DT_##name: \ + return #name; +#include "llvm/BinaryFormat/DynamicTags.def" +#undef DYNAMIC_TAG +#undef MIPS_DYNAMIC_TAG +#undef HEXAGON_DYNAMIC_TAG +#undef PPC64_DYNAMIC_TAG +#undef DYNAMIC_TAG_MARKER + default: + return "unknown"; + } +} + template void ELFDumper::parseDynamicTable() { - auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * { + auto toMappedAddr = [&](uint64_t Tag, uint64_t VAddr) -> const uint8_t * { auto MappedAddrOrError = ObjF->getELFFile()->toMappedAddr(VAddr); - if (!MappedAddrOrError) - report_fatal_error(MappedAddrOrError.takeError()); + if (!MappedAddrOrError) { + reportWarning("Unable to parse DT_" + + Twine(getTypeString( + ObjF->getELFFile()->getHeader()->e_machine, Tag)) + + ": " + llvm::toString(MappedAddrOrError.takeError())); + return nullptr; + } return MappedAddrOrError.get(); }; @@ -1474,26 +1534,26 @@ for (const Elf_Dyn &Dyn : dynamic_table()) { switch (Dyn.d_tag) { case ELF::DT_HASH: - HashTable = - reinterpret_cast(toMappedAddr(Dyn.getPtr())); + HashTable = reinterpret_cast( + toMappedAddr(Dyn.getTag(), Dyn.getPtr())); break; case ELF::DT_GNU_HASH: - GnuHashTable = - reinterpret_cast(toMappedAddr(Dyn.getPtr())); + GnuHashTable = reinterpret_cast( + toMappedAddr(Dyn.getTag(), Dyn.getPtr())); break; case ELF::DT_STRTAB: - StringTableBegin = - reinterpret_cast(toMappedAddr(Dyn.getPtr())); + StringTableBegin = reinterpret_cast( + toMappedAddr(Dyn.getTag(), Dyn.getPtr())); break; case ELF::DT_STRSZ: StringTableSize = Dyn.getVal(); break; case ELF::DT_SYMTAB: - DynSymRegion.Addr = toMappedAddr(Dyn.getPtr()); + DynSymRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); DynSymRegion.EntSize = sizeof(Elf_Sym); break; case ELF::DT_RELA: - DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr()); + DynRelaRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); break; case ELF::DT_RELASZ: DynRelaRegion.Size = Dyn.getVal(); @@ -1505,7 +1565,7 @@ SONameOffset = Dyn.getVal(); break; case ELF::DT_REL: - DynRelRegion.Addr = toMappedAddr(Dyn.getPtr()); + DynRelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); break; case ELF::DT_RELSZ: DynRelRegion.Size = Dyn.getVal(); @@ -1515,7 +1575,7 @@ break; case ELF::DT_RELR: case ELF::DT_ANDROID_RELR: - DynRelrRegion.Addr = toMappedAddr(Dyn.getPtr()); + DynRelrRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); break; case ELF::DT_RELRSZ: case ELF::DT_ANDROID_RELRSZ: @@ -1535,7 +1595,7 @@ Twine((uint64_t)Dyn.getVal())); break; case ELF::DT_JMPREL: - DynPLTRelRegion.Addr = toMappedAddr(Dyn.getPtr()); + DynPLTRelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); break; case ELF::DT_PLTRELSZ: DynPLTRelRegion.Size = Dyn.getVal(); @@ -1627,61 +1687,6 @@ ELFDumperStyle->printELFLinkerOptions(ObjF->getELFFile()); } -static const char *getTypeString(unsigned Arch, uint64_t Type) { -#define DYNAMIC_TAG(n, v) - switch (Arch) { - case EM_HEXAGON: - switch (Type) { -#define HEXAGON_DYNAMIC_TAG(name, value) \ - case DT_##name: \ - return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef HEXAGON_DYNAMIC_TAG - } - break; - - case EM_MIPS: - switch (Type) { -#define MIPS_DYNAMIC_TAG(name, value) \ - case DT_##name: \ - return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef MIPS_DYNAMIC_TAG - } - break; - - case EM_PPC64: - switch(Type) { -#define PPC64_DYNAMIC_TAG(name, value) \ - case DT_##name: \ - return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef PPC64_DYNAMIC_TAG - } - break; - } -#undef DYNAMIC_TAG - switch (Type) { -// Now handle all dynamic tags except the architecture specific ones -#define MIPS_DYNAMIC_TAG(name, value) -#define HEXAGON_DYNAMIC_TAG(name, value) -#define PPC64_DYNAMIC_TAG(name, value) -// Also ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc. -#define DYNAMIC_TAG_MARKER(name, value) -#define DYNAMIC_TAG(name, value) \ - case DT_##name: \ - return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef DYNAMIC_TAG -#undef MIPS_DYNAMIC_TAG -#undef HEXAGON_DYNAMIC_TAG -#undef PPC64_DYNAMIC_TAG -#undef DYNAMIC_TAG_MARKER - default: - return "unknown"; - } -} - #define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum) \ { #enum, prefix##_##enum }