summaryrefslogtreecommitdiffstats
path: root/disassembler
diff options
context:
space:
mode:
authorAlexandre Rames <alexandre.rames@arm.com>2014-10-27 11:28:14 +0000
committerAlexandre Rames <alexandre.rames@arm.com>2014-10-29 09:01:14 +0000
commita37d925d405be9f589ac282869a997e73414d859 (patch)
treef48473337f07df6fb9f505651d653ed01b9d2eda /disassembler
parentbe29639a910daaa5bdb0c32be1e03477cf12babb (diff)
downloadart-a37d925d405be9f589ac282869a997e73414d859.zip
art-a37d925d405be9f589ac282869a997e73414d859.tar.gz
art-a37d925d405be9f589ac282869a997e73414d859.tar.bz2
Improvements to the ARM64 disassembler.
This contains three changes: - Use register aliases in the disassembly. - When loading from a literal pool, show what is being loaded. - Disassemble using absolute addresses on ARM64. This ensures that addresses disassembled are coherent with instruction location addresses shown. Examples of disassembled instructions before and after the changes: Before: movz w17, #0x471f ldr d9, pc+736 (addr 0x72690d50) After: movz wip1, #0x471f ldr d9, pc+736 (addr 0x72690d50) (-745.133) Change-Id: I72fdc160fac26f74126921834f17a581c26fd5d8
Diffstat (limited to 'disassembler')
-rw-r--r--disassembler/disassembler.h10
-rw-r--r--disassembler/disassembler_arm64.cc80
-rw-r--r--disassembler/disassembler_arm64.h30
3 files changed, 115 insertions, 5 deletions
diff --git a/disassembler/disassembler.h b/disassembler/disassembler.h
index 487f433..1d827ba 100644
--- a/disassembler/disassembler.h
+++ b/disassembler/disassembler.h
@@ -34,8 +34,14 @@ class DisassemblerOptions {
// Base addess for calculating relative code offsets when absolute_addresses_ is false.
const uint8_t* const base_address_;
- DisassemblerOptions(bool absolute_addresses, const uint8_t* base_address)
- : absolute_addresses_(absolute_addresses), base_address_(base_address) {}
+ // If set, the disassembler is allowed to look at load targets in literal
+ // pools.
+ const bool can_read_literals_;
+
+ DisassemblerOptions(bool absolute_addresses, const uint8_t* base_address,
+ bool can_read_literals)
+ : absolute_addresses_(absolute_addresses), base_address_(base_address),
+ can_read_literals_(can_read_literals) {}
private:
DISALLOW_COPY_AND_ASSIGN(DisassemblerOptions);
diff --git a/disassembler/disassembler_arm64.cc b/disassembler/disassembler_arm64.cc
index 229ac97..fe50421 100644
--- a/disassembler/disassembler_arm64.cc
+++ b/disassembler/disassembler_arm64.cc
@@ -27,10 +27,88 @@
namespace art {
namespace arm64 {
+void CustomDisassembler::AppendRegisterNameToOutput(
+ const vixl::Instruction* instr,
+ const vixl::CPURegister& reg) {
+ USE(instr);
+ if (reg.IsRegister()) {
+ // This enumeration should mirror the declarations in
+ // runtime/arch/arm64/registers_arm64.h. We do not include that file to
+ // avoid a dependency on libart.
+ enum {
+ TR = 18,
+ ETR = 21,
+ IP0 = 16,
+ IP1 = 17,
+ FP = 29,
+ LR = 30
+ };
+ switch (reg.code()) {
+ case IP0: AppendToOutput(reg.Is64Bits() ? "ip0" : "wip0"); return;
+ case IP1: AppendToOutput(reg.Is64Bits() ? "ip1" : "wip1"); return;
+ case TR: AppendToOutput(reg.Is64Bits() ? "tr" : "w18"); return;
+ case ETR: AppendToOutput(reg.Is64Bits() ? "etr" : "w21"); return;
+ case FP: AppendToOutput(reg.Is64Bits() ? "fp" : "w29"); return;
+ case LR: AppendToOutput(reg.Is64Bits() ? "lr" : "w30"); return;
+ default:
+ // Fall through.
+ break;
+ }
+ }
+ // Print other register names as usual.
+ Disassembler::AppendRegisterNameToOutput(instr, reg);
+}
+
+void CustomDisassembler::VisitLoadLiteral(const vixl::Instruction* instr) {
+ Disassembler::VisitLoadLiteral(instr);
+
+ if (!read_literals_) {
+ return;
+ }
+
+ char* buffer = buffer_;
+ char* buffer_end = buffer_ + buffer_size_;
+
+ // Find the end position in the buffer.
+ while ((*buffer != 0) && (buffer < buffer_end)) {
+ ++buffer;
+ }
+
+ void* data_address = instr->LiteralAddress();
+ ptrdiff_t buf_size_remaining = buffer_end - buffer;
+ vixl::Instr op = instr->Mask(vixl::LoadLiteralMask);
+
+ switch (op) {
+ case vixl::LDR_w_lit:
+ case vixl::LDR_x_lit:
+ case vixl::LDRSW_x_lit: {
+ int64_t data = op == vixl::LDR_x_lit ? *reinterpret_cast<int64_t*>(data_address)
+ : *reinterpret_cast<int32_t*>(data_address);
+ snprintf(buffer, buf_size_remaining, " (0x%" PRIx64 " / %" PRId64 ")", data, data);
+ break;
+ }
+ case vixl::LDR_s_lit:
+ case vixl::LDR_d_lit: {
+ double data = (op == vixl::LDR_s_lit) ? *reinterpret_cast<float*>(data_address)
+ : *reinterpret_cast<double*>(data_address);
+ snprintf(buffer, buf_size_remaining, " (%g)", data);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
size_t DisassemblerArm64::Dump(std::ostream& os, const uint8_t* begin) {
const vixl::Instruction* instr = reinterpret_cast<const vixl::Instruction*>(begin);
decoder.Decode(instr);
- os << FormatInstructionPointer(begin)
+ // TODO: Use FormatInstructionPointer() once VIXL provides the appropriate
+ // features.
+ // VIXL does not yet allow remapping addresses disassembled. Using
+ // FormatInstructionPointer() would show incoherences between the instruction
+ // location addresses and the target addresses disassembled by VIXL (eg. for
+ // branch instructions).
+ os << StringPrintf("%p", instr)
<< StringPrintf(": %08x\t%s\n", instr->InstructionBits(), disasm.GetOutput());
return vixl::kInstructionSize;
}
diff --git a/disassembler/disassembler_arm64.h b/disassembler/disassembler_arm64.h
index ad20c70..96a4dd0 100644
--- a/disassembler/disassembler_arm64.h
+++ b/disassembler/disassembler_arm64.h
@@ -25,9 +25,35 @@
namespace art {
namespace arm64 {
+class CustomDisassembler FINAL : public vixl::Disassembler {
+ public:
+ explicit CustomDisassembler(bool read_literals) :
+ vixl::Disassembler(), read_literals_(read_literals) {}
+
+ // Use register aliases in the disassembly.
+ virtual void AppendRegisterNameToOutput(const vixl::Instruction* instr,
+ const vixl::CPURegister& reg) OVERRIDE;
+
+ // Improve the disassembly of literal load instructions.
+ virtual void VisitLoadLiteral(const vixl::Instruction* instr) OVERRIDE;
+
+ private:
+ // Indicate if the disassembler should read data loaded from literal pools.
+ // This should only be enabled if reading the target of literal loads is safe.
+ // Here are possible outputs when the option is on or off:
+ // read_literals_ | disassembly
+ // true | 0x72681558: 1c000acb ldr s11, pc+344 (addr 0x726816b0)
+ // false | 0x72681558: 1c000acb ldr s11, pc+344 (addr 0x726816b0) (3.40282e+38)
+ const bool read_literals_;
+};
+
class DisassemblerArm64 FINAL : public Disassembler {
public:
- explicit DisassemblerArm64(DisassemblerOptions* options) : Disassembler(options) {
+ // TODO: Update this code once VIXL provides the ability to map code addresses
+ // to disassemble as a different address (the way FormatInstructionPointer()
+ // does).
+ explicit DisassemblerArm64(DisassemblerOptions* options) :
+ Disassembler(options), disasm(options->can_read_literals_) {
decoder.AppendVisitor(&disasm);
}
@@ -36,7 +62,7 @@ class DisassemblerArm64 FINAL : public Disassembler {
private:
vixl::Decoder decoder;
- vixl::Disassembler disasm;
+ CustomDisassembler disasm;
DISALLOW_COPY_AND_ASSIGN(DisassemblerArm64);
};