|  | /* | 
|  | * 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 <sstream> | 
|  |  | 
|  | #include "android-base/logging.h" | 
|  | #include "android-base/stringprintf.h" | 
|  |  | 
|  | using android::base::StringPrintf; | 
|  |  | 
|  | using namespace vixl::aarch64;  // NOLINT(build/namespaces) | 
|  |  | 
|  | namespace art { | 
|  | namespace arm64 { | 
|  |  | 
|  | // 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  = 19, | 
|  | IP0 = 16, | 
|  | IP1 = 17, | 
|  | FP  = 29, | 
|  | LR  = 30 | 
|  | }; | 
|  |  | 
|  | void CustomDisassembler::AppendRegisterNameToOutput(const Instruction* instr, | 
|  | const CPURegister& reg) { | 
|  | USE(instr); | 
|  | if (reg.IsRegister() && reg.Is64Bits()) { | 
|  | if (reg.GetCode() == TR) { | 
|  | AppendToOutput("tr"); | 
|  | return; | 
|  | } else if (reg.GetCode() == LR) { | 
|  | AppendToOutput("lr"); | 
|  | return; | 
|  | } | 
|  | // Fall through. | 
|  | } | 
|  | // Print other register names as usual. | 
|  | Disassembler::AppendRegisterNameToOutput(instr, reg); | 
|  | } | 
|  |  | 
|  | void CustomDisassembler::VisitLoadLiteral(const Instruction* instr) { | 
|  | Disassembler::VisitLoadLiteral(instr); | 
|  |  | 
|  | if (!read_literals_) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Get address of literal. Bail if not within expected buffer range to | 
|  | // avoid trying to fetch invalid literals (we can encounter this when | 
|  | // interpreting raw data as instructions). | 
|  | void* data_address = instr->GetLiteralAddress<void*>(); | 
|  | if (data_address < base_address_ || data_address >= end_address_) { | 
|  | AppendToOutput(" (?)"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Output information on literal. | 
|  | Instr op = instr->Mask(LoadLiteralMask); | 
|  | switch (op) { | 
|  | case LDR_w_lit: | 
|  | case LDR_x_lit: | 
|  | case LDRSW_x_lit: { | 
|  | int64_t data = op == LDR_x_lit ? *reinterpret_cast<int64_t*>(data_address) | 
|  | : *reinterpret_cast<int32_t*>(data_address); | 
|  | AppendToOutput(" (0x%" PRIx64 " / %" PRId64 ")", data, data); | 
|  | break; | 
|  | } | 
|  | case LDR_s_lit: | 
|  | case LDR_d_lit: { | 
|  | double data = (op == LDR_s_lit) ? *reinterpret_cast<float*>(data_address) | 
|  | : *reinterpret_cast<double*>(data_address); | 
|  | AppendToOutput(" (%g)", data); | 
|  | break; | 
|  | } | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | void CustomDisassembler::VisitLoadStoreUnsignedOffset(const Instruction* instr) { | 
|  | Disassembler::VisitLoadStoreUnsignedOffset(instr); | 
|  |  | 
|  | if (instr->GetRn() == TR) { | 
|  | int64_t offset = instr->GetImmLSUnsigned() << instr->GetSizeLS(); | 
|  | std::ostringstream tmp_stream; | 
|  | options_->thread_offset_name_function_(tmp_stream, static_cast<uint32_t>(offset)); | 
|  | AppendToOutput(" ; %s", tmp_stream.str().c_str()); | 
|  | } | 
|  | } | 
|  |  | 
|  | size_t DisassemblerArm64::Dump(std::ostream& os, const uint8_t* begin) { | 
|  | const Instruction* instr = reinterpret_cast<const Instruction*>(begin); | 
|  | decoder.Decode(instr); | 
|  | os << FormatInstructionPointer(begin) | 
|  | << StringPrintf(": %08x\t%s\n", instr->GetInstructionBits(), disasm.GetOutput()); | 
|  | return kInstructionSize; | 
|  | } | 
|  |  | 
|  | void DisassemblerArm64::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) { | 
|  | for (const uint8_t* cur = begin; cur < end; cur += kInstructionSize) { | 
|  | Dump(os, cur); | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace arm64 | 
|  | }  // namespace art |