Michael J. Spencer | b2c064c | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 1 | //===-- ELFDump.cpp - ELF-specific dumper -----------------------*- C++ -*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | /// |
| 10 | /// \file |
Adrian Prantl | 26b584c | 2018-05-01 15:54:18 +0000 | [diff] [blame] | 11 | /// This file implements the ELF-specific dumper for llvm-objdump. |
Michael J. Spencer | b2c064c | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 12 | /// |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #include "llvm-objdump.h" |
Michael J. Spencer | 081a194 | 2013-08-08 22:27:13 +0000 | [diff] [blame] | 16 | #include "llvm/Object/ELFObjectFile.h" |
Michael J. Spencer | b2c064c | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 17 | #include "llvm/Support/Format.h" |
| 18 | #include "llvm/Support/MathExtras.h" |
| 19 | #include "llvm/Support/raw_ostream.h" |
| 20 | |
| 21 | using namespace llvm; |
| 22 | using namespace llvm::object; |
| 23 | |
Paul Semel | 05d358b | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 24 | template <class ELFT> |
| 25 | Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT> *Elf) { |
| 26 | typedef ELFFile<ELFT> ELFO; |
| 27 | |
| 28 | auto DynamicEntriesOrError = Elf->dynamicEntries(); |
| 29 | if (!DynamicEntriesOrError) |
| 30 | return DynamicEntriesOrError.takeError(); |
| 31 | |
| 32 | for (const typename ELFO::Elf_Dyn &Dyn : *DynamicEntriesOrError) { |
| 33 | if (Dyn.d_tag == ELF::DT_STRTAB) { |
| 34 | auto MappedAddrOrError = Elf->toMappedAddr(Dyn.getPtr()); |
| 35 | if (!MappedAddrOrError) |
| 36 | consumeError(MappedAddrOrError.takeError()); |
| 37 | return StringRef(reinterpret_cast<const char *>(*MappedAddrOrError)); |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | // If the dynamic segment is not present, we fall back on the sections. |
| 42 | auto SectionsOrError = Elf->sections(); |
| 43 | if (!SectionsOrError) |
| 44 | return SectionsOrError.takeError(); |
| 45 | |
| 46 | for (const typename ELFO::Elf_Shdr &Sec : *SectionsOrError) { |
| 47 | if (Sec.sh_type == ELF::SHT_DYNSYM) |
| 48 | return Elf->getStringTableForSymtab(Sec); |
| 49 | } |
| 50 | |
| 51 | return createError("dynamic string table not found"); |
| 52 | } |
| 53 | |
| 54 | template <class ELFT> |
| 55 | void printDynamicSection(const ELFFile<ELFT> *Elf, StringRef Filename) { |
| 56 | auto ProgramHeaderOrError = Elf->program_headers(); |
| 57 | if (!ProgramHeaderOrError) |
| 58 | report_error(Filename, ProgramHeaderOrError.takeError()); |
| 59 | |
| 60 | auto DynamicEntriesOrError = Elf->dynamicEntries(); |
| 61 | if (!DynamicEntriesOrError) |
| 62 | report_error(Filename, DynamicEntriesOrError.takeError()); |
| 63 | |
| 64 | outs() << "Dynamic Section:\n"; |
| 65 | for (const auto &Dyn : *DynamicEntriesOrError) { |
| 66 | if (Dyn.d_tag == ELF::DT_NULL) |
| 67 | continue; |
| 68 | |
| 69 | StringRef Str = StringRef(Elf->getDynamicTagAsString(Dyn.d_tag)); |
| 70 | |
| 71 | if (Str.empty()) { |
| 72 | std::string HexStr = utohexstr(static_cast<uint64_t>(Dyn.d_tag), true); |
| 73 | outs() << format(" 0x%-19s", HexStr.c_str()); |
| 74 | } else { |
| 75 | // We use "-21" in order to match GNU objdump's output. |
| 76 | outs() << format(" %-21s", Str.data()); |
| 77 | } |
| 78 | |
| 79 | const char *Fmt = |
| 80 | ELFT::Is64Bits ? "0x%016" PRIx64 "\n" : "0x%08" PRIx64 "\n"; |
| 81 | if (Dyn.d_tag == ELF::DT_NEEDED) { |
| 82 | Expected<StringRef> StrTabOrErr = getDynamicStrTab(Elf); |
| 83 | if (StrTabOrErr) { |
| 84 | const char *Data = StrTabOrErr.get().data(); |
| 85 | outs() << (Data + Dyn.d_un.d_val) << "\n"; |
| 86 | continue; |
| 87 | } |
| 88 | warn(errorToErrorCode(StrTabOrErr.takeError()).message()); |
| 89 | consumeError(StrTabOrErr.takeError()); |
| 90 | } |
| 91 | outs() << format(Fmt, (uint64_t)Dyn.d_un.d_val); |
| 92 | } |
| 93 | } |
| 94 | |
Michael J. Spencer | 081a194 | 2013-08-08 22:27:13 +0000 | [diff] [blame] | 95 | template <class ELFT> void printProgramHeaders(const ELFFile<ELFT> *o) { |
| 96 | typedef ELFFile<ELFT> ELFO; |
Michael J. Spencer | b2c064c | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 97 | outs() << "Program Header:\n"; |
Rafael Espindola | 7446318 | 2016-11-03 17:28:33 +0000 | [diff] [blame] | 98 | auto ProgramHeaderOrError = o->program_headers(); |
Davide Italiano | 63830bc | 2016-11-16 05:10:28 +0000 | [diff] [blame] | 99 | if (!ProgramHeaderOrError) |
| 100 | report_fatal_error( |
| 101 | errorToErrorCode(ProgramHeaderOrError.takeError()).message()); |
Rafael Espindola | 7446318 | 2016-11-03 17:28:33 +0000 | [diff] [blame] | 102 | for (const typename ELFO::Elf_Phdr &Phdr : *ProgramHeaderOrError) { |
Rafael Espindola | 9a4133e | 2015-07-20 13:35:33 +0000 | [diff] [blame] | 103 | switch (Phdr.p_type) { |
Ed Maste | 82c36cf | 2016-12-24 14:53:45 +0000 | [diff] [blame] | 104 | case ELF::PT_DYNAMIC: |
| 105 | outs() << " DYNAMIC "; |
Michael J. Spencer | b2c064c | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 106 | break; |
| 107 | case ELF::PT_GNU_EH_FRAME: |
| 108 | outs() << "EH_FRAME "; |
| 109 | break; |
Davide Italiano | d871b20 | 2017-01-16 22:58:26 +0000 | [diff] [blame] | 110 | case ELF::PT_GNU_RELRO: |
| 111 | outs() << " RELRO "; |
| 112 | break; |
Ed Maste | 82c36cf | 2016-12-24 14:53:45 +0000 | [diff] [blame] | 113 | case ELF::PT_GNU_STACK: |
| 114 | outs() << " STACK "; |
| 115 | break; |
Michael J. Spencer | 8a3a1de | 2013-02-20 20:18:10 +0000 | [diff] [blame] | 116 | case ELF::PT_INTERP: |
| 117 | outs() << " INTERP "; |
| 118 | break; |
Ed Maste | 82c36cf | 2016-12-24 14:53:45 +0000 | [diff] [blame] | 119 | case ELF::PT_LOAD: |
| 120 | outs() << " LOAD "; |
Michael J. Spencer | 8a3a1de | 2013-02-20 20:18:10 +0000 | [diff] [blame] | 121 | break; |
Davide Italiano | d97e732 | 2017-01-16 23:13:46 +0000 | [diff] [blame] | 122 | case ELF::PT_NOTE: |
| 123 | outs() << " NOTE "; |
| 124 | break; |
Davide Italiano | 9101096 | 2017-01-16 22:01:41 +0000 | [diff] [blame] | 125 | case ELF::PT_OPENBSD_BOOTDATA: |
| 126 | outs() << " OPENBSD_BOOTDATA "; |
| 127 | break; |
| 128 | case ELF::PT_OPENBSD_RANDOMIZE: |
| 129 | outs() << " OPENBSD_RANDOMIZE "; |
| 130 | break; |
| 131 | case ELF::PT_OPENBSD_WXNEEDED: |
| 132 | outs() << " OPENBSD_WXNEEDED "; |
| 133 | break; |
Michael J. Spencer | 5618230 | 2013-02-21 02:21:29 +0000 | [diff] [blame] | 134 | case ELF::PT_PHDR: |
| 135 | outs() << " PHDR "; |
| 136 | break; |
Shankar Easwaran | 512685d | 2013-02-27 17:57:17 +0000 | [diff] [blame] | 137 | case ELF::PT_TLS: |
| 138 | outs() << " TLS "; |
| 139 | break; |
Michael J. Spencer | b2c064c | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 140 | default: |
| 141 | outs() << " UNKNOWN "; |
| 142 | } |
| 143 | |
Michael J. Spencer | ac97f5c | 2013-01-15 07:44:25 +0000 | [diff] [blame] | 144 | const char *Fmt = ELFT::Is64Bits ? "0x%016" PRIx64 " " : "0x%08" PRIx64 " "; |
Michael J. Spencer | 4641879 | 2013-01-06 05:23:59 +0000 | [diff] [blame] | 145 | |
Rafael Espindola | 9a4133e | 2015-07-20 13:35:33 +0000 | [diff] [blame] | 146 | outs() << "off " << format(Fmt, (uint64_t)Phdr.p_offset) << "vaddr " |
| 147 | << format(Fmt, (uint64_t)Phdr.p_vaddr) << "paddr " |
| 148 | << format(Fmt, (uint64_t)Phdr.p_paddr) |
| 149 | << format("align 2**%u\n", |
| 150 | countTrailingZeros<uint64_t>(Phdr.p_align)) |
| 151 | << " filesz " << format(Fmt, (uint64_t)Phdr.p_filesz) |
| 152 | << "memsz " << format(Fmt, (uint64_t)Phdr.p_memsz) << "flags " |
| 153 | << ((Phdr.p_flags & ELF::PF_R) ? "r" : "-") |
| 154 | << ((Phdr.p_flags & ELF::PF_W) ? "w" : "-") |
| 155 | << ((Phdr.p_flags & ELF::PF_X) ? "x" : "-") << "\n"; |
Michael J. Spencer | b2c064c | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 156 | } |
| 157 | outs() << "\n"; |
| 158 | } |
| 159 | |
| 160 | void llvm::printELFFileHeader(const object::ObjectFile *Obj) { |
Xing GUO | 84a656e | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 161 | if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) |
Michael J. Spencer | 081a194 | 2013-08-08 22:27:13 +0000 | [diff] [blame] | 162 | printProgramHeaders(ELFObj->getELFFile()); |
Xing GUO | 84a656e | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 163 | else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) |
Michael J. Spencer | 081a194 | 2013-08-08 22:27:13 +0000 | [diff] [blame] | 164 | printProgramHeaders(ELFObj->getELFFile()); |
Xing GUO | 84a656e | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 165 | else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) |
Michael J. Spencer | 081a194 | 2013-08-08 22:27:13 +0000 | [diff] [blame] | 166 | printProgramHeaders(ELFObj->getELFFile()); |
Xing GUO | 84a656e | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 167 | else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) |
Michael J. Spencer | 081a194 | 2013-08-08 22:27:13 +0000 | [diff] [blame] | 168 | printProgramHeaders(ELFObj->getELFFile()); |
Michael J. Spencer | b2c064c | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 169 | } |
Paul Semel | 05d358b | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 170 | |
| 171 | void llvm::printELFDynamicSection(const object::ObjectFile *Obj) { |
Xing GUO | 84a656e | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 172 | if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) |
Paul Semel | 05d358b | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 173 | printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); |
Xing GUO | 84a656e | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 174 | else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) |
Paul Semel | 05d358b | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 175 | printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); |
Xing GUO | 84a656e | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 176 | else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) |
Paul Semel | 05d358b | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 177 | printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); |
Xing GUO | 84a656e | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 178 | else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) |
Paul Semel | 05d358b | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 179 | printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); |
| 180 | } |