blob: bd3bebf20fdafae3c743ada4da4e11d91bd8bff5 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "disassembler_arm64.h"
#include <inttypes.h>
#include <ostream>
#include "base/logging.h"
#include "base/stringprintf.h"
#include "thread.h"
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<void*>();
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);
// 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;
}
void DisassemblerArm64::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) {
for (const uint8_t* cur = begin; cur < end; cur += vixl::kInstructionSize) {
Dump(os, cur);
}
}
} // namespace arm64
} // namespace art