Home | History | Annotate | Download | only in disassembler
      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