summaryrefslogtreecommitdiff
path: root/tools/llvm-readobj/ARMWinEHPrinter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-readobj/ARMWinEHPrinter.cpp')
-rw-r--r--tools/llvm-readobj/ARMWinEHPrinter.cpp102
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) {