1 /* 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 21 #include <sstream> 22 23 #include "android-base/logging.h" 24 #include "android-base/stringprintf.h" 25 26 using android::base::StringPrintf; 27 28 using namespace vixl::aarch64; // NOLINT(build/namespaces) 29 30 namespace art { 31 namespace arm64 { 32 33 // This enumeration should mirror the declarations in 34 // runtime/arch/arm64/registers_arm64.h. We do not include that file to 35 // avoid a dependency on libart. 36 enum { 37 TR = 19, 38 IP0 = 16, 39 IP1 = 17, 40 FP = 29, 41 LR = 30 42 }; 43 44 void CustomDisassembler::AppendRegisterNameToOutput(const Instruction* instr, 45 const CPURegister& reg) { 46 USE(instr); 47 if (reg.IsRegister() && reg.Is64Bits()) { 48 if (reg.GetCode() == TR) { 49 AppendToOutput("tr"); 50 return; 51 } else if (reg.GetCode() == LR) { 52 AppendToOutput("lr"); 53 return; 54 } 55 // Fall through. 56 } 57 // Print other register names as usual. 58 Disassembler::AppendRegisterNameToOutput(instr, reg); 59 } 60 61 void CustomDisassembler::VisitLoadLiteral(const Instruction* instr) { 62 Disassembler::VisitLoadLiteral(instr); 63 64 if (!read_literals_) { 65 return; 66 } 67 68 // Get address of literal. Bail if not within expected buffer range to 69 // avoid trying to fetch invalid literals (we can encounter this when 70 // interpreting raw data as instructions). 71 void* data_address = instr->GetLiteralAddress<void*>(); 72 if (data_address < base_address_ || data_address >= end_address_) { 73 AppendToOutput(" (?)"); 74 return; 75 } 76 77 // Output information on literal. 78 Instr op = instr->Mask(LoadLiteralMask); 79 switch (op) { 80 case LDR_w_lit: 81 case LDR_x_lit: 82 case LDRSW_x_lit: { 83 int64_t data = op == LDR_x_lit ? *reinterpret_cast<int64_t*>(data_address) 84 : *reinterpret_cast<int32_t*>(data_address); 85 AppendToOutput(" (0x%" PRIx64 " / %" PRId64 ")", data, data); 86 break; 87 } 88 case LDR_s_lit: 89 case LDR_d_lit: { 90 double data = (op == LDR_s_lit) ? *reinterpret_cast<float*>(data_address) 91 : *reinterpret_cast<double*>(data_address); 92 AppendToOutput(" (%g)", data); 93 break; 94 } 95 default: 96 break; 97 } 98 } 99 100 void CustomDisassembler::VisitLoadStoreUnsignedOffset(const Instruction* instr) { 101 Disassembler::VisitLoadStoreUnsignedOffset(instr); 102 103 if (instr->GetRn() == TR) { 104 int64_t offset = instr->GetImmLSUnsigned() << instr->GetSizeLS(); 105 std::ostringstream tmp_stream; 106 options_->thread_offset_name_function_(tmp_stream, static_cast<uint32_t>(offset)); 107 AppendToOutput(" ; %s", tmp_stream.str().c_str()); 108 } 109 } 110 111 size_t DisassemblerArm64::Dump(std::ostream& os, const uint8_t* begin) { 112 const Instruction* instr = reinterpret_cast<const Instruction*>(begin); 113 decoder.Decode(instr); 114 os << FormatInstructionPointer(begin) 115 << StringPrintf(": %08x\t%s\n", instr->GetInstructionBits(), disasm.GetOutput()); 116 return kInstructionSize; 117 } 118 119 void DisassemblerArm64::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) { 120 for (const uint8_t* cur = begin; cur < end; cur += kInstructionSize) { 121 Dump(os, cur); 122 } 123 } 124 125 } // namespace arm64 126 } // namespace art 127