diff options
Diffstat (limited to 'tools/llvm-readobj/ARMWinEHPrinter.cpp')
-rw-r--r-- | tools/llvm-readobj/ARMWinEHPrinter.cpp | 102 |
1 files changed, 81 insertions, 21 deletions
diff --git a/tools/llvm-readobj/ARMWinEHPrinter.cpp b/tools/llvm-readobj/ARMWinEHPrinter.cpp index 256f73676d..d82b847a35 100644 --- a/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ b/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -7,6 +7,61 @@ // //===----------------------------------------------------------------------===// +// 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" @@ -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<uint16_t, uint32_t> &RegisterMask) { |