summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSaleem Abdulrasool <compnerd@compnerd.org>2014-01-21 02:33:15 +0000
committerSaleem Abdulrasool <compnerd@compnerd.org>2014-01-21 02:33:15 +0000
commitd28c094c802ed90f951c8c7100b8617b7d426daa (patch)
tree5949ddf5a433df6f2591523161547a5b19d23da6
parente502a6aad38cccb861eac7dfdde543e4ff248b9f (diff)
tools: support decoding ARM EHABI opcodes in readobj
Add support to llvm-readobj to decode the actual opcodes. The ARM EHABI opcodes are a variable length instruction set that describe the operations required for properly unwinding stack frames. The primary motivation for this change is to ease the creation of tests for the ARM EHABI object emission as well as the unwinding directive handling in the ARM IAS. Thanks to Logan Chien for an extra test case! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@199708 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--test/MC/ARM/eh-directive-unwind_raw.s33
-rw-r--r--test/tools/llvm-readobj/ARM/unwind.s169
-rw-r--r--tools/llvm-readobj/ARMEHABIPrinter.h290
3 files changed, 449 insertions, 43 deletions
diff --git a/test/MC/ARM/eh-directive-unwind_raw.s b/test/MC/ARM/eh-directive-unwind_raw.s
index ab826d58e63..c617aa37c49 100644
--- a/test/MC/ARM/eh-directive-unwind_raw.s
+++ b/test/MC/ARM/eh-directive-unwind_raw.s
@@ -62,18 +62,17 @@ stack_adjust:
@ CHECK: Model: Compact (Inline)
@ CHECK: PersonalityIndex: 0
@ CHECK: Opcodes [
-@ CHECK: Opcode: 0xB1
-@ CHECK: Opcode: 0x1
-@ CHECK: Opcode: 0xB0
+@ CHECK: 0xB1 0x01 ; pop {r0}
+@ CHECK: 0xB0 ; finish
@ CHECK: ]
@ CHECK: }
@ CHECK: Entry {
@ CHECK: Model: Compact (Inline)
@ CHECK: PersonalityIndex: 0
@ CHECK: Opcodes [
-@ CHECK: Opcode: 0xB0
-@ CHECK: Opcode: 0xB0
-@ CHECK: Opcode: 0xB0
+@ CHECK: 0xB0 ; finish
+@ CHECK: 0xB0 ; finish
+@ CHECK: 0xB0 ; finish
@ CHECK: ]
@ CHECK: }
@ CHECK: Entry {
@@ -81,30 +80,28 @@ stack_adjust:
@ CHECK: Model: Compact
@ CHECK: PersonalityIndex: 1
@ CHECK: Opcodes [
-@ CHECK: Opcode: 0x9B
-@ CHECK: Opcode: 0x40
-@ CHECK: Opcode: 0x84
-@ CHECK: Opcode: 0x80
-@ CHECK: Opcode: 0xB0
-@ CHECK: Opcode: 0xB0
+@ CHECK: 0x9B ; vsp = r11
+@ CHECK: 0x40 ; vsp = vsp - 4
+@ CHECK: 0x84 0x80 ; pop {fp, lr}
+@ CHECK: 0xB0 ; finish
+@ CHECK: 0xB0 ; finish
@ CHECK: ]
@ CHECK: }
@ CHECK: Entry {
@ CHECK: Model: Compact (Inline)
@ CHECK: PersonalityIndex: 0
@ CHECK: Opcodes [
-@ CHECK: Opcode: 0x80
-@ CHECK: Opcode: 0x0
-@ CHECK: Opcode: 0xB0
+@ CHECK: 0x80 0x00 ; refuse to unwind
+@ CHECK: 0xB0 ; finish
@ CHECK: ]
@ CHECK: }
@ CHECK: Entry {
@ CHECK: Model: Compact (Inline)
@ CHECK: PersonalityIndex: 0
@ CHECK: Opcodes [
-@ CHECK: Opcode: 0x9B
-@ CHECK: Opcode: 0x4D
-@ CHECK: Opcode: 0xC2
+@ CHECK: 0x9B ; vsp = r11
+@ CHECK: 0x4D ; vsp = vsp - 56
+@ CHECK: 0xC2 ; pop {wR10, wR11, wR12}
@ CHECK: ]
@ CHECK: }
@ CHECK: ]
diff --git a/test/tools/llvm-readobj/ARM/unwind.s b/test/tools/llvm-readobj/ARM/unwind.s
index 76068248bb1..afabeb7cd2e 100644
--- a/test/tools/llvm-readobj/ARM/unwind.s
+++ b/test/tools/llvm-readobj/ARM/unwind.s
@@ -1,5 +1,5 @@
-@ RUN: llvm-mc -triple armv7-eabi -filetype obj -o - %s | llvm-readobj -u - \
-@ RUN: | FileCheck %s
+@ RUN: llvm-mc -triple armv7-linux-eabi -filetype obj -o - %s \
+@ RUN: | llvm-readobj -u | FileCheck %s
.syntax unified
@@ -82,6 +82,69 @@ function2:
bx lr
.fnend
+ .section .raw
+
+ .type raw,%function
+ .thumb_func
+raw:
+ .fnstart
+ .unwind_raw 12, 0x02
+ .unwind_raw -12, 0x42
+ .unwind_raw 0, 0x80, 0x00
+ .unwind_raw 4, 0x81, 0x00
+ .unwind_raw 4, 0x80, 0x01
+ .unwind_raw 8, 0x80, 0xc0
+ .unwind_raw 12, 0x84, 0xc0
+ .unwind_raw 0, 0x91
+ .unwind_raw 8, 0xa1
+ .unwind_raw 12, 0xa9
+ .unwind_raw 0, 0xb0
+ .unwind_raw 4, 0xb1, 0x01
+ .unwind_raw 0xa04, 0xb2, 0x80, 0x04
+ .unwind_raw 24, 0xb3, 0x12
+ .unwind_raw 24, 0xba
+ .unwind_raw 24, 0xc2
+ .unwind_raw 24, 0xc6, 0x02
+ .unwind_raw 8, 0xc7, 0x03
+ .unwind_raw 24, 0xc8, 0x02
+ .unwind_raw 24, 0xc9, 0x02
+ .unwind_raw 64, 0xd7
+ .fnend
+
+ .section .spare
+
+ .type spare,%function
+spare:
+ .fnstart
+ .unwind_raw 4, 0x00
+ .unwind_raw -4, 0x40
+ .unwind_raw 0, 0x80, 0x00
+ .unwind_raw 4, 0x88, 0x00
+ .unwind_raw 0, 0x91
+ .unwind_raw 0, 0x9d
+ .unwind_raw 0, 0x9f
+ .unwind_raw 0, 0xa0
+ .unwind_raw 0, 0xa8
+ .unwind_raw 0, 0xb0
+ .unwind_raw 0, 0xb1, 0x00
+ .unwind_raw 4, 0xb1, 0x01
+ .unwind_raw 0, 0xb1, 0x10
+ .unwind_raw 0x204, 0xb2, 0x00
+ .unwind_raw 16, 0xb3, 0x00
+ .unwind_raw 0, 0xb4
+ .unwind_raw 16, 0xb8
+ .unwind_raw 4, 0xc0
+ .unwind_raw 4, 0xc6, 0x00
+ .unwind_raw 4, 0xc7, 0x00
+ .unwind_raw 4, 0xc7, 0x01
+ .unwind_raw 0, 0xc7, 0x10
+ .unwind_raw 16, 0xc8, 0x00
+ .unwind_raw 16, 0xc9, 0x00
+ .unwind_raw 0, 0xca
+ .unwind_raw 16, 0xd0
+ .unwind_raw 0, 0xd8
+ .fnend
+
@ CHECK: UnwindInformation {
@ CHECK: UnwindIndexTable {
@ CHECK: SectionName: .ARM.exidx.personality
@@ -92,9 +155,9 @@ function2:
@ CHECK: Model: Compact (Inline)
@ CHECK: PersonalityIndex: 0
@ CHECK: Opcodes [
-@ CHECK: Opcode: 0xB0
-@ CHECK: Opcode: 0xB0
-@ CHECK: Opcode: 0xB0
+@ CHECK: 0xB0 ; finish
+@ CHECK: 0xB0 ; finish
+@ CHECK: 0xB0 ; finish
@ CHECK: ]
@ CHECK: }
@ CHECK: ]
@@ -108,9 +171,9 @@ function2:
@ CHECK: Model: Compact (Inline)
@ CHECK: PersonalityIndex: 0
@ CHECK: Opcodes [
-@ CHECK: Opcode: 0xB0
-@ CHECK: Opcode: 0xB0
-@ CHECK: Opcode: 0xB0
+@ CHECK: 0xB0 ; finish
+@ CHECK: 0xB0 ; finish
+@ CHECK: 0xB0 ; finish
@ CHECK: ]
@ CHECK: }
@ CHECK: ]
@@ -126,12 +189,11 @@ function2:
@ CHECK: Model: Compact
@ CHECK: PersonalityIndex: 1
@ CHECK: Opcodes [
-@ CHECK: Opcode: 0xB1
-@ CHECK: Opcode: 0xF
-@ CHECK: Opcode: 0xA7
-@ CHECK: Opcode: 0x3F
-@ CHECK: Opcode: 0xB0
-@ CHECK: Opcode: 0xB0
+@ CHECK: 0xB1 0x0F ; pop {r0, r1, r2, r3}
+@ CHECK: 0xA7 ; pop {r4, r5, r6, r7, r8, r9, r10, fp}
+@ CHECK: 0x3F ; vsp = vsp + 256
+@ CHECK: 0xB0 ; finish
+@ CHECK: 0xB0 ; finish
@ CHECK: ]
@ CHECK: }
@ CHECK: ]
@@ -158,9 +220,8 @@ function2:
@ CHECK: Model: Compact (Inline)
@ CHECK: PersonalityIndex: 0
@ CHECK: Opcodes [
-@ CHECK: Opcode: 0xC9
-@ CHECK: Opcode: 0x84
-@ CHECK: Opcode: 0xB0
+@ CHECK: 0xC9 0x84 ; pop {d8, d9, d10, d11, d12}
+@ CHECK: 0xB0 ; finish
@ CHECK: ]
@ CHECK: }
@ CHECK: ]
@@ -174,9 +235,9 @@ function2:
@ CHECK: Model: Compact (Inline)
@ CHECK: PersonalityIndex: 0
@ CHECK: Opcodes [
-@ CHECK: Opcode: 0xB0
-@ CHECK: Opcode: 0xB0
-@ CHECK: Opcode: 0xB0
+@ CHECK: 0xB0 ; finish
+@ CHECK: 0xB0 ; finish
+@ CHECK: 0xB0 ; finish
@ CHECK: ]
@ CHECK: }
@ CHECK: Entry {
@@ -192,12 +253,74 @@ function2:
@ CHECK: Model: Compact (Inline)
@ CHECK: PersonalityIndex: 0
@ CHECK: Opcodes [
-@ CHECK: Opcode: 0xB0
-@ CHECK: Opcode: 0xB0
-@ CHECK: Opcode: 0xB0
+@ CHECK: 0xB0 ; finish
+@ CHECK: 0xB0 ; finish
+@ CHECK: 0xB0 ; finish
@ CHECK: ]
@ CHECK: }
@ CHECK: ]
@ CHECK: }
+@ CHECK: UnwindIndexTable {
+@ CHECK: SectionName: .ARM.exidx.raw
+@ CHECK: Entries [
+@ CHECK: Opcodes [
+@ CHECK: 0xD7 ; pop {d8, d9, d10, d11, d12, d13, d14, d15}
+@ CHECK: 0xC9 0x02 ; pop {d0, d1, d2}
+@ CHECK: 0xC8 0x02 ; pop {d16, d17, d18}
+@ CHECK: 0xC7 0x03 ; pop {wCGR0, wCGR1}
+@ CHECK: 0xC6 0x02 ; pop {wR0, wR1, wR2}
+@ CHECK: 0xC2 ; pop {wR10, wR11, wR12}
+@ CHECK: 0xBA ; pop {d8, d9, d10}
+@ CHECK: 0xB3 0x12 ; pop {d1, d2, d3}
+@ CHECK: 0xB2 0x80 0x04 ; vsp = vsp + 2564
+@ CHECK: 0xB1 0x01 ; pop {r0}
+@ CHECK: 0xB0 ; finish
+@ CHECK: 0xA9 ; pop {r4, r5, lr}
+@ CHECK: 0xA1 ; pop {r4, r5}
+@ CHECK: 0x91 ; vsp = r1
+@ CHECK: 0x84 0xC0 ; pop {r10, fp, lr}
+@ CHECK: 0x80 0xC0 ; pop {r10, fp}
+@ CHECK: 0x80 0x01 ; pop {r4}
+@ CHECK: 0x81 0x00 ; pop {ip}
+@ CHECK: 0x80 0x00 ; refuse to unwind
+@ CHECK: 0x42 ; vsp = vsp - 12
+@ CHECK: 0x02 ; vsp = vsp + 12
+@ CHECK: ]
+@ CHECK: ]
+@ CHECK: }
+@ CHECK: UnwindIndexTable {
+@ CHECK: SectionName: .ARM.exidx.spare
+@ CHECK: Entries [
+@ CHECK: Opcodes [
+@ CHECK: 0xD8 ; spare
+@ CHECK: 0xD0 ; pop {d8}
+@ CHECK: 0xCA ; spare
+@ CHECK: 0xC9 0x00 ; pop {d0}
+@ CHECK: 0xC8 0x00 ; pop {d16}
+@ CHECK: 0xC7 0x10 ; spare
+@ CHECK: 0xC7 0x01 ; pop {wCGR0}
+@ CHECK: 0xC7 0x00 ; spare
+@ CHECK: 0xC6 0x00 ; pop {wR0}
+@ CHECK: 0xC0 ; pop {wR10}
+@ CHECK: 0xB8 ; pop {d8}
+@ CHECK: 0xB4 ; spare
+@ CHECK: 0xB3 0x00 ; pop {d0}
+@ CHECK: 0xB2 0x00 ; vsp = vsp + 516
+@ CHECK: 0xB1 0x10 ; spare
+@ CHECK: 0xB1 0x01 ; pop {r0}
+@ CHECK: 0xB1 0x00 ; spare
+@ CHECK: 0xB0 ; finish
+@ CHECK: 0xA8 ; pop {r4, lr}
+@ CHECK: 0xA0 ; pop {r4}
+@ CHECK: 0x9F ; reserved (WiMMX MOVrr)
+@ CHECK: 0x9D ; reserved (ARM MOVrr)
+@ CHECK: 0x91 ; vsp = r1
+@ CHECK: 0x88 0x00 ; pop {pc}
+@ CHECK: 0x80 0x00 ; refuse to unwind
+@ CHECK: 0x40 ; vsp = vsp - 4
+@ CHECK: 0x00 ; vsp = vsp + 4
+@ CHECK: ]
+@ CHECK: ]
+@ CHECK: }
@ CHECK: }
diff --git a/tools/llvm-readobj/ARMEHABIPrinter.h b/tools/llvm-readobj/ARMEHABIPrinter.h
index 2cba126aadf..6a56373e26b 100644
--- a/tools/llvm-readobj/ARMEHABIPrinter.h
+++ b/tools/llvm-readobj/ARMEHABIPrinter.h
@@ -15,12 +15,299 @@
#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/type_traits.h"
+namespace {
+template <typename type_, size_t N>
+size_t countof(const type_ (&)[N]) {
+ return N;
+}
+}
+
namespace llvm {
namespace ARM {
namespace EHABI {
+
+class OpcodeDecoder {
+ StreamWriter &SW;
+ raw_ostream &OS;
+
+ struct RingEntry {
+ uint8_t Mask;
+ uint8_t Value;
+ void (OpcodeDecoder::*Routine)(const uint8_t *Opcodes, unsigned &OI);
+ };
+ static const 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(StreamWriter &SW) : SW(SW), OS(SW.getOStream()) {}
+ void Decode(const uint8_t *Opcodes, off_t Offset, size_t Length);
+};
+
+const OpcodeDecoder::RingEntry OpcodeDecoder::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 },
+};
+
+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);
+}
+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);
+}
+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';
+}
+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);
+}
+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);
+}
+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));
+}
+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';
+}
+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';
+}
+void OpcodeDecoder::Decode_10110000(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; finish\n", Opcode);
+}
+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) || Opcode1 == 0x00) ? "spare" : "pop ");
+ if (((Opcode1 & 0xf0) == 0x00) && Opcode1)
+ PrintGPR((Opcode1 & 0x0f));
+ OS << '\n';
+}
+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 + %u\n", 0x204 + (Value << 2));
+}
+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';
+}
+void OpcodeDecoder::Decode_101101nn(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; spare\n", Opcode);
+}
+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';
+}
+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';
+}
+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';
+}
+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';
+}
+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';
+}
+void OpcodeDecoder::Decode_11001yyy(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; spare\n", Opcode);
+}
+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';
+}
+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';
+}
+void OpcodeDecoder::Decode_11xxxyyy(const uint8_t *Opcodes, unsigned &OI) {
+ uint8_t Opcode = Opcodes[OI++ ^ 3];
+ SW.startLine() << format("0x%02X ; spare\n", Opcode);
+}
+
+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 << '}';
+}
+
+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 << '}';
+}
+
+void OpcodeDecoder::Decode(const uint8_t *Opcodes, off_t Offset, size_t Length) {
+ for (unsigned OCI = Offset; OCI < Length + Offset; ) {
+ bool Decoded = false;
+ for (unsigned REI = 0, REE = countof(Ring); REI != REE && !Decoded; ++REI) {
+ if ((Opcodes[OCI ^ 3] & Ring[REI].Mask) == Ring[REI].Value) {
+ (this->*Ring[REI].Routine)(Opcodes, OCI);
+ Decoded = true;
+ break;
+ }
+ }
+ if (!Decoded)
+ SW.startLine() << format("0x%02X ; reserved\n", Opcodes[OCI++ ^ 3]);
+ }
+}
+
template <typename ET>
class PrinterContext {
StreamWriter &SW;
@@ -171,8 +458,7 @@ template <typename ET>
void PrinterContext<ET>::PrintOpcodes(const uint8_t *Entry,
size_t Length, off_t Offset) const {
ListScope OCC(SW, "Opcodes");
- for (unsigned OCI = Offset; OCI < Length + Offset; OCI++)
- SW.printHex("Opcode", Entry[OCI ^ 0x3]);
+ OpcodeDecoder(OCC.W).Decode(Entry, Offset, Length);
}
template <typename ET>