[llvm] r199708 - tools: support decoding ARM EHABI opcodes in readobj

Saleem Abdulrasool compnerd at compnerd.org
Mon Jan 20 18:33:15 PST 2014


Author: compnerd
Date: Mon Jan 20 20:33:15 2014
New Revision: 199708

URL: http://llvm.org/viewvc/llvm-project?rev=199708&view=rev
Log:
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!

Modified:
    llvm/trunk/test/MC/ARM/eh-directive-unwind_raw.s
    llvm/trunk/test/tools/llvm-readobj/ARM/unwind.s
    llvm/trunk/tools/llvm-readobj/ARMEHABIPrinter.h

Modified: llvm/trunk/test/MC/ARM/eh-directive-unwind_raw.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ARM/eh-directive-unwind_raw.s?rev=199708&r1=199707&r2=199708&view=diff
==============================================================================
--- llvm/trunk/test/MC/ARM/eh-directive-unwind_raw.s (original)
+++ llvm/trunk/test/MC/ARM/eh-directive-unwind_raw.s Mon Jan 20 20:33:15 2014
@@ -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:     ]

Modified: llvm/trunk/test/tools/llvm-readobj/ARM/unwind.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/ARM/unwind.s?rev=199708&r1=199707&r2=199708&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/ARM/unwind.s (original)
+++ llvm/trunk/test/tools/llvm-readobj/ARM/unwind.s Mon Jan 20 20:33:15 2014
@@ -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: }
 

Modified: llvm/trunk/tools/llvm-readobj/ARMEHABIPrinter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ARMEHABIPrinter.h?rev=199708&r1=199707&r2=199708&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/ARMEHABIPrinter.h (original)
+++ llvm/trunk/tools/llvm-readobj/ARMEHABIPrinter.h Mon Jan 20 20:33:15 2014
@@ -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>





More information about the llvm-commits mailing list