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