X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllvm-readobj%2FARMWinEHPrinter.cpp;h=650955d1d75c053c2266b0fabd1ebba671591de5;hb=6e45bd9223aa621abb1ca94b91a786d40478253c;hp=256f73676d9b59d2bfb4dc0c2559f58dee4cfd86;hpb=510315c3864c4d3e12b5dd19f7100a94c1bea41d;p=oota-llvm.git diff --git a/tools/llvm-readobj/ARMWinEHPrinter.cpp b/tools/llvm-readobj/ARMWinEHPrinter.cpp index 256f73676d9..650955d1d75 100644 --- a/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ b/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -7,10 +7,65 @@ // //===----------------------------------------------------------------------===// +// Windows on ARM uses a series of serialised data structures (RuntimeFunction) +// to create a table of information for unwinding. In order to conserve space, +// there are two different ways that this data is represented. +// +// For functions with canonical forms for the prologue and epilogue, the data +// can be stored in a "packed" form. In this case, the data is packed into the +// RuntimeFunction's remaining 30-bits and can fully describe the entire frame. +// +// +---------------------------------------+ +// | Function Entry Address | +// +---------------------------------------+ +// | Packed Form Data | +// +---------------------------------------+ +// +// This layout is parsed by Decoder::dumpPackedEntry. No unwind bytecode is +// associated with such a frame as they can be derived from the provided data. +// The decoder does not synthesize this data as it is unnecessary for the +// purposes of validation, with the synthesis being required only by a proper +// unwinder. +// +// For functions that are large or do not match canonical forms, the data is +// split up into two portions, with the actual data residing in the "exception +// data" table (.xdata) with a reference to the entry from the "procedure data" +// (.pdata) entry. +// +// The exception data contains information about the frame setup, all of the +// epilouge scopes (for functions for which there are multiple exit points) and +// the associated exception handler. Additionally, the entry contains byte-code +// describing how to unwind the function (c.f. Decoder::decodeOpcodes). +// +// +---------------------------------------+ +// | Function Entry Address | +// +---------------------------------------+ +// | Exception Data Entry Address | +// +---------------------------------------+ +// +// This layout is parsed by Decoder::dumpUnpackedEntry. Such an entry must +// first resolve the exception data entry address. This structure +// (ExceptionDataRecord) has a variable sized header +// (c.f. ARM::WinEH::HeaderWords) and encodes most of the same information as +// the packed form. However, because this information is insufficient to +// synthesize the unwinding, there are associated unwinding bytecode which make +// up the bulk of the Decoder. +// +// The decoder itself is table-driven, using the first byte to determine the +// opcode and dispatching to the associated printing routine. The bytecode +// itself is a variable length instruction encoding that can fully describe the +// state of the stack and the necessary operations for unwinding to the +// beginning of the frame. +// +// The byte-code maintains a 1-1 instruction mapping, indicating both the width +// of the instruction (Thumb2 instructions are variable length, 16 or 32 bits +// wide) allowing the program to unwind from any point in the prologue, body, or +// epilogue of the function. + #include "ARMWinEHPrinter.h" #include "Error.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/ARMWinEH.h" #include "llvm/Support/Format.h" @@ -61,28 +116,33 @@ namespace ARM { namespace WinEH { const size_t Decoder::PDataEntrySize = sizeof(RuntimeFunction); +// TODO name the uops more appropriately const Decoder::RingEntry Decoder::Ring[] = { - { 0x80, 0x00, &Decoder::opcode_0xxxxxxx }, - { 0xc0, 0x80, &Decoder::opcode_10Lxxxxx }, - { 0xf0, 0xc0, &Decoder::opcode_1100xxxx }, - { 0xf8, 0xd0, &Decoder::opcode_11010Lxx }, - { 0xf8, 0xd8, &Decoder::opcode_11011Lxx }, - { 0xf8, 0xe0, &Decoder::opcode_11100xxx }, - { 0xfc, 0xe8, &Decoder::opcode_111010xx }, - { 0xfe, 0xec, &Decoder::opcode_1110110L }, - { 0xff, 0xee, &Decoder::opcode_11101110 }, - { 0xff, 0xef, &Decoder::opcode_11101111 }, - { 0xff, 0xf5, &Decoder::opcode_11110101 }, - { 0xff, 0xf6, &Decoder::opcode_11110110 }, - { 0xff, 0xf7, &Decoder::opcode_11110111 }, - { 0xff, 0xf8, &Decoder::opcode_11111000 }, - { 0xff, 0xf9, &Decoder::opcode_11111001 }, - { 0xff, 0xfa, &Decoder::opcode_11111010 }, - { 0xff, 0xfb, &Decoder::opcode_11111011 }, - { 0xff, 0xfc, &Decoder::opcode_11111100 }, - { 0xff, 0xfd, &Decoder::opcode_11111101 }, - { 0xff, 0xfe, &Decoder::opcode_11111110 }, - { 0xff, 0xff, &Decoder::opcode_11111111 }, + { 0x80, 0x00, &Decoder::opcode_0xxxxxxx }, // UOP_STACK_FREE (16-bit) + { 0xc0, 0x80, &Decoder::opcode_10Lxxxxx }, // UOP_POP (32-bit) + { 0xf0, 0xc0, &Decoder::opcode_1100xxxx }, // UOP_STACK_SAVE (16-bit) + { 0xf8, 0xd0, &Decoder::opcode_11010Lxx }, // UOP_POP (16-bit) + { 0xf8, 0xd8, &Decoder::opcode_11011Lxx }, // UOP_POP (32-bit) + { 0xf8, 0xe0, &Decoder::opcode_11100xxx }, // UOP_VPOP (32-bit) + { 0xfc, 0xe8, &Decoder::opcode_111010xx }, // UOP_STACK_FREE (32-bit) + { 0xfe, 0xec, &Decoder::opcode_1110110L }, // UOP_POP (16-bit) + { 0xff, 0xee, &Decoder::opcode_11101110 }, // UOP_MICROSOFT_SPECIFIC (16-bit) + // UOP_PUSH_MACHINE_FRAME + // UOP_PUSH_CONTEXT + // UOP_PUSH_TRAP_FRAME + // UOP_REDZONE_RESTORE_LR + { 0xff, 0xef, &Decoder::opcode_11101111 }, // UOP_LDRPC_POSTINC (32-bit) + { 0xff, 0xf5, &Decoder::opcode_11110101 }, // UOP_VPOP (32-bit) + { 0xff, 0xf6, &Decoder::opcode_11110110 }, // UOP_VPOP (32-bit) + { 0xff, 0xf7, &Decoder::opcode_11110111 }, // UOP_STACK_RESTORE (16-bit) + { 0xff, 0xf8, &Decoder::opcode_11111000 }, // UOP_STACK_RESTORE (16-bit) + { 0xff, 0xf9, &Decoder::opcode_11111001 }, // UOP_STACK_RESTORE (32-bit) + { 0xff, 0xfa, &Decoder::opcode_11111010 }, // UOP_STACK_RESTORE (32-bit) + { 0xff, 0xfb, &Decoder::opcode_11111011 }, // UOP_NOP (16-bit) + { 0xff, 0xfc, &Decoder::opcode_11111100 }, // UOP_NOP (32-bit) + { 0xff, 0xfd, &Decoder::opcode_11111101 }, // UOP_NOP (16-bit) / END + { 0xff, 0xfe, &Decoder::opcode_11111110 }, // UOP_NOP (32-bit) / END + { 0xff, 0xff, &Decoder::opcode_11111111 }, // UOP_END }; void Decoder::printRegisters(const std::pair &RegisterMask) { @@ -126,13 +186,8 @@ void Decoder::printRegisters(const std::pair &RegisterMask) ErrorOr Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { for (const auto &Section : COFF.sections()) { - uint64_t Address; - uint64_t Size; - - if (error_code EC = Section.getAddress(Address)) - return EC; - if (error_code EC = Section.getSize(Size)) - return EC; + uint64_t Address = Section.getAddress(); + uint64_t Size = Section.getSize(); if (VA >= Address && (VA - Address) <= Size) return Section; @@ -143,18 +198,13 @@ Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { ErrorOr Decoder::getSymbol(const COFFObjectFile &COFF, uint64_t VA, bool FunctionOnly) { for (const auto &Symbol : COFF.symbols()) { - if (FunctionOnly) { - SymbolRef::Type Type; - if (error_code EC = Symbol.getType(Type)) - return EC; - if (Type != SymbolRef::ST_Function) - continue; - } + if (FunctionOnly && Symbol.getType() != SymbolRef::ST_Function) + continue; - uint64_t Address; - if (error_code EC = Symbol.getAddress(Address)) + ErrorOr Address = Symbol.getAddress(); + if (std::error_code EC = Address.getError()) return EC; - if (Address == VA) + if (*Address == VA) return Symbol; } return readobj_error::unknown_symbol; @@ -164,16 +214,14 @@ ErrorOr Decoder::getRelocatedSymbol(const COFFObjectFile &, const SectionRef &Section, uint64_t Offset) { for (const auto &Relocation : Section.relocations()) { - uint64_t RelocationOffset; - if (auto Error = Relocation.getOffset(RelocationOffset)) - return Error; + uint64_t RelocationOffset = Relocation.getOffset(); if (RelocationOffset == Offset) return *Relocation.getSymbol(); } return readobj_error::unknown_symbol; } -bool Decoder::opcode_0xxxxxxx(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_0xxxxxxx(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { uint8_t Imm = OC[Offset] & 0x7f; SW.startLine() << format("0x%02x ; %s sp, #(%u * 4)\n", @@ -184,7 +232,7 @@ bool Decoder::opcode_0xxxxxxx(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_10Lxxxxx(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_10Lxxxxx(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { unsigned Link = (OC[Offset] & 0x20) >> 5; uint16_t RegisterMask = (Link << (Prologue ? 14 : 15)) @@ -203,7 +251,7 @@ bool Decoder::opcode_10Lxxxxx(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_1100xxxx(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_1100xxxx(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { if (Prologue) SW.startLine() << format("0x%02x ; mov r%u, sp\n", @@ -215,7 +263,7 @@ bool Decoder::opcode_1100xxxx(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_11010Lxx(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11010Lxx(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { unsigned Link = (OC[Offset] & 0x4) >> 3; unsigned Count = (OC[Offset] & 0x3); @@ -232,7 +280,7 @@ bool Decoder::opcode_11010Lxx(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_11011Lxx(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11011Lxx(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { unsigned Link = (OC[Offset] & 0x4) >> 2; unsigned Count = (OC[Offset] & 0x3) + 4; @@ -249,7 +297,7 @@ bool Decoder::opcode_11011Lxx(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_11100xxx(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11100xxx(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { unsigned High = (OC[Offset] & 0x7); uint32_t VFPMask = (((1 << (High + 1)) - 1) << 8); @@ -263,7 +311,7 @@ bool Decoder::opcode_11100xxx(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_111010xx(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_111010xx(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { uint16_t Imm = ((OC[Offset + 0] & 0x03) << 8) | ((OC[Offset + 1] & 0xff) << 0); @@ -276,7 +324,7 @@ bool Decoder::opcode_111010xx(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_1110110L(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_1110110L(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { uint8_t GPRMask = ((OC[Offset + 0] & 0x01) << (Prologue ? 14 : 15)) | ((OC[Offset + 1] & 0xff) << 0); @@ -290,7 +338,7 @@ bool Decoder::opcode_1110110L(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_11101110(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11101110(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { assert(!Prologue && "may not be used in prologue"); @@ -306,7 +354,7 @@ bool Decoder::opcode_11101110(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_11101111(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11101111(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { assert(!Prologue && "may not be used in prologue"); @@ -322,7 +370,7 @@ bool Decoder::opcode_11101111(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_11110101(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11110101(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; unsigned End = (OC[Offset + 1] & 0x0f) >> 0; @@ -337,7 +385,7 @@ bool Decoder::opcode_11110101(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_11110110(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11110110(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; unsigned End = (OC[Offset + 1] & 0x0f) >> 0; @@ -352,7 +400,7 @@ bool Decoder::opcode_11110110(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_11110111(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11110111(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); @@ -365,7 +413,7 @@ bool Decoder::opcode_11110111(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_11111000(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11111000(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { uint32_t Imm = (OC[Offset + 1] << 16) | (OC[Offset + 2] << 8) @@ -380,7 +428,7 @@ bool Decoder::opcode_11111000(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_11111001(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11111001(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); @@ -393,7 +441,7 @@ bool Decoder::opcode_11111001(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_11111010(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11111010(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { uint32_t Imm = (OC[Offset + 1] << 16) | (OC[Offset + 2] << 8) @@ -408,55 +456,53 @@ bool Decoder::opcode_11111010(const ulittle8_t *OC, unsigned &Offset, return false; } -bool Decoder::opcode_11111011(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11111011(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { SW.startLine() << format("0x%02x ; nop\n", OC[Offset]); ++Offset; return false; } -bool Decoder::opcode_11111100(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11111100(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { SW.startLine() << format("0x%02x ; nop.w\n", OC[Offset]); ++Offset; return false; } -bool Decoder::opcode_11111101(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11111101(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { SW.startLine() << format("0x%02x ; b\n", OC[Offset]); ++Offset; return true; } -bool Decoder::opcode_11111110(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11111110(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { SW.startLine() << format("0x%02x ; b.w\n", OC[Offset]); ++Offset; return true; } -bool Decoder::opcode_11111111(const ulittle8_t *OC, unsigned &Offset, +bool Decoder::opcode_11111111(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { ++Offset; return true; } -void Decoder::decodeOpcodes(ArrayRef Opcodes, unsigned Offset, +void Decoder::decodeOpcodes(ArrayRef Opcodes, unsigned Offset, bool Prologue) { assert((!Prologue || Offset == 0) && "prologue should always use offset 0"); bool Terminated = false; for (unsigned OI = Offset, OE = Opcodes.size(); !Terminated && OI < OE; ) { - bool Decoded = false; - for (unsigned DI = 0, DE = array_lengthof(Ring); DI < DE; ++DI) { + for (unsigned DI = 0;; ++DI) { if ((Opcodes[OI] & Ring[DI].Mask) == Ring[DI].Value) { Terminated = (this->*Ring[DI].Routine)(Opcodes.data(), OI, 0, Prologue); - Decoded = true; break; } + assert(DI < array_lengthof(Ring) && "unhandled opcode"); } - assert(Decoded && "unhandled opcode"); } } @@ -467,10 +513,7 @@ bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents)) return false; - uint64_t SectionVA; - if (Section.getAddress(SectionVA)) - return false; - + uint64_t SectionVA = Section.getAddress(); uint64_t Offset = VA - SectionVA; const ulittle32_t *Data = reinterpret_cast(Contents.data() + Offset); @@ -488,7 +531,7 @@ bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, static_cast(XData.CodeWords() * sizeof(uint32_t))); if (XData.E()) { - ArrayRef UC = XData.UnwindByteCode(); + ArrayRef UC = XData.UnwindByteCode(); if (!XData.F()) { ListScope PS(SW, "Prologue"); decodeOpcodes(UC, 0, /*Prologue=*/true); @@ -524,12 +567,12 @@ bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, if (!Symbol) Symbol = getSymbol(COFF, Address, /*FunctionOnly=*/true); - StringRef Name; - if (Symbol) - Symbol->getName(Name); + ErrorOr Name = Symbol->getName(); + if (std::error_code EC = Name.getError()) + report_fatal_error(EC.message()); ListScope EHS(SW, "ExceptionHandler"); - SW.printString("Routine", formatSymbol(Name, Address)); + SW.printString("Routine", formatSymbol(*Name, Address)); SW.printHex("Parameter", Parameter); } @@ -558,8 +601,14 @@ bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF, StringRef FunctionName; uint64_t FunctionAddress; if (Function) { - Function->getName(FunctionName); - Function->getAddress(FunctionAddress); + ErrorOr FunctionNameOrErr = Function->getName(); + if (std::error_code EC = FunctionNameOrErr.getError()) + report_fatal_error(EC.message()); + FunctionName = *FunctionNameOrErr; + ErrorOr FunctionAddressOrErr = Function->getAddress(); + if (std::error_code EC = FunctionAddressOrErr.getError()) + report_fatal_error(EC.message()); + FunctionAddress = *FunctionAddressOrErr; } else { const pe32_header *PEHeader; if (COFF.getPE32Header(PEHeader)) @@ -570,17 +619,21 @@ bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF, SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); if (XDataRecord) { - StringRef Name; - uint64_t Address; + ErrorOr Name = XDataRecord->getName(); + if (std::error_code EC = Name.getError()) + report_fatal_error(EC.message()); - XDataRecord->getName(Name); - XDataRecord->getAddress(Address); + ErrorOr AddressOrErr = XDataRecord->getAddress(); + if (std::error_code EC = AddressOrErr.getError()) + report_fatal_error(EC.message()); + uint64_t Address = *AddressOrErr; - SW.printString("ExceptionRecord", formatSymbol(Name, Address)); + SW.printString("ExceptionRecord", formatSymbol(*Name, Address)); - section_iterator SI = COFF.section_end(); - if (XDataRecord->getSection(SI)) + ErrorOr SIOrErr = XDataRecord->getSection(); + if (!SIOrErr) return false; + section_iterator SI = *SIOrErr; return dumpXDataRecord(COFF, *SI, FunctionAddress, Address); } else { @@ -615,8 +668,12 @@ bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF, StringRef FunctionName; uint64_t FunctionAddress; if (Function) { - Function->getName(FunctionName); - Function->getAddress(FunctionAddress); + ErrorOr FunctionNameOrErr = Function->getName(); + if (std::error_code EC = FunctionNameOrErr.getError()) + report_fatal_error(EC.message()); + FunctionName = *FunctionNameOrErr; + ErrorOr FunctionAddressOrErr = Function->getAddress(); + FunctionAddress = *FunctionAddressOrErr; } else { const pe32_header *PEHeader; if (COFF.getPE32Header(PEHeader)) @@ -668,19 +725,18 @@ void Decoder::dumpProcedureData(const COFFObjectFile &COFF, break; } -error_code Decoder::dumpProcedureData(const COFFObjectFile &COFF) { +std::error_code Decoder::dumpProcedureData(const COFFObjectFile &COFF) { for (const auto &Section : COFF.sections()) { StringRef SectionName; - if (error_code EC = COFF.getSectionName(COFF.getCOFFSection(Section), - SectionName)) + if (std::error_code EC = + COFF.getSectionName(COFF.getCOFFSection(Section), SectionName)) return EC; if (SectionName.startswith(".pdata")) dumpProcedureData(COFF, Section); } - return error_code(); + return std::error_code(); } } } } -