648 lines · c
1//===--- ARMEHABIPrinter.h - ARM EHABI Unwind Information Printer ----------===//2//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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_TOOLS_LLVM_READOBJ_ARMEHABIPRINTER_H10#define LLVM_TOOLS_LLVM_READOBJ_ARMEHABIPRINTER_H11 12#include "llvm-readobj.h"13#include "llvm/ADT/STLExtras.h"14#include "llvm/Object/ELF.h"15#include "llvm/Object/ELFTypes.h"16#include "llvm/Support/ARMEHABI.h"17#include "llvm/Support/Debug.h"18#include "llvm/Support/Endian.h"19#include "llvm/Support/Format.h"20#include "llvm/Support/ScopedPrinter.h"21#include "llvm/Support/type_traits.h"22 23namespace llvm {24namespace ARM {25namespace EHABI {26 27class OpcodeDecoder {28 ScopedPrinter &SW;29 raw_ostream &OS;30 31 struct RingEntry {32 uint8_t Mask;33 uint8_t Value;34 void (OpcodeDecoder::*Routine)(const uint8_t *Opcodes, unsigned &OI);35 };36 static ArrayRef<RingEntry> ring();37 38 void Decode_00xxxxxx(const uint8_t *Opcodes, unsigned &OI);39 void Decode_01xxxxxx(const uint8_t *Opcodes, unsigned &OI);40 void Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes, unsigned &OI);41 void Decode_10011101(const uint8_t *Opcodes, unsigned &OI);42 void Decode_10011111(const uint8_t *Opcodes, unsigned &OI);43 void Decode_1001nnnn(const uint8_t *Opcodes, unsigned &OI);44 void Decode_10100nnn(const uint8_t *Opcodes, unsigned &OI);45 void Decode_10101nnn(const uint8_t *Opcodes, unsigned &OI);46 void Decode_10110000(const uint8_t *Opcodes, unsigned &OI);47 void Decode_10110001_0000iiii(const uint8_t *Opcodes, unsigned &OI);48 void Decode_10110010_uleb128(const uint8_t *Opcodes, unsigned &OI);49 void Decode_10110011_sssscccc(const uint8_t *Opcodes, unsigned &OI);50 void Decode_101101nn(const uint8_t *Opcodes, unsigned &OI);51 void Decode_10111nnn(const uint8_t *Opcodes, unsigned &OI);52 void Decode_11000110_sssscccc(const uint8_t *Opcodes, unsigned &OI);53 void Decode_11000111_0000iiii(const uint8_t *Opcodes, unsigned &OI);54 void Decode_11001000_sssscccc(const uint8_t *Opcodes, unsigned &OI);55 void Decode_11001001_sssscccc(const uint8_t *Opcodes, unsigned &OI);56 void Decode_11001yyy(const uint8_t *Opcodes, unsigned &OI);57 void Decode_11000nnn(const uint8_t *Opcodes, unsigned &OI);58 void Decode_11010nnn(const uint8_t *Opcodes, unsigned &OI);59 void Decode_11xxxyyy(const uint8_t *Opcodes, unsigned &OI);60 61 void PrintGPR(uint16_t GPRMask);62 void PrintRegisters(uint32_t Mask, StringRef Prefix);63 64public:65 OpcodeDecoder(ScopedPrinter &SW) : SW(SW), OS(SW.getOStream()) {}66 void Decode(const uint8_t *Opcodes, off_t Offset, size_t Length);67};68 69inline ArrayRef<OpcodeDecoder::RingEntry> OpcodeDecoder::ring() {70 static const OpcodeDecoder::RingEntry Ring[] = {71 {0xc0, 0x00, &OpcodeDecoder::Decode_00xxxxxx},72 {0xc0, 0x40, &OpcodeDecoder::Decode_01xxxxxx},73 {0xf0, 0x80, &OpcodeDecoder::Decode_1000iiii_iiiiiiii},74 {0xff, 0x9d, &OpcodeDecoder::Decode_10011101},75 {0xff, 0x9f, &OpcodeDecoder::Decode_10011111},76 {0xf0, 0x90, &OpcodeDecoder::Decode_1001nnnn},77 {0xf8, 0xa0, &OpcodeDecoder::Decode_10100nnn},78 {0xf8, 0xa8, &OpcodeDecoder::Decode_10101nnn},79 {0xff, 0xb0, &OpcodeDecoder::Decode_10110000},80 {0xff, 0xb1, &OpcodeDecoder::Decode_10110001_0000iiii},81 {0xff, 0xb2, &OpcodeDecoder::Decode_10110010_uleb128},82 {0xff, 0xb3, &OpcodeDecoder::Decode_10110011_sssscccc},83 {0xfc, 0xb4, &OpcodeDecoder::Decode_101101nn},84 {0xf8, 0xb8, &OpcodeDecoder::Decode_10111nnn},85 {0xff, 0xc6, &OpcodeDecoder::Decode_11000110_sssscccc},86 {0xff, 0xc7, &OpcodeDecoder::Decode_11000111_0000iiii},87 {0xff, 0xc8, &OpcodeDecoder::Decode_11001000_sssscccc},88 {0xff, 0xc9, &OpcodeDecoder::Decode_11001001_sssscccc},89 {0xc8, 0xc8, &OpcodeDecoder::Decode_11001yyy},90 {0xf8, 0xc0, &OpcodeDecoder::Decode_11000nnn},91 {0xf8, 0xd0, &OpcodeDecoder::Decode_11010nnn},92 {0xc0, 0xc0, &OpcodeDecoder::Decode_11xxxyyy},93 };94 return ArrayRef(Ring);95}96 97inline void OpcodeDecoder::Decode_00xxxxxx(const uint8_t *Opcodes,98 unsigned &OI) {99 uint8_t Opcode = Opcodes[OI++ ^ 3];100 SW.startLine() << format("0x%02X ; vsp = vsp + %u\n", Opcode,101 ((Opcode & 0x3f) << 2) + 4);102}103inline void OpcodeDecoder::Decode_01xxxxxx(const uint8_t *Opcodes,104 unsigned &OI) {105 uint8_t Opcode = Opcodes[OI++ ^ 3];106 SW.startLine() << format("0x%02X ; vsp = vsp - %u\n", Opcode,107 ((Opcode & 0x3f) << 2) + 4);108}109inline void OpcodeDecoder::Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes,110 unsigned &OI) {111 uint8_t Opcode0 = Opcodes[OI++ ^ 3];112 uint8_t Opcode1 = Opcodes[OI++ ^ 3];113 114 uint16_t GPRMask = (Opcode1 << 4) | ((Opcode0 & 0x0f) << 12);115 SW.startLine()116 << format("0x%02X 0x%02X ; %s",117 Opcode0, Opcode1, GPRMask ? "pop " : "refuse to unwind");118 if (GPRMask)119 PrintGPR(GPRMask);120 OS << '\n';121}122inline void OpcodeDecoder::Decode_10011101(const uint8_t *Opcodes,123 unsigned &OI) {124 uint8_t Opcode = Opcodes[OI++ ^ 3];125 SW.startLine() << format("0x%02X ; reserved (ARM MOVrr)\n", Opcode);126}127inline void OpcodeDecoder::Decode_10011111(const uint8_t *Opcodes,128 unsigned &OI) {129 uint8_t Opcode = Opcodes[OI++ ^ 3];130 SW.startLine() << format("0x%02X ; reserved (WiMMX MOVrr)\n", Opcode);131}132inline void OpcodeDecoder::Decode_1001nnnn(const uint8_t *Opcodes,133 unsigned &OI) {134 uint8_t Opcode = Opcodes[OI++ ^ 3];135 SW.startLine() << format("0x%02X ; vsp = r%u\n", Opcode, (Opcode & 0x0f));136}137inline void OpcodeDecoder::Decode_10100nnn(const uint8_t *Opcodes,138 unsigned &OI) {139 uint8_t Opcode = Opcodes[OI++ ^ 3];140 SW.startLine() << format("0x%02X ; pop ", Opcode);141 PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4));142 OS << '\n';143}144inline void OpcodeDecoder::Decode_10101nnn(const uint8_t *Opcodes,145 unsigned &OI) {146 uint8_t Opcode = Opcodes[OI++ ^ 3];147 SW.startLine() << format("0x%02X ; pop ", Opcode);148 PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4) | (1 << 14));149 OS << '\n';150}151inline void OpcodeDecoder::Decode_10110000(const uint8_t *Opcodes,152 unsigned &OI) {153 uint8_t Opcode = Opcodes[OI++ ^ 3];154 SW.startLine() << format("0x%02X ; finish\n", Opcode);155}156inline void OpcodeDecoder::Decode_10110001_0000iiii(const uint8_t *Opcodes,157 unsigned &OI) {158 uint8_t Opcode0 = Opcodes[OI++ ^ 3];159 uint8_t Opcode1 = Opcodes[OI++ ^ 3];160 161 SW.startLine() << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1,162 (Opcode1 & 0xf0) ? "spare" : "pop ");163 if (((Opcode1 & 0xf0) == 0x00) && Opcode1)164 PrintGPR((Opcode1 & 0x0f));165 OS << '\n';166}167inline void OpcodeDecoder::Decode_10110010_uleb128(const uint8_t *Opcodes,168 unsigned &OI) {169 uint8_t Opcode = Opcodes[OI++ ^ 3];170 SW.startLine() << format("0x%02X ", Opcode);171 172 SmallVector<uint8_t, 4> ULEB;173 do { ULEB.push_back(Opcodes[OI ^ 3]); } while (Opcodes[OI++ ^ 3] & 0x80);174 175 for (unsigned BI = 0, BE = ULEB.size(); BI != BE; ++BI)176 OS << format("0x%02X ", ULEB[BI]);177 178 uint64_t Value = 0;179 for (unsigned BI = 0, BE = ULEB.size(); BI != BE; ++BI)180 Value = Value | ((ULEB[BI] & 0x7f) << (7 * BI));181 182 OS << format("; vsp = vsp + %" PRIu64 "\n", 0x204 + (Value << 2));183}184inline void OpcodeDecoder::Decode_10110011_sssscccc(const uint8_t *Opcodes,185 unsigned &OI) {186 uint8_t Opcode0 = Opcodes[OI++ ^ 3];187 uint8_t Opcode1 = Opcodes[OI++ ^ 3];188 SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);189 uint8_t Start = ((Opcode1 & 0xf0) >> 4);190 uint8_t Count = ((Opcode1 & 0x0f) >> 0);191 PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d");192 OS << '\n';193}194inline void OpcodeDecoder::Decode_101101nn(const uint8_t *Opcodes,195 unsigned &OI) {196 uint8_t Opcode = Opcodes[OI++ ^ 3];197 SW.startLine() << format("0x%02X ; %s\n", Opcode,198 (Opcode == 0xb4) ? "pop ra_auth_code" : "spare");199}200inline void OpcodeDecoder::Decode_10111nnn(const uint8_t *Opcodes,201 unsigned &OI) {202 uint8_t Opcode = Opcodes[OI++ ^ 3];203 SW.startLine() << format("0x%02X ; pop ", Opcode);204 PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d");205 OS << '\n';206}207inline void OpcodeDecoder::Decode_11000110_sssscccc(const uint8_t *Opcodes,208 unsigned &OI) {209 uint8_t Opcode0 = Opcodes[OI++ ^ 3];210 uint8_t Opcode1 = Opcodes[OI++ ^ 3];211 SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);212 uint8_t Start = ((Opcode1 & 0xf0) >> 4);213 uint8_t Count = ((Opcode1 & 0x0f) >> 0);214 PrintRegisters((((1 << (Count + 1)) - 1) << Start), "wR");215 OS << '\n';216}217inline void OpcodeDecoder::Decode_11000111_0000iiii(const uint8_t *Opcodes,218 unsigned &OI) {219 uint8_t Opcode0 = Opcodes[OI++ ^ 3];220 uint8_t Opcode1 = Opcodes[OI++ ^ 3];221 SW.startLine()222 << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1,223 ((Opcode1 & 0xf0) || Opcode1 == 0x00) ? "spare" : "pop ");224 if ((Opcode1 & 0xf0) == 0x00 && Opcode1)225 PrintRegisters(Opcode1 & 0x0f, "wCGR");226 OS << '\n';227}228inline void OpcodeDecoder::Decode_11001000_sssscccc(const uint8_t *Opcodes,229 unsigned &OI) {230 uint8_t Opcode0 = Opcodes[OI++ ^ 3];231 uint8_t Opcode1 = Opcodes[OI++ ^ 3];232 SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);233 uint8_t Start = 16 + ((Opcode1 & 0xf0) >> 4);234 uint8_t Count = ((Opcode1 & 0x0f) >> 0);235 PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d");236 OS << '\n';237}238inline void OpcodeDecoder::Decode_11001001_sssscccc(const uint8_t *Opcodes,239 unsigned &OI) {240 uint8_t Opcode0 = Opcodes[OI++ ^ 3];241 uint8_t Opcode1 = Opcodes[OI++ ^ 3];242 SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1);243 uint8_t Start = ((Opcode1 & 0xf0) >> 4);244 uint8_t Count = ((Opcode1 & 0x0f) >> 0);245 PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d");246 OS << '\n';247}248inline void OpcodeDecoder::Decode_11001yyy(const uint8_t *Opcodes,249 unsigned &OI) {250 uint8_t Opcode = Opcodes[OI++ ^ 3];251 SW.startLine() << format("0x%02X ; spare\n", Opcode);252}253inline void OpcodeDecoder::Decode_11000nnn(const uint8_t *Opcodes,254 unsigned &OI) {255 uint8_t Opcode = Opcodes[OI++ ^ 3];256 SW.startLine() << format("0x%02X ; pop ", Opcode);257 PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 10), "wR");258 OS << '\n';259}260inline void OpcodeDecoder::Decode_11010nnn(const uint8_t *Opcodes,261 unsigned &OI) {262 uint8_t Opcode = Opcodes[OI++ ^ 3];263 SW.startLine() << format("0x%02X ; pop ", Opcode);264 PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d");265 OS << '\n';266}267inline void OpcodeDecoder::Decode_11xxxyyy(const uint8_t *Opcodes,268 unsigned &OI) {269 uint8_t Opcode = Opcodes[OI++ ^ 3];270 SW.startLine() << format("0x%02X ; spare\n", Opcode);271}272 273inline void OpcodeDecoder::PrintGPR(uint16_t GPRMask) {274 static const char *GPRRegisterNames[16] = {275 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",276 "fp", "ip", "sp", "lr", "pc"277 };278 279 OS << '{';280 bool Comma = false;281 for (unsigned RI = 0, RE = 17; RI < RE; ++RI) {282 if (GPRMask & (1 << RI)) {283 if (Comma)284 OS << ", ";285 OS << GPRRegisterNames[RI];286 Comma = true;287 }288 }289 OS << '}';290}291 292inline void OpcodeDecoder::PrintRegisters(uint32_t VFPMask, StringRef Prefix) {293 OS << '{';294 bool Comma = false;295 for (unsigned RI = 0, RE = 32; RI < RE; ++RI) {296 if (VFPMask & (1 << RI)) {297 if (Comma)298 OS << ", ";299 OS << Prefix << RI;300 Comma = true;301 }302 }303 OS << '}';304}305 306inline void OpcodeDecoder::Decode(const uint8_t *Opcodes, off_t Offset,307 size_t Length) {308 for (unsigned OCI = Offset; OCI < Length + Offset; ) {309 bool Decoded = false;310 for (const auto &RE : ring()) {311 if ((Opcodes[OCI ^ 3] & RE.Mask) == RE.Value) {312 (this->*RE.Routine)(Opcodes, OCI);313 Decoded = true;314 break;315 }316 }317 if (!Decoded)318 SW.startLine() << format("0x%02X ; reserved\n", Opcodes[OCI++ ^ 3]);319 }320}321 322template <typename ET>323class PrinterContext {324 typedef typename ET::Sym Elf_Sym;325 typedef typename ET::Shdr Elf_Shdr;326 typedef typename ET::Rel Elf_Rel;327 typedef typename ET::Word Elf_Word;328 329 ScopedPrinter &SW;330 const object::ELFFile<ET> &ELF;331 StringRef FileName;332 const Elf_Shdr *Symtab;333 ArrayRef<Elf_Word> ShndxTable;334 335 static const size_t IndexTableEntrySize;336 337 static uint64_t PREL31(uint32_t Address, uint32_t Place) {338 uint64_t Location = Address & 0x7fffffff;339 if (Location & 0x40000000)340 Location |= (uint64_t) ~0x7fffffff;341 return Location + Place;342 }343 344 ErrorOr<StringRef>345 FunctionAtAddress(uint64_t Address,346 std::optional<unsigned> SectionIndex) const;347 const Elf_Shdr *FindExceptionTable(unsigned IndexTableIndex,348 off_t IndexTableOffset) const;349 350 void PrintIndexTable(unsigned SectionIndex, const Elf_Shdr *IT) const;351 void PrintExceptionTable(const Elf_Shdr &EHT,352 uint64_t TableEntryOffset) const;353 void PrintOpcodes(const uint8_t *Entry, size_t Length, off_t Offset) const;354 355public:356 PrinterContext(ScopedPrinter &SW, const object::ELFFile<ET> &ELF,357 StringRef FileName, const Elf_Shdr *Symtab)358 : SW(SW), ELF(ELF), FileName(FileName), Symtab(Symtab) {}359 360 void PrintUnwindInformation() const;361};362 363template <typename ET>364const size_t PrinterContext<ET>::IndexTableEntrySize = 8;365 366template <typename ET>367ErrorOr<StringRef> PrinterContext<ET>::FunctionAtAddress(368 uint64_t Address, std::optional<unsigned> SectionIndex) const {369 if (!Symtab)370 return inconvertibleErrorCode();371 auto StrTableOrErr = ELF.getStringTableForSymtab(*Symtab);372 if (!StrTableOrErr)373 reportError(StrTableOrErr.takeError(), FileName);374 StringRef StrTable = *StrTableOrErr;375 376 for (const Elf_Sym &Sym : unwrapOrError(FileName, ELF.symbols(Symtab))) {377 if (SectionIndex && *SectionIndex != Sym.st_shndx)378 continue;379 380 if (Sym.st_value == Address && Sym.getType() == ELF::STT_FUNC) {381 auto NameOrErr = Sym.getName(StrTable);382 if (!NameOrErr) {383 // TODO: Actually report errors helpfully.384 consumeError(NameOrErr.takeError());385 return inconvertibleErrorCode();386 }387 return *NameOrErr;388 }389 }390 391 return inconvertibleErrorCode();392}393 394template <typename ET>395const typename ET::Shdr *396PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex,397 off_t IndexTableOffset) const {398 /// Iterate through the sections, searching for the relocation section399 /// associated with the unwind index table section specified by400 /// IndexSectionIndex. Iterate the associated section searching for the401 /// relocation associated with the index table entry specified by402 /// IndexTableOffset. The symbol is the section symbol for the exception403 /// handling table. Use this symbol to recover the actual exception handling404 /// table.405 406 for (const Elf_Shdr &Sec : unwrapOrError(FileName, ELF.sections())) {407 if (Sec.sh_type != ELF::SHT_REL || Sec.sh_info != IndexSectionIndex)408 continue;409 410 auto SymTabOrErr = ELF.getSection(Sec.sh_link);411 if (!SymTabOrErr)412 reportError(SymTabOrErr.takeError(), FileName);413 const Elf_Shdr *SymTab = *SymTabOrErr;414 415 for (const Elf_Rel &R : unwrapOrError(FileName, ELF.rels(Sec))) {416 if (R.r_offset != static_cast<unsigned>(IndexTableOffset))417 continue;418 419 typename ET::Rela RelA;420 RelA.r_offset = R.r_offset;421 RelA.r_info = R.r_info;422 RelA.r_addend = 0;423 424 const Elf_Sym *Symbol =425 unwrapOrError(FileName, ELF.getRelocationSymbol(RelA, SymTab));426 427 auto Ret = ELF.getSection(*Symbol, SymTab, ShndxTable);428 if (!Ret)429 report_fatal_error(Twine(errorToErrorCode(Ret.takeError()).message()));430 return *Ret;431 }432 }433 return nullptr;434}435 436template <typename ET>437static const typename ET::Shdr *438findSectionContainingAddress(const object::ELFFile<ET> &Obj, StringRef FileName,439 uint64_t Address) {440 for (const typename ET::Shdr &Sec : unwrapOrError(FileName, Obj.sections()))441 if (Address >= Sec.sh_addr && Address < Sec.sh_addr + Sec.sh_size)442 return &Sec;443 return nullptr;444}445 446template <typename ET>447void PrinterContext<ET>::PrintExceptionTable(const Elf_Shdr &EHT,448 uint64_t TableEntryOffset) const {449 // TODO: handle failure.450 Expected<ArrayRef<uint8_t>> Contents = ELF.getSectionContents(EHT);451 if (!Contents)452 return;453 454 /// ARM EHABI Section 6.2 - The generic model455 ///456 /// An exception-handling table entry for the generic model is laid out as:457 ///458 /// 3 3459 /// 1 0 0460 /// +-+------------------------------+461 /// |0| personality routine offset |462 /// +-+------------------------------+463 /// | personality routine data ... |464 ///465 ///466 /// ARM EHABI Section 6.3 - The ARM-defined compact model467 ///468 /// An exception-handling table entry for the compact model looks like:469 ///470 /// 3 3 2 2 2 2471 /// 1 0 8 7 4 3 0472 /// +-+---+----+-----------------------+473 /// |1| 0 | Ix | data for pers routine |474 /// +-+---+----+-----------------------+475 /// | more personality routine data |476 477 const support::ulittle32_t Word =478 *reinterpret_cast<const support::ulittle32_t *>(Contents->data() + TableEntryOffset);479 480 if (Word & 0x80000000) {481 SW.printString("Model", StringRef("Compact"));482 483 unsigned PersonalityIndex = (Word & 0x0f000000) >> 24;484 SW.printNumber("PersonalityIndex", PersonalityIndex);485 486 switch (PersonalityIndex) {487 case AEABI_UNWIND_CPP_PR0:488 PrintOpcodes(Contents->data() + TableEntryOffset, 3, 1);489 break;490 case AEABI_UNWIND_CPP_PR1:491 case AEABI_UNWIND_CPP_PR2:492 unsigned AdditionalWords = (Word & 0x00ff0000) >> 16;493 PrintOpcodes(Contents->data() + TableEntryOffset, 2 + 4 * AdditionalWords,494 2);495 break;496 }497 } else {498 SW.printString("Model", StringRef("Generic"));499 const bool IsRelocatable = ELF.getHeader().e_type == ELF::ET_REL;500 uint64_t Address = IsRelocatable501 ? PREL31(Word, EHT.sh_addr)502 : PREL31(Word, EHT.sh_addr + TableEntryOffset);503 SW.printHex("PersonalityRoutineAddress", Address);504 std::optional<unsigned> SecIndex =505 IsRelocatable ? std::optional<unsigned>(EHT.sh_link) : std::nullopt;506 if (ErrorOr<StringRef> Name = FunctionAtAddress(Address, SecIndex))507 SW.printString("PersonalityRoutineName", *Name);508 }509}510 511template <typename ET>512void PrinterContext<ET>::PrintOpcodes(const uint8_t *Entry,513 size_t Length, off_t Offset) const {514 ListScope OCC(SW, "Opcodes");515 OpcodeDecoder(SW).Decode(Entry, Offset, Length);516}517 518template <typename ET>519void PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex,520 const Elf_Shdr *IT) const {521 // TODO: handle failure.522 Expected<ArrayRef<uint8_t>> Contents = ELF.getSectionContents(*IT);523 if (!Contents)524 return;525 526 /// ARM EHABI Section 5 - Index Table Entries527 /// * The first word contains a PREL31 offset to the start of a function with528 /// bit 31 clear529 /// * The second word contains one of:530 /// - The PREL31 offset of the start of the table entry for the function,531 /// with bit 31 clear532 /// - The exception-handling table entry itself with bit 31 set533 /// - The special bit pattern EXIDX_CANTUNWIND, indicating that associated534 /// frames cannot be unwound535 536 const support::ulittle32_t *Data =537 reinterpret_cast<const support::ulittle32_t *>(Contents->data());538 const unsigned Entries = IT->sh_size / IndexTableEntrySize;539 const bool IsRelocatable = ELF.getHeader().e_type == ELF::ET_REL;540 541 ListScope E(SW, "Entries");542 for (unsigned Entry = 0; Entry < Entries; ++Entry) {543 DictScope E(SW, "Entry");544 545 const support::ulittle32_t Word0 =546 Data[Entry * (IndexTableEntrySize / sizeof(*Data)) + 0];547 const support::ulittle32_t Word1 =548 Data[Entry * (IndexTableEntrySize / sizeof(*Data)) + 1];549 550 if (Word0 & 0x80000000) {551 errs() << "corrupt unwind data in section " << SectionIndex << "\n";552 continue;553 }554 555 // FIXME: For a relocatable object ideally we might want to:556 // 1) Find a relocation for the offset of Word0.557 // 2) Verify this relocation is of an expected type (R_ARM_PREL31) and558 // verify the symbol index.559 // 3) Resolve the relocation using it's symbol value, addend etc.560 // Currently the code assumes that Word0 contains an addend of a561 // R_ARM_PREL31 REL relocation that references a section symbol. RELA562 // relocations are not supported and it works because addresses of sections563 // are nulls in relocatable objects.564 //565 // For a non-relocatable object, Word0 contains a place-relative signed566 // offset to the referenced entity.567 const uint64_t Address =568 IsRelocatable569 ? PREL31(Word0, IT->sh_addr)570 : PREL31(Word0, IT->sh_addr + Entry * IndexTableEntrySize);571 SW.printHex("FunctionAddress", Address);572 573 // In a relocatable output we might have many .ARM.exidx sections linked to574 // their code sections via the sh_link field. For a non-relocatable ELF file575 // the sh_link field is not reliable, because we have one .ARM.exidx section576 // normally, but might have many code sections.577 std::optional<unsigned> SecIndex =578 IsRelocatable ? std::optional<unsigned>(IT->sh_link) : std::nullopt;579 if (ErrorOr<StringRef> Name = FunctionAtAddress(Address, SecIndex))580 SW.printString("FunctionName", *Name);581 582 if (Word1 == EXIDX_CANTUNWIND) {583 SW.printString("Model", StringRef("CantUnwind"));584 continue;585 }586 587 if (Word1 & 0x80000000) {588 SW.printString("Model", StringRef("Compact (Inline)"));589 590 unsigned PersonalityIndex = (Word1 & 0x0f000000) >> 24;591 SW.printNumber("PersonalityIndex", PersonalityIndex);592 593 PrintOpcodes(Contents->data() + Entry * IndexTableEntrySize + 4, 3, 1);594 } else {595 const Elf_Shdr *EHT;596 uint64_t TableEntryAddress;597 if (IsRelocatable) {598 TableEntryAddress = PREL31(Word1, IT->sh_addr);599 EHT = FindExceptionTable(SectionIndex, Entry * IndexTableEntrySize + 4);600 } else {601 TableEntryAddress =602 PREL31(Word1, IT->sh_addr + Entry * IndexTableEntrySize + 4);603 EHT = findSectionContainingAddress(ELF, FileName, TableEntryAddress);604 }605 606 if (EHT)607 // TODO: handle failure.608 if (Expected<StringRef> Name = ELF.getSectionName(*EHT))609 SW.printString("ExceptionHandlingTable", *Name);610 611 SW.printHex(IsRelocatable ? "TableEntryOffset" : "TableEntryAddress",612 TableEntryAddress);613 if (EHT) {614 if (IsRelocatable)615 PrintExceptionTable(*EHT, TableEntryAddress);616 else617 PrintExceptionTable(*EHT, TableEntryAddress - EHT->sh_addr);618 }619 }620 }621}622 623template <typename ET>624void PrinterContext<ET>::PrintUnwindInformation() const {625 DictScope UI(SW, "UnwindInformation");626 627 int SectionIndex = 0;628 for (const Elf_Shdr &Sec : unwrapOrError(FileName, ELF.sections())) {629 if (Sec.sh_type == ELF::SHT_ARM_EXIDX) {630 DictScope UIT(SW, "UnwindIndexTable");631 632 SW.printNumber("SectionIndex", SectionIndex);633 // TODO: handle failure.634 if (Expected<StringRef> SectionName = ELF.getSectionName(Sec))635 SW.printString("SectionName", *SectionName);636 SW.printHex("SectionOffset", Sec.sh_offset);637 638 PrintIndexTable(SectionIndex, &Sec);639 }640 ++SectionIndex;641 }642}643}644}645}646 647#endif648