Michael J. Spencer | 209565db | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 1 | //===-- ELFDump.cpp - ELF-specific dumper -----------------------*- C++ -*-===// |
| 2 | // |
Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
Michael J. Spencer | 209565db | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | /// |
| 9 | /// \file |
Adrian Prantl | 5f8f34e4 | 2018-05-01 15:54:18 +0000 | [diff] [blame] | 10 | /// This file implements the ELF-specific dumper for llvm-objdump. |
Michael J. Spencer | 209565db | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 11 | /// |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "llvm-objdump.h" |
George Rimar | c196488 | 2019-01-18 11:33:26 +0000 | [diff] [blame] | 15 | #include "llvm/Demangle/Demangle.h" |
Michael J. Spencer | 126973b | 2013-08-08 22:27:13 +0000 | [diff] [blame] | 16 | #include "llvm/Object/ELFObjectFile.h" |
Michael J. Spencer | 209565db | 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 | 0913dcd | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 24 | template <class ELFT> |
| 25 | Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT> *Elf) { |
Paul Semel | 0913dcd | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 26 | auto DynamicEntriesOrError = Elf->dynamicEntries(); |
| 27 | if (!DynamicEntriesOrError) |
| 28 | return DynamicEntriesOrError.takeError(); |
| 29 | |
Fangrui Song | 454a7bb | 2019-04-07 08:28:56 +0000 | [diff] [blame] | 30 | for (const typename ELFT::Dyn &Dyn : *DynamicEntriesOrError) { |
Paul Semel | 0913dcd | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 31 | if (Dyn.d_tag == ELF::DT_STRTAB) { |
| 32 | auto MappedAddrOrError = Elf->toMappedAddr(Dyn.getPtr()); |
| 33 | if (!MappedAddrOrError) |
| 34 | consumeError(MappedAddrOrError.takeError()); |
| 35 | return StringRef(reinterpret_cast<const char *>(*MappedAddrOrError)); |
| 36 | } |
| 37 | } |
| 38 | |
| 39 | // If the dynamic segment is not present, we fall back on the sections. |
| 40 | auto SectionsOrError = Elf->sections(); |
| 41 | if (!SectionsOrError) |
| 42 | return SectionsOrError.takeError(); |
| 43 | |
Fangrui Song | 454a7bb | 2019-04-07 08:28:56 +0000 | [diff] [blame] | 44 | for (const typename ELFT::Shdr &Sec : *SectionsOrError) { |
Paul Semel | 0913dcd | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 45 | if (Sec.sh_type == ELF::SHT_DYNSYM) |
| 46 | return Elf->getStringTableForSymtab(Sec); |
| 47 | } |
| 48 | |
| 49 | return createError("dynamic string table not found"); |
| 50 | } |
| 51 | |
| 52 | template <class ELFT> |
Fangrui Song | f67de6c | 2019-04-08 16:24:08 +0000 | [diff] [blame^] | 53 | static Error getRelocationValueString(const ELFObjectFile<ELFT> *Obj, |
| 54 | const RelocationRef &RelRef, |
| 55 | SmallVectorImpl<char> &Result) { |
George Rimar | c196488 | 2019-01-18 11:33:26 +0000 | [diff] [blame] | 56 | const ELFFile<ELFT> &EF = *Obj->getELFFile(); |
| 57 | DataRefImpl Rel = RelRef.getRawDataRefImpl(); |
| 58 | auto SecOrErr = EF.getSection(Rel.d.a); |
| 59 | if (!SecOrErr) |
Fangrui Song | f67de6c | 2019-04-08 16:24:08 +0000 | [diff] [blame^] | 60 | return SecOrErr.takeError(); |
George Rimar | c196488 | 2019-01-18 11:33:26 +0000 | [diff] [blame] | 61 | |
| 62 | int64_t Addend = 0; |
| 63 | // If there is no Symbol associated with the relocation, we set the undef |
| 64 | // boolean value to 'true'. This will prevent us from calling functions that |
| 65 | // requires the relocation to be associated with a symbol. |
| 66 | // |
| 67 | // In SHT_REL case we would need to read the addend from section data. |
| 68 | // GNU objdump does not do that and we just follow for simplicity atm. |
| 69 | bool Undef = false; |
| 70 | if ((*SecOrErr)->sh_type == ELF::SHT_RELA) { |
Fangrui Song | af7314b | 2019-04-07 08:29:04 +0000 | [diff] [blame] | 71 | const typename ELFT::Rela *ERela = Obj->getRela(Rel); |
George Rimar | c196488 | 2019-01-18 11:33:26 +0000 | [diff] [blame] | 72 | Addend = ERela->r_addend; |
| 73 | Undef = ERela->getSymbol(false) == 0; |
| 74 | } else if ((*SecOrErr)->sh_type != ELF::SHT_REL) { |
Fangrui Song | f67de6c | 2019-04-08 16:24:08 +0000 | [diff] [blame^] | 75 | return make_error<BinaryError>(); |
George Rimar | c196488 | 2019-01-18 11:33:26 +0000 | [diff] [blame] | 76 | } |
| 77 | |
| 78 | // Default scheme is to print Target, as well as "+ <addend>" for nonzero |
| 79 | // addend. Should be acceptable for all normal purposes. |
| 80 | std::string FmtBuf; |
| 81 | raw_string_ostream Fmt(FmtBuf); |
| 82 | |
| 83 | if (!Undef) { |
| 84 | symbol_iterator SI = RelRef.getSymbol(); |
Fangrui Song | 454a7bb | 2019-04-07 08:28:56 +0000 | [diff] [blame] | 85 | const typename ELFT::Sym *Sym = Obj->getSymbol(SI->getRawDataRefImpl()); |
George Rimar | c196488 | 2019-01-18 11:33:26 +0000 | [diff] [blame] | 86 | if (Sym->getType() == ELF::STT_SECTION) { |
| 87 | Expected<section_iterator> SymSI = SI->getSection(); |
| 88 | if (!SymSI) |
Fangrui Song | f67de6c | 2019-04-08 16:24:08 +0000 | [diff] [blame^] | 89 | return SymSI.takeError(); |
Fangrui Song | 454a7bb | 2019-04-07 08:28:56 +0000 | [diff] [blame] | 90 | const typename ELFT::Shdr *SymSec = |
| 91 | Obj->getSection((*SymSI)->getRawDataRefImpl()); |
George Rimar | c196488 | 2019-01-18 11:33:26 +0000 | [diff] [blame] | 92 | auto SecName = EF.getSectionName(SymSec); |
| 93 | if (!SecName) |
Fangrui Song | f67de6c | 2019-04-08 16:24:08 +0000 | [diff] [blame^] | 94 | return SecName.takeError(); |
George Rimar | c196488 | 2019-01-18 11:33:26 +0000 | [diff] [blame] | 95 | Fmt << *SecName; |
| 96 | } else { |
| 97 | Expected<StringRef> SymName = SI->getName(); |
| 98 | if (!SymName) |
Fangrui Song | f67de6c | 2019-04-08 16:24:08 +0000 | [diff] [blame^] | 99 | return SymName.takeError(); |
George Rimar | c196488 | 2019-01-18 11:33:26 +0000 | [diff] [blame] | 100 | if (Demangle) |
| 101 | Fmt << demangle(*SymName); |
| 102 | else |
| 103 | Fmt << *SymName; |
| 104 | } |
| 105 | } else { |
| 106 | Fmt << "*ABS*"; |
| 107 | } |
| 108 | |
| 109 | if (Addend != 0) |
| 110 | Fmt << (Addend < 0 ? "" : "+") << Addend; |
| 111 | Fmt.flush(); |
| 112 | Result.append(FmtBuf.begin(), FmtBuf.end()); |
Fangrui Song | f67de6c | 2019-04-08 16:24:08 +0000 | [diff] [blame^] | 113 | return Error::success(); |
George Rimar | c196488 | 2019-01-18 11:33:26 +0000 | [diff] [blame] | 114 | } |
| 115 | |
Fangrui Song | f67de6c | 2019-04-08 16:24:08 +0000 | [diff] [blame^] | 116 | Error llvm::getELFRelocationValueString(const ELFObjectFileBase *Obj, |
| 117 | const RelocationRef &Rel, |
| 118 | SmallVectorImpl<char> &Result) { |
George Rimar | c196488 | 2019-01-18 11:33:26 +0000 | [diff] [blame] | 119 | if (auto *ELF32LE = dyn_cast<ELF32LEObjectFile>(Obj)) |
| 120 | return getRelocationValueString(ELF32LE, Rel, Result); |
| 121 | if (auto *ELF64LE = dyn_cast<ELF64LEObjectFile>(Obj)) |
| 122 | return getRelocationValueString(ELF64LE, Rel, Result); |
| 123 | if (auto *ELF32BE = dyn_cast<ELF32BEObjectFile>(Obj)) |
| 124 | return getRelocationValueString(ELF32BE, Rel, Result); |
| 125 | auto *ELF64BE = cast<ELF64BEObjectFile>(Obj); |
| 126 | return getRelocationValueString(ELF64BE, Rel, Result); |
| 127 | } |
| 128 | |
| 129 | template <class ELFT> |
George Rimar | 87fa2e6 | 2019-01-28 14:11:35 +0000 | [diff] [blame] | 130 | static uint64_t getSectionLMA(const ELFFile<ELFT> *Obj, |
| 131 | const object::ELFSectionRef &Sec) { |
| 132 | auto PhdrRangeOrErr = Obj->program_headers(); |
| 133 | if (!PhdrRangeOrErr) |
| 134 | report_fatal_error(errorToErrorCode(PhdrRangeOrErr.takeError()).message()); |
| 135 | |
| 136 | // Search for a PT_LOAD segment containing the requested section. Use this |
| 137 | // segment's p_addr to calculate the section's LMA. |
Fangrui Song | af7314b | 2019-04-07 08:29:04 +0000 | [diff] [blame] | 138 | for (const typename ELFT::Phdr &Phdr : *PhdrRangeOrErr) |
George Rimar | 87fa2e6 | 2019-01-28 14:11:35 +0000 | [diff] [blame] | 139 | if ((Phdr.p_type == ELF::PT_LOAD) && (Phdr.p_vaddr <= Sec.getAddress()) && |
| 140 | (Phdr.p_vaddr + Phdr.p_memsz > Sec.getAddress())) |
| 141 | return Sec.getAddress() - Phdr.p_vaddr + Phdr.p_paddr; |
| 142 | |
| 143 | // Return section's VMA if it isn't in a PT_LOAD segment. |
| 144 | return Sec.getAddress(); |
| 145 | } |
| 146 | |
| 147 | uint64_t llvm::getELFSectionLMA(const object::ELFSectionRef &Sec) { |
| 148 | if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Sec.getObject())) |
| 149 | return getSectionLMA(ELFObj->getELFFile(), Sec); |
| 150 | else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Sec.getObject())) |
| 151 | return getSectionLMA(ELFObj->getELFFile(), Sec); |
| 152 | else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Sec.getObject())) |
| 153 | return getSectionLMA(ELFObj->getELFFile(), Sec); |
| 154 | const auto *ELFObj = cast<ELF64BEObjectFile>(Sec.getObject()); |
| 155 | return getSectionLMA(ELFObj->getELFFile(), Sec); |
| 156 | } |
| 157 | |
| 158 | template <class ELFT> |
Paul Semel | 0913dcd | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 159 | void printDynamicSection(const ELFFile<ELFT> *Elf, StringRef Filename) { |
Fangrui Song | e7834bd | 2019-04-07 08:19:55 +0000 | [diff] [blame] | 160 | ArrayRef<typename ELFT::Dyn> DynamicEntries = |
| 161 | unwrapOrError(Elf->dynamicEntries(), Filename); |
Paul Semel | 0913dcd | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 162 | outs() << "Dynamic Section:\n"; |
Fangrui Song | e7834bd | 2019-04-07 08:19:55 +0000 | [diff] [blame] | 163 | for (const typename ELFT::Dyn &Dyn : DynamicEntries) { |
Paul Semel | 0913dcd | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 164 | if (Dyn.d_tag == ELF::DT_NULL) |
| 165 | continue; |
| 166 | |
Xing GUO | b285878 | 2019-03-02 04:20:28 +0000 | [diff] [blame] | 167 | std::string Str = Elf->getDynamicTagAsString(Dyn.d_tag); |
| 168 | outs() << format(" %-21s", Str.c_str()); |
Paul Semel | 0913dcd | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 169 | |
| 170 | const char *Fmt = |
| 171 | ELFT::Is64Bits ? "0x%016" PRIx64 "\n" : "0x%08" PRIx64 "\n"; |
Xing GUO | d78164a | 2019-02-27 16:37:15 +0000 | [diff] [blame] | 172 | if (Dyn.d_tag == ELF::DT_NEEDED || Dyn.d_tag == ELF::DT_RPATH || |
| 173 | Dyn.d_tag == ELF::DT_RUNPATH || Dyn.d_tag == ELF::DT_SONAME || |
| 174 | Dyn.d_tag == ELF::DT_AUXILIARY || Dyn.d_tag == ELF::DT_FILTER) { |
Paul Semel | 0913dcd | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 175 | Expected<StringRef> StrTabOrErr = getDynamicStrTab(Elf); |
| 176 | if (StrTabOrErr) { |
| 177 | const char *Data = StrTabOrErr.get().data(); |
| 178 | outs() << (Data + Dyn.d_un.d_val) << "\n"; |
| 179 | continue; |
| 180 | } |
| 181 | warn(errorToErrorCode(StrTabOrErr.takeError()).message()); |
| 182 | consumeError(StrTabOrErr.takeError()); |
| 183 | } |
| 184 | outs() << format(Fmt, (uint64_t)Dyn.d_un.d_val); |
| 185 | } |
| 186 | } |
| 187 | |
Michael J. Spencer | 126973b | 2013-08-08 22:27:13 +0000 | [diff] [blame] | 188 | template <class ELFT> void printProgramHeaders(const ELFFile<ELFT> *o) { |
Michael J. Spencer | 209565db | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 189 | outs() << "Program Header:\n"; |
Rafael Espindola | 6a49497 | 2016-11-03 17:28:33 +0000 | [diff] [blame] | 190 | auto ProgramHeaderOrError = o->program_headers(); |
Davide Italiano | 6cf0926 | 2016-11-16 05:10:28 +0000 | [diff] [blame] | 191 | if (!ProgramHeaderOrError) |
| 192 | report_fatal_error( |
| 193 | errorToErrorCode(ProgramHeaderOrError.takeError()).message()); |
Fangrui Song | 454a7bb | 2019-04-07 08:28:56 +0000 | [diff] [blame] | 194 | for (const typename ELFT::Phdr &Phdr : *ProgramHeaderOrError) { |
Rafael Espindola | 073624b | 2015-07-20 13:35:33 +0000 | [diff] [blame] | 195 | switch (Phdr.p_type) { |
Ed Maste | 178a4e5 | 2016-12-24 14:53:45 +0000 | [diff] [blame] | 196 | case ELF::PT_DYNAMIC: |
| 197 | outs() << " DYNAMIC "; |
Michael J. Spencer | 209565db | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 198 | break; |
| 199 | case ELF::PT_GNU_EH_FRAME: |
| 200 | outs() << "EH_FRAME "; |
| 201 | break; |
Davide Italiano | cad1927 | 2017-01-16 22:58:26 +0000 | [diff] [blame] | 202 | case ELF::PT_GNU_RELRO: |
| 203 | outs() << " RELRO "; |
| 204 | break; |
Ed Maste | 178a4e5 | 2016-12-24 14:53:45 +0000 | [diff] [blame] | 205 | case ELF::PT_GNU_STACK: |
| 206 | outs() << " STACK "; |
| 207 | break; |
Michael J. Spencer | 1366a61 | 2013-02-20 20:18:10 +0000 | [diff] [blame] | 208 | case ELF::PT_INTERP: |
| 209 | outs() << " INTERP "; |
| 210 | break; |
Ed Maste | 178a4e5 | 2016-12-24 14:53:45 +0000 | [diff] [blame] | 211 | case ELF::PT_LOAD: |
| 212 | outs() << " LOAD "; |
Michael J. Spencer | 1366a61 | 2013-02-20 20:18:10 +0000 | [diff] [blame] | 213 | break; |
Davide Italiano | eb9ad98 | 2017-01-16 23:13:46 +0000 | [diff] [blame] | 214 | case ELF::PT_NOTE: |
| 215 | outs() << " NOTE "; |
| 216 | break; |
Davide Italiano | 6cc726e | 2017-01-16 22:01:41 +0000 | [diff] [blame] | 217 | case ELF::PT_OPENBSD_BOOTDATA: |
| 218 | outs() << " OPENBSD_BOOTDATA "; |
| 219 | break; |
| 220 | case ELF::PT_OPENBSD_RANDOMIZE: |
| 221 | outs() << " OPENBSD_RANDOMIZE "; |
| 222 | break; |
| 223 | case ELF::PT_OPENBSD_WXNEEDED: |
| 224 | outs() << " OPENBSD_WXNEEDED "; |
| 225 | break; |
Michael J. Spencer | ed82095 | 2013-02-21 02:21:29 +0000 | [diff] [blame] | 226 | case ELF::PT_PHDR: |
| 227 | outs() << " PHDR "; |
| 228 | break; |
Shankar Easwaran | e0bdc94 | 2013-02-27 17:57:17 +0000 | [diff] [blame] | 229 | case ELF::PT_TLS: |
| 230 | outs() << " TLS "; |
| 231 | break; |
Michael J. Spencer | 209565db | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 232 | default: |
| 233 | outs() << " UNKNOWN "; |
| 234 | } |
| 235 | |
Michael J. Spencer | 1a79161 | 2013-01-15 07:44:25 +0000 | [diff] [blame] | 236 | const char *Fmt = ELFT::Is64Bits ? "0x%016" PRIx64 " " : "0x%08" PRIx64 " "; |
Michael J. Spencer | 6acf814 | 2013-01-06 05:23:59 +0000 | [diff] [blame] | 237 | |
Rafael Espindola | 073624b | 2015-07-20 13:35:33 +0000 | [diff] [blame] | 238 | outs() << "off " << format(Fmt, (uint64_t)Phdr.p_offset) << "vaddr " |
| 239 | << format(Fmt, (uint64_t)Phdr.p_vaddr) << "paddr " |
| 240 | << format(Fmt, (uint64_t)Phdr.p_paddr) |
| 241 | << format("align 2**%u\n", |
| 242 | countTrailingZeros<uint64_t>(Phdr.p_align)) |
| 243 | << " filesz " << format(Fmt, (uint64_t)Phdr.p_filesz) |
| 244 | << "memsz " << format(Fmt, (uint64_t)Phdr.p_memsz) << "flags " |
| 245 | << ((Phdr.p_flags & ELF::PF_R) ? "r" : "-") |
| 246 | << ((Phdr.p_flags & ELF::PF_W) ? "w" : "-") |
| 247 | << ((Phdr.p_flags & ELF::PF_X) ? "x" : "-") << "\n"; |
Michael J. Spencer | 209565db | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 248 | } |
| 249 | outs() << "\n"; |
| 250 | } |
| 251 | |
Xing GUO | 56d651d | 2019-02-25 13:13:19 +0000 | [diff] [blame] | 252 | template <class ELFT> |
| 253 | void printSymbolVersionDependency(ArrayRef<uint8_t> Contents, |
| 254 | StringRef StrTab) { |
Xing GUO | 56d651d | 2019-02-25 13:13:19 +0000 | [diff] [blame] | 255 | outs() << "Version References:\n"; |
| 256 | |
| 257 | const uint8_t *Buf = Contents.data(); |
| 258 | while (Buf) { |
Fangrui Song | 454a7bb | 2019-04-07 08:28:56 +0000 | [diff] [blame] | 259 | auto *Verneed = reinterpret_cast<const typename ELFT::Verneed *>(Buf); |
Xing GUO | 56d651d | 2019-02-25 13:13:19 +0000 | [diff] [blame] | 260 | outs() << " required from " |
| 261 | << StringRef(StrTab.drop_front(Verneed->vn_file).data()) << ":\n"; |
| 262 | |
| 263 | const uint8_t *BufAux = Buf + Verneed->vn_aux; |
| 264 | while (BufAux) { |
Fangrui Song | 454a7bb | 2019-04-07 08:28:56 +0000 | [diff] [blame] | 265 | auto *Vernaux = reinterpret_cast<const typename ELFT::Vernaux *>(BufAux); |
Xing GUO | 56d651d | 2019-02-25 13:13:19 +0000 | [diff] [blame] | 266 | outs() << " " |
| 267 | << format("0x%08" PRIx32 " ", (uint32_t)Vernaux->vna_hash) |
| 268 | << format("0x%02" PRIx16 " ", (uint16_t)Vernaux->vna_flags) |
| 269 | << format("%02" PRIu16 " ", (uint16_t)Vernaux->vna_other) |
| 270 | << StringRef(StrTab.drop_front(Vernaux->vna_name).data()) << '\n'; |
| 271 | BufAux = Vernaux->vna_next ? BufAux + Vernaux->vna_next : nullptr; |
| 272 | } |
| 273 | Buf = Verneed->vn_next ? Buf + Verneed->vn_next : nullptr; |
| 274 | } |
| 275 | } |
| 276 | |
| 277 | template <class ELFT> |
Xing GUO | 85b50a7 | 2019-02-26 13:06:16 +0000 | [diff] [blame] | 278 | void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr, |
| 279 | ArrayRef<uint8_t> Contents, |
| 280 | StringRef StrTab) { |
Xing GUO | 85b50a7 | 2019-02-26 13:06:16 +0000 | [diff] [blame] | 281 | outs() << "Version definitions:\n"; |
| 282 | |
| 283 | const uint8_t *Buf = Contents.data(); |
| 284 | uint32_t VerdefIndex = 1; |
| 285 | // sh_info contains the number of entries in the SHT_GNU_verdef section. To |
| 286 | // make the index column have consistent width, we should insert blank spaces |
| 287 | // according to sh_info. |
| 288 | uint16_t VerdefIndexWidth = std::to_string(Shdr.sh_info).size(); |
| 289 | while (Buf) { |
Fangrui Song | af7314b | 2019-04-07 08:29:04 +0000 | [diff] [blame] | 290 | auto *Verdef = reinterpret_cast<const typename ELFT::Verdef *>(Buf); |
Xing GUO | 85b50a7 | 2019-02-26 13:06:16 +0000 | [diff] [blame] | 291 | outs() << format_decimal(VerdefIndex++, VerdefIndexWidth) << " " |
| 292 | << format("0x%02" PRIx16 " ", (uint16_t)Verdef->vd_flags) |
| 293 | << format("0x%08" PRIx32 " ", (uint32_t)Verdef->vd_hash); |
| 294 | |
| 295 | const uint8_t *BufAux = Buf + Verdef->vd_aux; |
| 296 | uint16_t VerdauxIndex = 0; |
| 297 | while (BufAux) { |
Fangrui Song | af7314b | 2019-04-07 08:29:04 +0000 | [diff] [blame] | 298 | auto *Verdaux = reinterpret_cast<const typename ELFT::Verdaux *>(BufAux); |
Xing GUO | 85b50a7 | 2019-02-26 13:06:16 +0000 | [diff] [blame] | 299 | if (VerdauxIndex) |
| 300 | outs() << std::string(VerdefIndexWidth + 17, ' '); |
| 301 | outs() << StringRef(StrTab.drop_front(Verdaux->vda_name).data()) << '\n'; |
| 302 | BufAux = Verdaux->vda_next ? BufAux + Verdaux->vda_next : nullptr; |
| 303 | ++VerdauxIndex; |
| 304 | } |
| 305 | Buf = Verdef->vd_next ? Buf + Verdef->vd_next : nullptr; |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | template <class ELFT> |
Xing GUO | 56d651d | 2019-02-25 13:13:19 +0000 | [diff] [blame] | 310 | void printSymbolVersionInfo(const ELFFile<ELFT> *Elf, StringRef FileName) { |
Fangrui Song | e7834bd | 2019-04-07 08:19:55 +0000 | [diff] [blame] | 311 | ArrayRef<typename ELFT::Shdr> Sections = |
| 312 | unwrapOrError(Elf->sections(), FileName); |
| 313 | for (const typename ELFT::Shdr &Shdr : Sections) { |
Xing GUO | 85b50a7 | 2019-02-26 13:06:16 +0000 | [diff] [blame] | 314 | if (Shdr.sh_type != ELF::SHT_GNU_verneed && |
| 315 | Shdr.sh_type != ELF::SHT_GNU_verdef) |
Xing GUO | 56d651d | 2019-02-25 13:13:19 +0000 | [diff] [blame] | 316 | continue; |
| 317 | |
Fangrui Song | e7834bd | 2019-04-07 08:19:55 +0000 | [diff] [blame] | 318 | ArrayRef<uint8_t> Contents = |
| 319 | unwrapOrError(Elf->getSectionContents(&Shdr), FileName); |
| 320 | const typename ELFT::Shdr *StrTabSec = |
| 321 | unwrapOrError(Elf->getSection(Shdr.sh_link), FileName); |
| 322 | StringRef StrTab = unwrapOrError(Elf->getStringTable(StrTabSec), FileName); |
Xing GUO | 56d651d | 2019-02-25 13:13:19 +0000 | [diff] [blame] | 323 | |
Xing GUO | 85b50a7 | 2019-02-26 13:06:16 +0000 | [diff] [blame] | 324 | if (Shdr.sh_type == ELF::SHT_GNU_verneed) |
Fangrui Song | e7834bd | 2019-04-07 08:19:55 +0000 | [diff] [blame] | 325 | printSymbolVersionDependency<ELFT>(Contents, StrTab); |
Xing GUO | 85b50a7 | 2019-02-26 13:06:16 +0000 | [diff] [blame] | 326 | else |
Fangrui Song | e7834bd | 2019-04-07 08:19:55 +0000 | [diff] [blame] | 327 | printSymbolVersionDefinition<ELFT>(Shdr, Contents, StrTab); |
Xing GUO | 56d651d | 2019-02-25 13:13:19 +0000 | [diff] [blame] | 328 | } |
| 329 | } |
| 330 | |
Michael J. Spencer | 209565db | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 331 | void llvm::printELFFileHeader(const object::ObjectFile *Obj) { |
Xing GUO | cc0829f | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 332 | if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) |
Michael J. Spencer | 126973b | 2013-08-08 22:27:13 +0000 | [diff] [blame] | 333 | printProgramHeaders(ELFObj->getELFFile()); |
Xing GUO | cc0829f | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 334 | else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) |
Michael J. Spencer | 126973b | 2013-08-08 22:27:13 +0000 | [diff] [blame] | 335 | printProgramHeaders(ELFObj->getELFFile()); |
Xing GUO | cc0829f | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 336 | else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) |
Michael J. Spencer | 126973b | 2013-08-08 22:27:13 +0000 | [diff] [blame] | 337 | printProgramHeaders(ELFObj->getELFFile()); |
Xing GUO | cc0829f | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 338 | else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) |
Michael J. Spencer | 126973b | 2013-08-08 22:27:13 +0000 | [diff] [blame] | 339 | printProgramHeaders(ELFObj->getELFFile()); |
Michael J. Spencer | 209565db | 2013-01-06 03:56:49 +0000 | [diff] [blame] | 340 | } |
Paul Semel | 0913dcd | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 341 | |
| 342 | void llvm::printELFDynamicSection(const object::ObjectFile *Obj) { |
Xing GUO | cc0829f | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 343 | if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) |
Paul Semel | 0913dcd | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 344 | printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); |
Xing GUO | cc0829f | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 345 | else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) |
Paul Semel | 0913dcd | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 346 | printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); |
Xing GUO | cc0829f | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 347 | else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) |
Paul Semel | 0913dcd | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 348 | printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); |
Xing GUO | cc0829f | 2018-11-15 11:51:13 +0000 | [diff] [blame] | 349 | else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) |
Paul Semel | 0913dcd | 2018-07-25 11:09:20 +0000 | [diff] [blame] | 350 | printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); |
| 351 | } |
Xing GUO | 56d651d | 2019-02-25 13:13:19 +0000 | [diff] [blame] | 352 | |
| 353 | void llvm::printELFSymbolVersionInfo(const object::ObjectFile *Obj) { |
| 354 | if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) |
| 355 | printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); |
| 356 | else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) |
| 357 | printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); |
| 358 | else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) |
| 359 | printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); |
| 360 | else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) |
| 361 | printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); |
| 362 | } |