123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647 |
- //===--- ARMEHABIPrinter.h - ARM EHABI Unwind Information Printer ----------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_TOOLS_LLVM_READOBJ_ARMEHABIPRINTER_H
- #define LLVM_TOOLS_LLVM_READOBJ_ARMEHABIPRINTER_H
- #include "llvm-readobj.h"
- #include "llvm/ADT/STLExtras.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/ScopedPrinter.h"
- #include "llvm/Support/type_traits.h"
- namespace llvm {
- namespace ARM {
- namespace EHABI {
- class OpcodeDecoder {
- ScopedPrinter &SW;
- raw_ostream &OS;
- struct RingEntry {
- uint8_t Mask;
- uint8_t Value;
- void (OpcodeDecoder::*Routine)(const uint8_t *Opcodes, unsigned &OI);
- };
- static ArrayRef<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(ScopedPrinter &SW) : SW(SW), OS(SW.getOStream()) {}
- void Decode(const uint8_t *Opcodes, off_t Offset, size_t Length);
- };
- inline ArrayRef<OpcodeDecoder::RingEntry> OpcodeDecoder::ring() {
- static const OpcodeDecoder::RingEntry 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},
- };
- return ArrayRef(Ring);
- }
- inline 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);
- }
- inline 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);
- }
- inline 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';
- }
- inline 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);
- }
- inline 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);
- }
- inline 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));
- }
- inline 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';
- }
- inline 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';
- }
- inline void OpcodeDecoder::Decode_10110000(const uint8_t *Opcodes,
- unsigned &OI) {
- uint8_t Opcode = Opcodes[OI++ ^ 3];
- SW.startLine() << format("0x%02X ; finish\n", Opcode);
- }
- inline 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) ? "spare" : "pop ");
- if (((Opcode1 & 0xf0) == 0x00) && Opcode1)
- PrintGPR((Opcode1 & 0x0f));
- OS << '\n';
- }
- inline 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));
- }
- inline 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';
- }
- inline void OpcodeDecoder::Decode_101101nn(const uint8_t *Opcodes,
- unsigned &OI) {
- uint8_t Opcode = Opcodes[OI++ ^ 3];
- SW.startLine() << format("0x%02X ; %s\n", Opcode,
- (Opcode == 0xb4) ? "pop ra_auth_code" : "spare");
- }
- inline 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';
- }
- inline 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';
- }
- inline 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';
- }
- inline 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';
- }
- inline 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';
- }
- inline void OpcodeDecoder::Decode_11001yyy(const uint8_t *Opcodes,
- unsigned &OI) {
- uint8_t Opcode = Opcodes[OI++ ^ 3];
- SW.startLine() << format("0x%02X ; spare\n", Opcode);
- }
- inline 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';
- }
- inline 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';
- }
- inline void OpcodeDecoder::Decode_11xxxyyy(const uint8_t *Opcodes,
- unsigned &OI) {
- uint8_t Opcode = Opcodes[OI++ ^ 3];
- SW.startLine() << format("0x%02X ; spare\n", Opcode);
- }
- inline 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 << '}';
- }
- inline 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 << '}';
- }
- inline void OpcodeDecoder::Decode(const uint8_t *Opcodes, off_t Offset,
- size_t Length) {
- for (unsigned OCI = Offset; OCI < Length + Offset; ) {
- bool Decoded = false;
- for (const auto &RE : ring()) {
- if ((Opcodes[OCI ^ 3] & RE.Mask) == RE.Value) {
- (this->*RE.Routine)(Opcodes, OCI);
- Decoded = true;
- break;
- }
- }
- if (!Decoded)
- SW.startLine() << format("0x%02X ; reserved\n", Opcodes[OCI++ ^ 3]);
- }
- }
- template <typename ET>
- class PrinterContext {
- typedef typename ET::Sym Elf_Sym;
- typedef typename ET::Shdr Elf_Shdr;
- typedef typename ET::Rel Elf_Rel;
- typedef typename ET::Word Elf_Word;
- ScopedPrinter &SW;
- const object::ELFFile<ET> &ELF;
- StringRef FileName;
- const Elf_Shdr *Symtab;
- ArrayRef<Elf_Word> ShndxTable;
- static const size_t IndexTableEntrySize;
- static uint64_t PREL31(uint32_t Address, uint32_t Place) {
- uint64_t Location = Address & 0x7fffffff;
- if (Location & 0x40000000)
- Location |= (uint64_t) ~0x7fffffff;
- return Location + Place;
- }
- ErrorOr<StringRef>
- FunctionAtAddress(uint64_t Address,
- std::optional<unsigned> SectionIndex) 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 &EHT,
- uint64_t TableEntryOffset) const;
- void PrintOpcodes(const uint8_t *Entry, size_t Length, off_t Offset) const;
- public:
- PrinterContext(ScopedPrinter &SW, const object::ELFFile<ET> &ELF,
- StringRef FileName, const Elf_Shdr *Symtab)
- : SW(SW), ELF(ELF), FileName(FileName), Symtab(Symtab) {}
- void PrintUnwindInformation() const;
- };
- template <typename ET>
- const size_t PrinterContext<ET>::IndexTableEntrySize = 8;
- template <typename ET>
- ErrorOr<StringRef> PrinterContext<ET>::FunctionAtAddress(
- uint64_t Address, std::optional<unsigned> SectionIndex) const {
- if (!Symtab)
- return inconvertibleErrorCode();
- auto StrTableOrErr = ELF.getStringTableForSymtab(*Symtab);
- if (!StrTableOrErr)
- reportError(StrTableOrErr.takeError(), FileName);
- StringRef StrTable = *StrTableOrErr;
- for (const Elf_Sym &Sym : unwrapOrError(FileName, ELF.symbols(Symtab))) {
- if (SectionIndex && *SectionIndex != Sym.st_shndx)
- continue;
- if (Sym.st_value == Address && Sym.getType() == ELF::STT_FUNC) {
- auto NameOrErr = Sym.getName(StrTable);
- if (!NameOrErr) {
- // TODO: Actually report errors helpfully.
- consumeError(NameOrErr.takeError());
- return inconvertibleErrorCode();
- }
- return *NameOrErr;
- }
- }
- return inconvertibleErrorCode();
- }
- template <typename ET>
- const typename ET::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 (const Elf_Shdr &Sec : unwrapOrError(FileName, ELF.sections())) {
- if (Sec.sh_type != ELF::SHT_REL || Sec.sh_info != IndexSectionIndex)
- continue;
- auto SymTabOrErr = ELF.getSection(Sec.sh_link);
- if (!SymTabOrErr)
- reportError(SymTabOrErr.takeError(), FileName);
- const Elf_Shdr *SymTab = *SymTabOrErr;
- for (const Elf_Rel &R : unwrapOrError(FileName, ELF.rels(Sec))) {
- if (R.r_offset != static_cast<unsigned>(IndexTableOffset))
- continue;
- typename ET::Rela RelA;
- RelA.r_offset = R.r_offset;
- RelA.r_info = R.r_info;
- RelA.r_addend = 0;
- const Elf_Sym *Symbol =
- unwrapOrError(FileName, ELF.getRelocationSymbol(RelA, SymTab));
- auto Ret = ELF.getSection(*Symbol, SymTab, ShndxTable);
- if (!Ret)
- report_fatal_error(Twine(errorToErrorCode(Ret.takeError()).message()));
- return *Ret;
- }
- }
- return nullptr;
- }
- template <typename ET>
- static const typename ET::Shdr *
- findSectionContainingAddress(const object::ELFFile<ET> &Obj, StringRef FileName,
- uint64_t Address) {
- for (const typename ET::Shdr &Sec : unwrapOrError(FileName, Obj.sections()))
- if (Address >= Sec.sh_addr && Address < Sec.sh_addr + Sec.sh_size)
- return &Sec;
- return nullptr;
- }
- template <typename ET>
- void PrinterContext<ET>::PrintExceptionTable(const Elf_Shdr &EHT,
- uint64_t TableEntryOffset) const {
- // TODO: handle failure.
- Expected<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"));
- const bool IsRelocatable = ELF.getHeader().e_type == ELF::ET_REL;
- uint64_t Address = IsRelocatable
- ? PREL31(Word, EHT.sh_addr)
- : PREL31(Word, EHT.sh_addr + TableEntryOffset);
- SW.printHex("PersonalityRoutineAddress", Address);
- std::optional<unsigned> SecIndex =
- IsRelocatable ? std::optional<unsigned>(EHT.sh_link) : std::nullopt;
- if (ErrorOr<StringRef> Name = FunctionAtAddress(Address, SecIndex))
- 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(SW).Decode(Entry, Offset, Length);
- }
- template <typename ET>
- void PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex,
- const Elf_Shdr *IT) const {
- // TODO: handle failure.
- Expected<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;
- const bool IsRelocatable = ELF.getHeader().e_type == ELF::ET_REL;
- 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;
- }
- // FIXME: For a relocatable object ideally we might want to:
- // 1) Find a relocation for the offset of Word0.
- // 2) Verify this relocation is of an expected type (R_ARM_PREL31) and
- // verify the symbol index.
- // 3) Resolve the relocation using it's symbol value, addend etc.
- // Currently the code assumes that Word0 contains an addend of a
- // R_ARM_PREL31 REL relocation that references a section symbol. RELA
- // relocations are not supported and it works because addresses of sections
- // are nulls in relocatable objects.
- //
- // For a non-relocatable object, Word0 contains a place-relative signed
- // offset to the referenced entity.
- const uint64_t Address =
- IsRelocatable
- ? PREL31(Word0, IT->sh_addr)
- : PREL31(Word0, IT->sh_addr + Entry * IndexTableEntrySize);
- SW.printHex("FunctionAddress", Address);
- // In a relocatable output we might have many .ARM.exidx sections linked to
- // their code sections via the sh_link field. For a non-relocatable ELF file
- // the sh_link field is not reliable, because we have one .ARM.exidx section
- // normally, but might have many code sections.
- std::optional<unsigned> SecIndex =
- IsRelocatable ? std::optional<unsigned>(IT->sh_link) : std::nullopt;
- if (ErrorOr<StringRef> Name = FunctionAtAddress(Address, SecIndex))
- 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;
- uint64_t TableEntryAddress;
- if (IsRelocatable) {
- TableEntryAddress = PREL31(Word1, IT->sh_addr);
- EHT = FindExceptionTable(SectionIndex, Entry * IndexTableEntrySize + 4);
- } else {
- TableEntryAddress =
- PREL31(Word1, IT->sh_addr + Entry * IndexTableEntrySize + 4);
- EHT = findSectionContainingAddress(ELF, FileName, TableEntryAddress);
- }
- if (EHT)
- // TODO: handle failure.
- if (Expected<StringRef> Name = ELF.getSectionName(*EHT))
- SW.printString("ExceptionHandlingTable", *Name);
- SW.printHex(IsRelocatable ? "TableEntryOffset" : "TableEntryAddress",
- TableEntryAddress);
- if (EHT) {
- if (IsRelocatable)
- PrintExceptionTable(*EHT, TableEntryAddress);
- else
- PrintExceptionTable(*EHT, TableEntryAddress - EHT->sh_addr);
- }
- }
- }
- }
- template <typename ET>
- void PrinterContext<ET>::PrintUnwindInformation() const {
- DictScope UI(SW, "UnwindInformation");
- int SectionIndex = 0;
- for (const Elf_Shdr &Sec : unwrapOrError(FileName, ELF.sections())) {
- if (Sec.sh_type == ELF::SHT_ARM_EXIDX) {
- DictScope UIT(SW, "UnwindIndexTable");
- SW.printNumber("SectionIndex", SectionIndex);
- // TODO: handle failure.
- if (Expected<StringRef> SectionName = ELF.getSectionName(Sec))
- SW.printString("SectionName", *SectionName);
- SW.printHex("SectionOffset", Sec.sh_offset);
- PrintIndexTable(SectionIndex, &Sec);
- }
- ++SectionIndex;
- }
- }
- }
- }
- }
- #endif
|