summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2012-04-10 15:04:25 -0700
committerElliott Hughes <enh@google.com>2012-04-10 15:04:25 -0700
commit105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cd (patch)
treefc5b59d5cd6f5ad4dccbe42c19fbd71e86271cef
parentb92bcabcbb28f69fe99e1c2f2e5559ab2c47aa60 (diff)
downloadart-105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cd.zip
art-105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cd.tar.gz
art-105afd2bd8f9f0ddfcfcb4b8db9f356ee82ae8cd.tar.bz2
Fancy disassembly of Thumb2 IT blocks.
Example: 0x60ce6ea4: 4291 cmp r1, r2 0x60ce6ea6: bf0e itee eq 0x60ce6ea8: 2001 movseq r0, #1 0x60ce6eaa: 1c10 movne r0, r2 0x60ce6eac: 47f0 blxne lr 0x60ce6eae: 1c06 mov r6, r0 Change-Id: I85deae2e471b8bfc513281be421e0bd46c1b60a0
-rw-r--r--src/disassembler.h7
-rw-r--r--src/disassembler_arm.cc31
-rw-r--r--src/disassembler_arm.h6
-rw-r--r--src/utils.h1
4 files changed, 43 insertions, 2 deletions
diff --git a/src/disassembler.h b/src/disassembler.h
index bd745a8..9f99ca6 100644
--- a/src/disassembler.h
+++ b/src/disassembler.h
@@ -22,6 +22,7 @@
#include <iosfwd>
#include "instruction_set.h"
+#include "macros.h"
namespace art {
@@ -31,6 +32,12 @@ class Disassembler {
virtual ~Disassembler() {}
virtual void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) = 0;
+
+ protected:
+ Disassembler() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Disassembler);
};
} // namespace art
diff --git a/src/disassembler_arm.cc b/src/disassembler_arm.cc
index 57fcec3..2492f50 100644
--- a/src/disassembler_arm.cc
+++ b/src/disassembler_arm.cc
@@ -899,9 +899,29 @@ size_t DisassemblerArm::DumpThumb16(std::ostream& os, const uint8_t* instr_ptr)
default: break;
}
} else {
+ uint32_t first_cond = opA;
+ uint32_t mask = opB;
opcode << "it";
- args << reinterpret_cast<void*>(opB) << " ";
- DumpCond(args, opA);
+
+ // Flesh out the base "it" opcode with the specific collection of 't's and 'e's,
+ // and store up the actual condition codes we'll want to add to the next few opcodes.
+ size_t count = 3 - CTZ(mask);
+ it_conditions_.resize(count + 2); // Plus the implicit 't', plus the "" for the IT itself.
+ for (size_t i = 0; i < count; ++i) {
+ bool positive_cond = ((first_cond & 1) != 0);
+ bool positive_mask = ((mask & (1 << (3 - i))) != 0);
+ if (positive_mask == positive_cond) {
+ opcode << 't';
+ it_conditions_[i] = kConditionCodeNames[first_cond];
+ } else {
+ opcode << 'e';
+ it_conditions_[i] = kConditionCodeNames[first_cond ^ 1];
+ }
+ }
+ it_conditions_[count] = kConditionCodeNames[first_cond]; // The implicit 't'.
+
+ it_conditions_[count + 1] = ""; // No condition code for the IT itself...
+ DumpCond(args, first_cond); // ...because it's considered an argument.
}
break;
}
@@ -943,6 +963,13 @@ size_t DisassemblerArm::DumpThumb16(std::ostream& os, const uint8_t* instr_ptr)
opcode << "b";
DumpBranchTarget(args, instr_ptr + 4, imm32);
}
+
+ // Apply any IT-block conditions to the opcode if necessary.
+ if (!it_conditions_.empty()) {
+ opcode << it_conditions_.back();
+ it_conditions_.pop_back();
+ }
+
os << StringPrintf("\t\t\t%p: %04x \t%-7s ", instr_ptr, instr, opcode.str().c_str()) << args.str() << '\n';
}
return 2;
diff --git a/src/disassembler_arm.h b/src/disassembler_arm.h
index 336d277..c59d395 100644
--- a/src/disassembler_arm.h
+++ b/src/disassembler_arm.h
@@ -17,6 +17,8 @@
#ifndef ART_SRC_DISASSEMBLER_ARM_H_
#define ART_SRC_DISASSEMBLER_ARM_H_
+#include <vector>
+
#include "disassembler.h"
namespace art {
@@ -36,6 +38,10 @@ class DisassemblerArm : public Disassembler {
void DumpBranchTarget(std::ostream& os, const uint8_t* instr_ptr, int32_t imm32);
void DumpCond(std::ostream& os, uint32_t cond);
+
+ std::vector<const char*> it_conditions_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisassemblerArm);
};
} // namespace arm
diff --git a/src/utils.h b/src/utils.h
index c709f9a..f11a769 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -131,6 +131,7 @@ static inline int CountOneBits(uint32_t x) {
}
#define CLZ(x) __builtin_clz(x)
+#define CTZ(x) __builtin_ctz(x)
static inline bool NeedsEscaping(uint16_t ch) {
return (ch < ' ' || ch > '~');