blob: 4ff44b47c268bfb72380e9725f97e157bfe1521b [file] [log] [blame]
Serban Constantinescue6622be2014-02-27 15:36:47 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "disassembler_arm64.h"
18
19#include <inttypes.h>
20
Zheng Xua34e7602015-02-03 12:03:15 +080021#include <sstream>
Serban Constantinescue6622be2014-02-27 15:36:47 +000022
23#include "base/logging.h"
24#include "base/stringprintf.h"
25#include "thread.h"
26
27namespace art {
28namespace arm64 {
29
Zheng Xua34e7602015-02-03 12:03:15 +080030// This enumeration should mirror the declarations in
31// runtime/arch/arm64/registers_arm64.h. We do not include that file to
32// avoid a dependency on libart.
33enum {
34 TR = 18,
35 ETR = 21,
36 IP0 = 16,
37 IP1 = 17,
38 FP = 29,
39 LR = 30
40};
41
Alexandre Ramesa37d9252014-10-27 11:28:14 +000042void CustomDisassembler::AppendRegisterNameToOutput(
43 const vixl::Instruction* instr,
44 const vixl::CPURegister& reg) {
45 USE(instr);
46 if (reg.IsRegister()) {
Alexandre Ramesa37d9252014-10-27 11:28:14 +000047 switch (reg.code()) {
48 case IP0: AppendToOutput(reg.Is64Bits() ? "ip0" : "wip0"); return;
49 case IP1: AppendToOutput(reg.Is64Bits() ? "ip1" : "wip1"); return;
50 case TR: AppendToOutput(reg.Is64Bits() ? "tr" : "w18"); return;
51 case ETR: AppendToOutput(reg.Is64Bits() ? "etr" : "w21"); return;
52 case FP: AppendToOutput(reg.Is64Bits() ? "fp" : "w29"); return;
53 case LR: AppendToOutput(reg.Is64Bits() ? "lr" : "w30"); return;
54 default:
55 // Fall through.
56 break;
57 }
58 }
59 // Print other register names as usual.
60 Disassembler::AppendRegisterNameToOutput(instr, reg);
61}
62
63void CustomDisassembler::VisitLoadLiteral(const vixl::Instruction* instr) {
64 Disassembler::VisitLoadLiteral(instr);
65
66 if (!read_literals_) {
67 return;
68 }
69
Serban Constantinescu32f5b4d2014-11-25 20:05:46 +000070 void* data_address = instr->LiteralAddress<void*>();
Alexandre Ramesa37d9252014-10-27 11:28:14 +000071 vixl::Instr op = instr->Mask(vixl::LoadLiteralMask);
72
73 switch (op) {
74 case vixl::LDR_w_lit:
75 case vixl::LDR_x_lit:
76 case vixl::LDRSW_x_lit: {
77 int64_t data = op == vixl::LDR_x_lit ? *reinterpret_cast<int64_t*>(data_address)
78 : *reinterpret_cast<int32_t*>(data_address);
Zheng Xua34e7602015-02-03 12:03:15 +080079 AppendToOutput(" (0x%" PRIx64 " / %" PRId64 ")", data, data);
Alexandre Ramesa37d9252014-10-27 11:28:14 +000080 break;
81 }
82 case vixl::LDR_s_lit:
83 case vixl::LDR_d_lit: {
84 double data = (op == vixl::LDR_s_lit) ? *reinterpret_cast<float*>(data_address)
85 : *reinterpret_cast<double*>(data_address);
Zheng Xua34e7602015-02-03 12:03:15 +080086 AppendToOutput(" (%g)", data);
Alexandre Ramesa37d9252014-10-27 11:28:14 +000087 break;
88 }
89 default:
90 break;
91 }
92}
93
Zheng Xua34e7602015-02-03 12:03:15 +080094void CustomDisassembler::VisitLoadStoreUnsignedOffset(const vixl::Instruction* instr) {
95 Disassembler::VisitLoadStoreUnsignedOffset(instr);
96
97 if (instr->Rn() == TR) {
98 int64_t offset = instr->ImmLSUnsigned() << instr->SizeLS();
99 std::ostringstream tmp_stream;
100 Thread::DumpThreadOffset<8>(tmp_stream, static_cast<uint32_t>(offset));
101 AppendToOutput(" (%s)", tmp_stream.str().c_str());
102 }
103}
104
Serban Constantinescue6622be2014-02-27 15:36:47 +0000105size_t DisassemblerArm64::Dump(std::ostream& os, const uint8_t* begin) {
Alexandre Ramesfef019c2014-10-10 17:14:18 +0100106 const vixl::Instruction* instr = reinterpret_cast<const vixl::Instruction*>(begin);
107 decoder.Decode(instr);
Alexandre Ramesa37d9252014-10-27 11:28:14 +0000108 // TODO: Use FormatInstructionPointer() once VIXL provides the appropriate
109 // features.
110 // VIXL does not yet allow remapping addresses disassembled. Using
111 // FormatInstructionPointer() would show incoherences between the instruction
112 // location addresses and the target addresses disassembled by VIXL (eg. for
113 // branch instructions).
114 os << StringPrintf("%p", instr)
Alexandre Ramesfef019c2014-10-10 17:14:18 +0100115 << StringPrintf(": %08x\t%s\n", instr->InstructionBits(), disasm.GetOutput());
Serban Constantinescue6622be2014-02-27 15:36:47 +0000116 return vixl::kInstructionSize;
117}
118
119void DisassemblerArm64::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) {
120 for (const uint8_t* cur = begin; cur < end; cur += vixl::kInstructionSize) {
121 Dump(os, cur);
122 }
123}
124
125} // namespace arm64
126} // namespace art