diff options
author | Ian Rogers <irogers@google.com> | 2014-11-19 21:09:12 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-11-19 21:09:15 +0000 |
commit | 834896de1c955c04d781d2bf8c53573f94ce8c3e (patch) | |
tree | 7152aa7bebe9a82f7b35b3f233aacaf6e3e72ea7 /disassembler | |
parent | 7b5f98e0c17785ec64eb291856cd08dcd3d19ce1 (diff) | |
parent | a37d925d405be9f589ac282869a997e73414d859 (diff) | |
download | art-834896de1c955c04d781d2bf8c53573f94ce8c3e.zip art-834896de1c955c04d781d2bf8c53573f94ce8c3e.tar.gz art-834896de1c955c04d781d2bf8c53573f94ce8c3e.tar.bz2 |
Merge "Improvements to the ARM64 disassembler."
Diffstat (limited to 'disassembler')
-rw-r--r-- | disassembler/disassembler.h | 10 | ||||
-rw-r--r-- | disassembler/disassembler_arm64.cc | 80 | ||||
-rw-r--r-- | disassembler/disassembler_arm64.h | 30 |
3 files changed, 115 insertions, 5 deletions
diff --git a/disassembler/disassembler.h b/disassembler/disassembler.h index 9cd631c..966ee3a 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 e56fe4f..a370b8d 100644 --- a/disassembler/disassembler_arm64.h +++ b/disassembler/disassembler_arm64.h @@ -28,9 +28,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); } @@ -39,7 +65,7 @@ class DisassemblerArm64 FINAL : public Disassembler { private: vixl::Decoder decoder; - vixl::Disassembler disasm; + CustomDisassembler disasm; DISALLOW_COPY_AND_ASSIGN(DisassemblerArm64); }; |