diff options
Diffstat (limited to 'tools/llvm-readobj/ARMEHABIPrinter.h')
-rw-r--r-- | tools/llvm-readobj/ARMEHABIPrinter.h | 557 |
1 files changed, 557 insertions, 0 deletions
diff --git a/tools/llvm-readobj/ARMEHABIPrinter.h b/tools/llvm-readobj/ARMEHABIPrinter.h new file mode 100644 index 0000000..75e2bee --- /dev/null +++ b/tools/llvm-readobj/ARMEHABIPrinter.h @@ -0,0 +1,557 @@ +//===--- ARMEHABIPrinter.h - ARM EHABI Unwind Information Printer ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_ARMEHABI_PRINTER_H +#define LLVM_READOBJ_ARMEHABI_PRINTER_H + +#include "Error.h" +#include "StreamWriter.h" +#include "llvm/Object/ELF.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Support/ARMEHABI.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/type_traits.h" + +namespace { +template <typename type_, size_t N> +size_t countof(const type_ (&)[N]) { + return N; +} +} + +namespace llvm { +namespace ARM { +namespace EHABI { + +class OpcodeDecoder { + StreamWriter &SW; + raw_ostream &OS; + + struct RingEntry { + uint8_t Mask; + uint8_t Value; + void (OpcodeDecoder::*Routine)(const uint8_t *Opcodes, unsigned &OI); + }; + static const RingEntry Ring[]; + + void Decode_00xxxxxx(const uint8_t *Opcodes, unsigned &OI); + void Decode_01xxxxxx(const uint8_t *Opcodes, unsigned &OI); + void Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes, unsigned &OI); + void Decode_10011101(const uint8_t *Opcodes, unsigned &OI); + void Decode_10011111(const uint8_t *Opcodes, unsigned &OI); + void Decode_1001nnnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_10100nnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_10101nnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_10110000(const uint8_t *Opcodes, unsigned &OI); + void Decode_10110001_0000iiii(const uint8_t *Opcodes, unsigned &OI); + void Decode_10110010_uleb128(const uint8_t *Opcodes, unsigned &OI); + void Decode_10110011_sssscccc(const uint8_t *Opcodes, unsigned &OI); + void Decode_101101nn(const uint8_t *Opcodes, unsigned &OI); + void Decode_10111nnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_11000110_sssscccc(const uint8_t *Opcodes, unsigned &OI); + void Decode_11000111_0000iiii(const uint8_t *Opcodes, unsigned &OI); + void Decode_11001000_sssscccc(const uint8_t *Opcodes, unsigned &OI); + void Decode_11001001_sssscccc(const uint8_t *Opcodes, unsigned &OI); + void Decode_11001yyy(const uint8_t *Opcodes, unsigned &OI); + void Decode_11000nnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_11010nnn(const uint8_t *Opcodes, unsigned &OI); + void Decode_11xxxyyy(const uint8_t *Opcodes, unsigned &OI); + + void PrintGPR(uint16_t GPRMask); + void PrintRegisters(uint32_t Mask, StringRef Prefix); + +public: + OpcodeDecoder(StreamWriter &SW) : SW(SW), OS(SW.getOStream()) {} + void Decode(const uint8_t *Opcodes, off_t Offset, size_t Length); +}; + +const OpcodeDecoder::RingEntry OpcodeDecoder::Ring[] = { + { 0xc0, 0x00, &OpcodeDecoder::Decode_00xxxxxx }, + { 0xc0, 0x40, &OpcodeDecoder::Decode_01xxxxxx }, + { 0xf0, 0x80, &OpcodeDecoder::Decode_1000iiii_iiiiiiii }, + { 0xff, 0x9d, &OpcodeDecoder::Decode_10011101 }, + { 0xff, 0x9f, &OpcodeDecoder::Decode_10011111 }, + { 0xf0, 0x90, &OpcodeDecoder::Decode_1001nnnn }, + { 0xf8, 0xa0, &OpcodeDecoder::Decode_10100nnn }, + { 0xf8, 0xa8, &OpcodeDecoder::Decode_10101nnn }, + { 0xff, 0xb0, &OpcodeDecoder::Decode_10110000 }, + { 0xff, 0xb1, &OpcodeDecoder::Decode_10110001_0000iiii }, + { 0xff, 0xb2, &OpcodeDecoder::Decode_10110010_uleb128 }, + { 0xff, 0xb3, &OpcodeDecoder::Decode_10110011_sssscccc }, + { 0xfc, 0xb4, &OpcodeDecoder::Decode_101101nn }, + { 0xf8, 0xb8, &OpcodeDecoder::Decode_10111nnn }, + { 0xff, 0xc6, &OpcodeDecoder::Decode_11000110_sssscccc }, + { 0xff, 0xc7, &OpcodeDecoder::Decode_11000111_0000iiii }, + { 0xff, 0xc8, &OpcodeDecoder::Decode_11001000_sssscccc }, + { 0xff, 0xc9, &OpcodeDecoder::Decode_11001001_sssscccc }, + { 0xc8, 0xc8, &OpcodeDecoder::Decode_11001yyy }, + { 0xf8, 0xc0, &OpcodeDecoder::Decode_11000nnn }, + { 0xf8, 0xd0, &OpcodeDecoder::Decode_11010nnn }, + { 0xc0, 0xc0, &OpcodeDecoder::Decode_11xxxyyy }, +}; + +void OpcodeDecoder::Decode_00xxxxxx(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; vsp = vsp + %u\n", Opcode, + ((Opcode & 0x3f) << 2) + 4); +} +void OpcodeDecoder::Decode_01xxxxxx(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; vsp = vsp - %u\n", Opcode, + ((Opcode & 0x3f) << 2) + 4); +} +void OpcodeDecoder::Decode_1000iiii_iiiiiiii(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + + uint16_t GPRMask = (Opcode1 << 4) | ((Opcode0 & 0x0f) << 12); + SW.startLine() + << format("0x%02X 0x%02X ; %s", + Opcode0, Opcode1, GPRMask ? "pop " : "refuse to unwind"); + if (GPRMask) + PrintGPR(GPRMask); + OS << '\n'; +} +void OpcodeDecoder::Decode_10011101(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; reserved (ARM MOVrr)\n", Opcode); +} +void OpcodeDecoder::Decode_10011111(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; reserved (WiMMX MOVrr)\n", Opcode); +} +void OpcodeDecoder::Decode_1001nnnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; vsp = r%u\n", Opcode, (Opcode & 0x0f)); +} +void OpcodeDecoder::Decode_10100nnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; pop ", Opcode); + PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4)); + OS << '\n'; +} +void OpcodeDecoder::Decode_10101nnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; pop ", Opcode); + PrintGPR((((1 << ((Opcode & 0x7) + 1)) - 1) << 4) | (1 << 14)); + OS << '\n'; +} +void OpcodeDecoder::Decode_10110000(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; finish\n", Opcode); +} +void OpcodeDecoder::Decode_10110001_0000iiii(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + + SW.startLine() + << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1, + ((Opcode1 & 0xf0) || Opcode1 == 0x00) ? "spare" : "pop "); + if (((Opcode1 & 0xf0) == 0x00) && Opcode1) + PrintGPR((Opcode1 & 0x0f)); + OS << '\n'; +} +void OpcodeDecoder::Decode_10110010_uleb128(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ", Opcode); + + SmallVector<uint8_t, 4> ULEB; + do { ULEB.push_back(Opcodes[OI ^ 3]); } while (Opcodes[OI++ ^ 3] & 0x80); + + for (unsigned BI = 0, BE = ULEB.size(); BI != BE; ++BI) + OS << format("0x%02X ", ULEB[BI]); + + uint64_t Value = 0; + for (unsigned BI = 0, BE = ULEB.size(); BI != BE; ++BI) + Value = Value | ((ULEB[BI] & 0x7f) << (7 * BI)); + + OS << format("; vsp = vsp + %" PRIu64 "\n", 0x204 + (Value << 2)); +} +void OpcodeDecoder::Decode_10110011_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); + uint8_t Start = ((Opcode1 & 0xf0) >> 4); + uint8_t Count = ((Opcode1 & 0x0f) >> 0); + PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d"); + OS << '\n'; +} +void OpcodeDecoder::Decode_101101nn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; spare\n", Opcode); +} +void OpcodeDecoder::Decode_10111nnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; pop ", Opcode); + PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11000110_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); + uint8_t Start = ((Opcode1 & 0xf0) >> 4); + uint8_t Count = ((Opcode1 & 0x0f) >> 0); + PrintRegisters((((1 << (Count + 1)) - 1) << Start), "wR"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11000111_0000iiii(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + SW.startLine() + << format("0x%02X 0x%02X ; %s", Opcode0, Opcode1, + ((Opcode1 & 0xf0) || Opcode1 == 0x00) ? "spare" : "pop "); + if ((Opcode1 & 0xf0) == 0x00 && Opcode1) + PrintRegisters(Opcode1 & 0x0f, "wCGR"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11001000_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); + uint8_t Start = 16 + ((Opcode1 & 0xf0) >> 4); + uint8_t Count = ((Opcode1 & 0x0f) >> 0); + PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11001001_sssscccc(const uint8_t *Opcodes, + unsigned &OI) { + uint8_t Opcode0 = Opcodes[OI++ ^ 3]; + uint8_t Opcode1 = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X 0x%02X ; pop ", Opcode0, Opcode1); + uint8_t Start = ((Opcode1 & 0xf0) >> 4); + uint8_t Count = ((Opcode1 & 0x0f) >> 0); + PrintRegisters((((1 << (Count + 1)) - 1) << Start), "d"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11001yyy(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; spare\n", Opcode); +} +void OpcodeDecoder::Decode_11000nnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; pop ", Opcode); + PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 10), "wR"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11010nnn(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; pop ", Opcode); + PrintRegisters((((1 << ((Opcode & 0x07) + 1)) - 1) << 8), "d"); + OS << '\n'; +} +void OpcodeDecoder::Decode_11xxxyyy(const uint8_t *Opcodes, unsigned &OI) { + uint8_t Opcode = Opcodes[OI++ ^ 3]; + SW.startLine() << format("0x%02X ; spare\n", Opcode); +} + +void OpcodeDecoder::PrintGPR(uint16_t GPRMask) { + static const char *GPRRegisterNames[16] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", + "fp", "ip", "sp", "lr", "pc" + }; + + OS << '{'; + bool Comma = false; + for (unsigned RI = 0, RE = 17; RI < RE; ++RI) { + if (GPRMask & (1 << RI)) { + if (Comma) + OS << ", "; + OS << GPRRegisterNames[RI]; + Comma = true; + } + } + OS << '}'; +} + +void OpcodeDecoder::PrintRegisters(uint32_t VFPMask, StringRef Prefix) { + OS << '{'; + bool Comma = false; + for (unsigned RI = 0, RE = 32; RI < RE; ++RI) { + if (VFPMask & (1 << RI)) { + if (Comma) + OS << ", "; + OS << Prefix << RI; + Comma = true; + } + } + OS << '}'; +} + +void OpcodeDecoder::Decode(const uint8_t *Opcodes, off_t Offset, size_t Length) { + for (unsigned OCI = Offset; OCI < Length + Offset; ) { + bool Decoded = false; + for (unsigned REI = 0, REE = countof(Ring); REI != REE && !Decoded; ++REI) { + if ((Opcodes[OCI ^ 3] & Ring[REI].Mask) == Ring[REI].Value) { + (this->*Ring[REI].Routine)(Opcodes, OCI); + Decoded = true; + break; + } + } + if (!Decoded) + SW.startLine() << format("0x%02X ; reserved\n", Opcodes[OCI++ ^ 3]); + } +} + +template <typename ET> +class PrinterContext { + StreamWriter &SW; + const object::ELFFile<ET> *ELF; + + typedef typename object::ELFFile<ET>::Elf_Sym Elf_Sym; + typedef typename object::ELFFile<ET>::Elf_Shdr Elf_Shdr; + + typedef typename object::ELFFile<ET>::Elf_Rel_Iter Elf_Rel_iterator; + typedef typename object::ELFFile<ET>::Elf_Sym_Iter Elf_Sym_iterator; + typedef typename object::ELFFile<ET>::Elf_Shdr_Iter Elf_Shdr_iterator; + + static const size_t IndexTableEntrySize; + + static uint64_t PREL31(uint32_t Address, uint32_t Place) { + uint64_t Location = Address & 0x7fffffff; + if (Location & 0x04000000) + Location |= (uint64_t) ~0x7fffffff; + return Location + Place; + } + + ErrorOr<StringRef> FunctionAtAddress(unsigned Section, uint64_t Address) const; + const Elf_Shdr *FindExceptionTable(unsigned IndexTableIndex, + off_t IndexTableOffset) const; + + void PrintIndexTable(unsigned SectionIndex, const Elf_Shdr *IT) const; + void PrintExceptionTable(const Elf_Shdr *IT, const Elf_Shdr *EHT, + uint64_t TableEntryOffset) const; + void PrintOpcodes(const uint8_t *Entry, size_t Length, off_t Offset) const; + +public: + PrinterContext(StreamWriter &Writer, const object::ELFFile<ET> *File) + : SW(Writer), ELF(File) {} + + void PrintUnwindInformation() const; +}; + +template <typename ET> +const size_t PrinterContext<ET>::IndexTableEntrySize = 8; + +template <typename ET> +ErrorOr<StringRef> PrinterContext<ET>::FunctionAtAddress(unsigned Section, + uint64_t Address) const { + for (Elf_Sym_iterator SI = ELF->begin_symbols(), SE = ELF->end_symbols(); + SI != SE; ++SI) + if (SI->st_shndx == Section && SI->st_value == Address && + SI->getType() == ELF::STT_FUNC) + return ELF->getSymbolName(SI); + return readobj_error::unknown_symbol; +} + +template <typename ET> +const typename object::ELFFile<ET>::Elf_Shdr * +PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex, + off_t IndexTableOffset) const { + /// Iterate through the sections, searching for the relocation section + /// associated with the unwind index table section specified by + /// IndexSectionIndex. Iterate the associated section searching for the + /// relocation associated with the index table entry specified by + /// IndexTableOffset. The symbol is the section symbol for the exception + /// handling table. Use this symbol to recover the actual exception handling + /// table. + + for (Elf_Shdr_iterator SI = ELF->begin_sections(), SE = ELF->end_sections(); + SI != SE; ++SI) { + if (SI->sh_type == ELF::SHT_REL && SI->sh_info == IndexSectionIndex) { + for (Elf_Rel_iterator RI = ELF->begin_rel(&*SI), RE = ELF->end_rel(&*SI); + RI != RE; ++RI) { + if (RI->r_offset == static_cast<unsigned>(IndexTableOffset)) { + typename object::ELFFile<ET>::Elf_Rela RelA; + RelA.r_offset = RI->r_offset; + RelA.r_info = RI->r_info; + RelA.r_addend = 0; + + std::pair<const Elf_Shdr *, const Elf_Sym *> Symbol = + ELF->getRelocationSymbol(&(*SI), &RelA); + + return ELF->getSection(Symbol.second); + } + } + } + } + return NULL; +} + +template <typename ET> +void PrinterContext<ET>::PrintExceptionTable(const Elf_Shdr *IT, + const Elf_Shdr *EHT, + uint64_t TableEntryOffset) const { + ErrorOr<ArrayRef<uint8_t> > Contents = ELF->getSectionContents(EHT); + if (!Contents) + return; + + /// ARM EHABI Section 6.2 - The generic model + /// + /// An exception-handling table entry for the generic model is laid out as: + /// + /// 3 3 + /// 1 0 0 + /// +-+------------------------------+ + /// |0| personality routine offset | + /// +-+------------------------------+ + /// | personality routine data ... | + /// + /// + /// ARM EHABI Section 6.3 - The ARM-defined compact model + /// + /// An exception-handling table entry for the compact model looks like: + /// + /// 3 3 2 2 2 2 + /// 1 0 8 7 4 3 0 + /// +-+---+----+-----------------------+ + /// |1| 0 | Ix | data for pers routine | + /// +-+---+----+-----------------------+ + /// | more personality routine data | + + const support::ulittle32_t Word = + *reinterpret_cast<const support::ulittle32_t *>(Contents->data() + TableEntryOffset); + + if (Word & 0x80000000) { + SW.printString("Model", StringRef("Compact")); + + unsigned PersonalityIndex = (Word & 0x0f000000) >> 24; + SW.printNumber("PersonalityIndex", PersonalityIndex); + + switch (PersonalityIndex) { + case AEABI_UNWIND_CPP_PR0: + PrintOpcodes(Contents->data() + TableEntryOffset, 3, 1); + break; + case AEABI_UNWIND_CPP_PR1: + case AEABI_UNWIND_CPP_PR2: + unsigned AdditionalWords = (Word & 0x00ff0000) >> 16; + PrintOpcodes(Contents->data() + TableEntryOffset, 2 + 4 * AdditionalWords, + 2); + break; + } + } else { + SW.printString("Model", StringRef("Generic")); + + uint64_t Address = PREL31(Word, EHT->sh_addr); + SW.printHex("PersonalityRoutineAddress", Address); + if (ErrorOr<StringRef> Name = FunctionAtAddress(EHT->sh_link, Address)) + SW.printString("PersonalityRoutineName", *Name); + } +} + +template <typename ET> +void PrinterContext<ET>::PrintOpcodes(const uint8_t *Entry, + size_t Length, off_t Offset) const { + ListScope OCC(SW, "Opcodes"); + OpcodeDecoder(OCC.W).Decode(Entry, Offset, Length); +} + +template <typename ET> +void PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex, + const Elf_Shdr *IT) const { + ErrorOr<ArrayRef<uint8_t> > Contents = ELF->getSectionContents(IT); + if (!Contents) + return; + + /// ARM EHABI Section 5 - Index Table Entries + /// * The first word contains a PREL31 offset to the start of a function with + /// bit 31 clear + /// * The second word contains one of: + /// - The PREL31 offset of the start of the table entry for the function, + /// with bit 31 clear + /// - The exception-handling table entry itself with bit 31 set + /// - The special bit pattern EXIDX_CANTUNWIND, indicating that associated + /// frames cannot be unwound + + const support::ulittle32_t *Data = + reinterpret_cast<const support::ulittle32_t *>(Contents->data()); + const unsigned Entries = IT->sh_size / IndexTableEntrySize; + + ListScope E(SW, "Entries"); + for (unsigned Entry = 0; Entry < Entries; ++Entry) { + DictScope E(SW, "Entry"); + + const support::ulittle32_t Word0 = + Data[Entry * (IndexTableEntrySize / sizeof(*Data)) + 0]; + const support::ulittle32_t Word1 = + Data[Entry * (IndexTableEntrySize / sizeof(*Data)) + 1]; + + if (Word0 & 0x80000000) { + errs() << "corrupt unwind data in section " << SectionIndex << "\n"; + continue; + } + + const uint64_t Offset = PREL31(Word0, IT->sh_addr); + SW.printHex("FunctionAddress", Offset); + if (ErrorOr<StringRef> Name = FunctionAtAddress(IT->sh_link, Offset)) + SW.printString("FunctionName", *Name); + + if (Word1 == EXIDX_CANTUNWIND) { + SW.printString("Model", StringRef("CantUnwind")); + continue; + } + + if (Word1 & 0x80000000) { + SW.printString("Model", StringRef("Compact (Inline)")); + + unsigned PersonalityIndex = (Word1 & 0x0f000000) >> 24; + SW.printNumber("PersonalityIndex", PersonalityIndex); + + PrintOpcodes(Contents->data() + Entry * IndexTableEntrySize + 4, 3, 1); + } else { + const Elf_Shdr *EHT = + FindExceptionTable(SectionIndex, Entry * IndexTableEntrySize + 4); + + if (ErrorOr<StringRef> Name = ELF->getSectionName(EHT)) + SW.printString("ExceptionHandlingTable", *Name); + + uint64_t TableEntryOffset = PREL31(Word1, IT->sh_addr); + SW.printHex("TableEntryOffset", TableEntryOffset); + + PrintExceptionTable(IT, EHT, TableEntryOffset); + } + } +} + +template <typename ET> +void PrinterContext<ET>::PrintUnwindInformation() const { + DictScope UI(SW, "UnwindInformation"); + + int SectionIndex = 0; + for (Elf_Shdr_iterator SI = ELF->begin_sections(), SE = ELF->end_sections(); + SI != SE; ++SI, ++SectionIndex) { + if (SI->sh_type == ELF::SHT_ARM_EXIDX) { + const Elf_Shdr *IT = &(*SI); + + DictScope UIT(SW, "UnwindIndexTable"); + + SW.printNumber("SectionIndex", SectionIndex); + if (ErrorOr<StringRef> SectionName = ELF->getSectionName(IT)) + SW.printString("SectionName", *SectionName); + SW.printHex("SectionOffset", IT->sh_offset); + + PrintIndexTable(SectionIndex, IT); + } + } +} +} +} +} + +#endif + |