summaryrefslogtreecommitdiff
path: root/tools/llvm-readobj/ARMWinEHPrinter.cpp
diff options
context:
space:
mode:
authorSaleem Abdulrasool <compnerd@compnerd.org>2014-06-07 19:23:07 +0000
committerSaleem Abdulrasool <compnerd@compnerd.org>2014-06-07 19:23:07 +0000
commit3ddcc4965059b1b5b8e3e57817660a4b931f295c (patch)
tree03da31a3a4d6810864dd307179aef113da010c4b /tools/llvm-readobj/ARMWinEHPrinter.cpp
parent1a17cd457be4ed19e1a0f88b13a7377476cc766b (diff)
downloadllvm-3ddcc4965059b1b5b8e3e57817660a4b931f295c.tar.gz
llvm-3ddcc4965059b1b5b8e3e57817660a4b931f295c.tar.bz2
llvm-3ddcc4965059b1b5b8e3e57817660a4b931f295c.tar.xz
tools: add a high level explanation for WoA EH data
Add a brief explanation of the data section layout for the unwind data that the Windows on ARM EH models. This is simply to provide a rough idea of the layout of the code involved in the decoding of the unwinding. Details on the involved data structures are available in the associated support header. The bulk of it is related to printing out the byte-code to help validate generation of WoA EH. No functional change. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@210397 91177308-0d34-0410-b5e6-96231b3b80d8
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) {