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