Index: test/tools/llvm-objdump/private-headers-dynamic-section.test =================================================================== --- /dev/null +++ test/tools/llvm-objdump/private-headers-dynamic-section.test @@ -0,0 +1,34 @@ +# RUN: llvm-objdump -p %p/Inputs/eh_frame.elf-mipsel | FileCheck %s + +# CHECK: Dynamic Section: +# CHECK: NEEDED libstdc++.so.6 +# CHECK: NEEDED libm.so.6 +# CHECK: NEEDED libgcc_s.so.1 +# CHECK: NEEDED libc.so.6 +# CHECK: INIT 0x00400660 +# CHECK: FINI 0x004009f0 +# CHECK: HASH 0x00400328 +# CHECK: STRTAB 0x0040047c +# CHECK: SYMTAB 0x0040037c +# CHECK: STRSZ 0x00000144 +# CHECK: SYMENT 0x00000010 +# CHECK: 0x70000016 0x00410ba0 +# CHECK: DEBUG 0x00000000 +# CHECK: PLTGOT 0x00410bd0 +# CHECK: REL 0x00400620 +# CHECK: RELSZ 0x00000018 +# CHECK: RELENT 0x00000008 +# CHECK: 0x70000001 0x00000001 +# CHECK: 0x70000005 0x00000002 +# CHECK: 0x70000006 0x00400000 +# CHECK: 0x7000000a 0x00000005 +# CHECK: 0x70000011 0x00000010 +# CHECK: 0x70000012 0x00000025 +# CHECK: 0x70000013 0x0000000e +# CHECK: PLTREL 0x00000011 +# CHECK: JMPREL 0x00400638 +# CHECK: PLTRELSZ 0x00000028 +# CHECK: 0x70000032 0x00410b64 +# CHECK: VERNEED 0x004005e0 +# CHECK: VERNEEDNUM 0x00000002 +# CHECK: VERSYM 0x004005c0 Index: tools/llvm-objdump/ELFDump.cpp =================================================================== --- tools/llvm-objdump/ELFDump.cpp +++ tools/llvm-objdump/ELFDump.cpp @@ -21,10 +21,170 @@ using namespace llvm; using namespace llvm::object; +template +Expected getDynamicStrTab(const ELFFile *o, + const typename ELFFile::Elf_Dyn *Dyn, + uint64_t VirtBase) { + for (; Dyn->d_tag != ELF::DT_NULL; Dyn++) { + if (Dyn->d_tag == ELF::DT_STRTAB) + return StringRef(reinterpret_cast( + o->base() + (Dyn->d_un.d_val - VirtBase))); + } + return createError("string table entry not present"); +} + +template +void printDynamicSection(const ELFFile *o, + const typename ELFFile::Elf_Dyn *Dyn, + uint64_t VirtBase) { + outs() << "Dynamic Section:\n"; + for (; Dyn->d_tag != ELF::DT_NULL; Dyn++) { + char TagValue[11]; + sprintf(TagValue, "0x%x", static_cast(Dyn->d_tag)); + const char *Str = nullptr; + switch (Dyn->d_tag) { + case ELF::DT_NEEDED: + Str = "NEEDED"; + break; + case ELF::DT_PLTRELSZ: + Str = "PLTRELSZ"; + break; + case ELF::DT_PLTGOT: + Str = "PLTGOT"; + break; + case ELF::DT_HASH: + Str = "HASH"; + break; + case ELF::DT_STRTAB: + Str = "STRTAB"; + break; + case ELF::DT_SYMTAB: + Str = "SYMTAB"; + break; + case ELF::DT_RELA: + Str = "RELA"; + break; + case ELF::DT_RELASZ: + Str = "RELASZ"; + break; + case ELF::DT_RELAENT: + Str = "RELAENT"; + break; + case ELF::DT_STRSZ: + Str = "STRSZ"; + break; + case ELF::DT_SYMENT: + Str = "SYMENT"; + break; + case ELF::DT_INIT: + Str = "INIT"; + break; + case ELF::DT_FINI: + Str = "FINI"; + break; + case ELF::DT_SONAME: + Str = "SONAME"; + break; + case ELF::DT_RPATH: + Str = "RPATH"; + break; + case ELF::DT_SYMBOLIC: + Str = "SYMBOLIC"; + break; + case ELF::DT_REL: + Str = "REL"; + break; + case ELF::DT_RELSZ: + Str = "RELSZ"; + break; + case ELF::DT_RELENT: + Str = "RELENT"; + break; + case ELF::DT_PLTREL: + Str = "PLTREL"; + break; + case ELF::DT_DEBUG: + Str = "DEBUG"; + break; + case ELF::DT_TEXTREL: + Str = "TEXTREL"; + break; + case ELF::DT_JMPREL: + Str = "JMPREL"; + break; + case ELF::DT_BIND_NOW: + Str = "BIND_NOW"; + break; + case ELF::DT_INIT_ARRAY: + Str = "INIT_ARRAY"; + break; + case ELF::DT_FINI_ARRAY: + Str = "FINI_ARRAY"; + break; + case ELF::DT_INIT_ARRAYSZ: + Str = "INIT_ARRAYSZ"; + break; + case ELF::DT_FINI_ARRAYSZ: + Str = "FINI_ARRAYSZ"; + break; + case ELF::DT_RUNPATH: + Str = "RUNPATH"; + break; + case ELF::DT_FLAGS: + Str = "FLAGS"; + break; + case ELF::DT_PREINIT_ARRAY: + Str = "PREINIT_ARRAY"; + break; + case ELF::DT_PREINIT_ARRAYSZ: + Str = "PREINIT_ARRAYSZ"; + break; + case ELF::DT_LOOS: + Str = "LOOS"; + break; + case ELF::DT_GNU_HASH: + Str = "GNU_HASH"; + break; + case ELF::DT_TLSDESC_PLT: + Str = "TLSDESC_PLT"; + break; + case ELF::DT_TLSDESC_GOT: + Str = "TLSDESC_GOT"; + break; + case ELF::DT_VERNEEDNUM: + Str = "VERNEEDNUM"; + break; + case ELF::DT_VERSYM: + Str = "VERSYM"; + break; + case ELF::DT_VERNEED: + Str = "VERNEED"; + break; + default: + Str = TagValue; + break; + } + outs() << format(" %-18s", Str); + const char *Fmt = + ELFT::Is64Bits ? "0x%016" PRIx64 "\n" : "0x%08" PRIx64 "\n"; + if (Dyn->d_tag == ELF::DT_NEEDED) { + Expected StrTabOrErr = getDynamicStrTab(o, Dyn, VirtBase); + if (StrTabOrErr) { + const char *Data = StrTabOrErr.get().data(); + outs() << (Data + Dyn->d_un.d_val) << "\n"; + continue; + } + } + outs() << format(Fmt, (uint64_t)Dyn->d_un.d_val); + } +} + template void printProgramHeaders(const ELFFile *o) { typedef ELFFile ELFO; outs() << "Program Header:\n"; auto ProgramHeaderOrError = o->program_headers(); + const typename ELFO::Elf_Dyn *Dyn = nullptr; + uint64_t VirtBase = 0; if (!ProgramHeaderOrError) report_fatal_error( errorToErrorCode(ProgramHeaderOrError.takeError()).message()); @@ -32,6 +192,8 @@ switch (Phdr.p_type) { case ELF::PT_DYNAMIC: outs() << " DYNAMIC "; + Dyn = reinterpret_cast(o->base() + + Phdr.p_offset); break; case ELF::PT_GNU_EH_FRAME: outs() << "EH_FRAME "; @@ -62,6 +224,7 @@ break; case ELF::PT_PHDR: outs() << " PHDR "; + VirtBase = Phdr.p_vaddr - Phdr.p_offset; break; case ELF::PT_TLS: outs() << " TLS "; @@ -84,6 +247,9 @@ << ((Phdr.p_flags & ELF::PF_X) ? "x" : "-") << "\n"; } outs() << "\n"; + + if (Dyn) + printDynamicSection(o, Dyn, VirtBase); } void llvm::printELFFileHeader(const object::ObjectFile *Obj) {