Home | History | Annotate | Download | only in disassembler
      1 /*
      2  * Copyright (C) 2012 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_arm.h"
     18 
     19 #include <memory>
     20 #include <string>
     21 
     22 #include "android-base/logging.h"
     23 
     24 #include "arch/arm/registers_arm.h"
     25 #include "base/bit_utils.h"
     26 
     27 #pragma GCC diagnostic push
     28 #pragma GCC diagnostic ignored "-Wshadow"
     29 #include "aarch32/instructions-aarch32.h"
     30 #include "aarch32/disasm-aarch32.h"
     31 #pragma GCC diagnostic pop
     32 
     33 namespace art {
     34 namespace arm {
     35 
     36 using vixl::aarch32::MemOperand;
     37 using vixl::aarch32::PrintDisassembler;
     38 using vixl::aarch32::pc;
     39 
     40 static const vixl::aarch32::Register tr(TR);
     41 
     42 class DisassemblerArm::CustomDisassembler FINAL : public PrintDisassembler {
     43   class CustomDisassemblerStream FINAL : public DisassemblerStream {
     44    public:
     45     CustomDisassemblerStream(std::ostream& os,
     46                              const CustomDisassembler* disasm,
     47                              const DisassemblerOptions* options)
     48         : DisassemblerStream(os), disasm_(disasm), options_(options) {}
     49 
     50     DisassemblerStream& operator<<(const PrintLabel& label) OVERRIDE {
     51       const LocationType type = label.GetLocationType();
     52 
     53       switch (type) {
     54         case kLoadByteLocation:
     55         case kLoadHalfWordLocation:
     56         case kLoadWordLocation:
     57         case kLoadDoubleWordLocation:
     58         case kLoadSignedByteLocation:
     59         case kLoadSignedHalfWordLocation:
     60         case kLoadSinglePrecisionLocation:
     61         case kLoadDoublePrecisionLocation:
     62         case kVld1Location:
     63         case kVld2Location:
     64         case kVld3Location:
     65         case kVld4Location: {
     66           const uintptr_t pc_delta = label.GetLabel()->GetPcOffset();
     67           const int32_t offset = label.GetLabel()->GetLocation();
     68 
     69           os() << "[pc, #" << offset - pc_delta << "]";
     70           PrintLiteral(type, offset);
     71           return *this;
     72         }
     73         default:
     74           return DisassemblerStream::operator<<(label);
     75       }
     76     }
     77 
     78     DisassemblerStream& operator<<(vixl::aarch32::Register reg) OVERRIDE {
     79       if (reg.Is(tr)) {
     80         os() << "tr";
     81         return *this;
     82       } else {
     83         return DisassemblerStream::operator<<(reg);
     84       }
     85     }
     86 
     87     DisassemblerStream& operator<<(const MemOperand& operand) OVERRIDE {
     88       // VIXL must use a PrintLabel object whenever the base register is PC;
     89       // the following check verifies this invariant, and guards against bugs.
     90       DCHECK(!operand.GetBaseRegister().Is(pc));
     91       DisassemblerStream::operator<<(operand);
     92 
     93       if (operand.GetBaseRegister().Is(tr) && operand.IsImmediate()) {
     94         os() << " ; ";
     95         options_->thread_offset_name_function_(os(), operand.GetOffsetImmediate());
     96       }
     97 
     98       return *this;
     99     }
    100 
    101     DisassemblerStream& operator<<(const vixl::aarch32::AlignedMemOperand& operand) OVERRIDE {
    102       // VIXL must use a PrintLabel object whenever the base register is PC;
    103       // the following check verifies this invariant, and guards against bugs.
    104       DCHECK(!operand.GetBaseRegister().Is(pc));
    105       return DisassemblerStream::operator<<(operand);
    106     }
    107 
    108    private:
    109     void PrintLiteral(LocationType type, int32_t offset);
    110 
    111     const CustomDisassembler* disasm_;
    112     const DisassemblerOptions* options_;
    113   };
    114 
    115  public:
    116   CustomDisassembler(std::ostream& os, const DisassemblerOptions* options)
    117       : PrintDisassembler(&disassembler_stream_), disassembler_stream_(os, this, options) {}
    118 
    119   void PrintCodeAddress(uint32_t prog_ctr) OVERRIDE {
    120     os() << "0x" << std::hex << std::setw(8) << std::setfill('0') << prog_ctr << ": ";
    121   }
    122 
    123  private:
    124   CustomDisassemblerStream disassembler_stream_;
    125 };
    126 
    127 void DisassemblerArm::CustomDisassembler::CustomDisassemblerStream::PrintLiteral(LocationType type,
    128                                                                                  int32_t offset) {
    129   // Literal offsets are not required to be aligned, so we may need unaligned access.
    130   typedef const int16_t unaligned_int16_t __attribute__ ((aligned (1)));
    131   typedef const uint16_t unaligned_uint16_t __attribute__ ((aligned (1)));
    132   typedef const int32_t unaligned_int32_t __attribute__ ((aligned (1)));
    133   typedef const int64_t unaligned_int64_t __attribute__ ((aligned (1)));
    134   typedef const float unaligned_float __attribute__ ((aligned (1)));
    135   typedef const double unaligned_double __attribute__ ((aligned (1)));
    136 
    137   // Zeros are used for the LocationType values this function does not care about.
    138   const size_t literal_size[kVst4Location + 1] = {
    139       0, 0, 0, 0, sizeof(uint8_t), sizeof(unaligned_uint16_t), sizeof(unaligned_int32_t),
    140       sizeof(unaligned_int64_t), sizeof(int8_t), sizeof(unaligned_int16_t),
    141       sizeof(unaligned_float), sizeof(unaligned_double)};
    142   const uintptr_t begin = reinterpret_cast<uintptr_t>(options_->base_address_);
    143   const uintptr_t end = reinterpret_cast<uintptr_t>(options_->end_address_);
    144   uintptr_t literal_addr = RoundDown(disasm_->GetCodeAddress(), vixl::aarch32::kRegSizeInBytes) + offset;
    145 
    146   if (!options_->absolute_addresses_) {
    147     literal_addr += begin;
    148   }
    149 
    150   os() << "  ; ";
    151 
    152   // Bail out if not within expected buffer range to avoid trying to fetch invalid literals
    153   // (we can encounter them when interpreting raw data as instructions).
    154   if (literal_addr < begin || literal_addr > end - literal_size[type]) {
    155     os() << "(?)";
    156   } else {
    157     switch (type) {
    158       case kLoadByteLocation:
    159         os() << *reinterpret_cast<const uint8_t*>(literal_addr);
    160         break;
    161       case kLoadHalfWordLocation:
    162         os() << *reinterpret_cast<unaligned_uint16_t*>(literal_addr);
    163         break;
    164       case kLoadWordLocation: {
    165         const int32_t value = *reinterpret_cast<unaligned_int32_t*>(literal_addr);
    166         os() << "0x" << std::hex << std::setw(8) << std::setfill('0') << value;
    167         break;
    168       }
    169       case kLoadDoubleWordLocation: {
    170         const int64_t value = *reinterpret_cast<unaligned_int64_t*>(literal_addr);
    171         os() << "0x" << std::hex << std::setw(16) << std::setfill('0') << value;
    172         break;
    173       }
    174       case kLoadSignedByteLocation:
    175         os() << *reinterpret_cast<const int8_t*>(literal_addr);
    176         break;
    177       case kLoadSignedHalfWordLocation:
    178         os() << *reinterpret_cast<unaligned_int16_t*>(literal_addr);
    179         break;
    180       case kLoadSinglePrecisionLocation:
    181         os() << *reinterpret_cast<unaligned_float*>(literal_addr);
    182         break;
    183       case kLoadDoublePrecisionLocation:
    184         os() << *reinterpret_cast<unaligned_double*>(literal_addr);
    185         break;
    186       default:
    187         UNIMPLEMENTED(FATAL) << "Unexpected literal type: " << type;
    188     }
    189   }
    190 }
    191 
    192 DisassemblerArm::DisassemblerArm(DisassemblerOptions* options)
    193     : Disassembler(options), disasm_(std::make_unique<CustomDisassembler>(output_, options)) {}
    194 
    195 size_t DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin) {
    196   uintptr_t next;
    197   // Remove the Thumb specifier bit; no effect if begin does not point to T32 code.
    198   const uintptr_t instr_ptr = reinterpret_cast<uintptr_t>(begin) & ~1;
    199 
    200   const bool is_t32 = (reinterpret_cast<uintptr_t>(begin) & 1) != 0;
    201   disasm_->SetCodeAddress(GetPc(instr_ptr));
    202 
    203   if (is_t32) {
    204     const uint16_t* const ip = reinterpret_cast<const uint16_t*>(instr_ptr);
    205     const uint16_t* const end_address = reinterpret_cast<const uint16_t*>(
    206         GetDisassemblerOptions()->end_address_);
    207     next = reinterpret_cast<uintptr_t>(disasm_->DecodeT32At(ip, end_address));
    208   } else {
    209     const uint32_t* const ip = reinterpret_cast<const uint32_t*>(instr_ptr);
    210     next = reinterpret_cast<uintptr_t>(disasm_->DecodeA32At(ip));
    211   }
    212 
    213   os << output_.str();
    214   output_.str(std::string());
    215   return next - instr_ptr;
    216 }
    217 
    218 void DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) {
    219   DCHECK_LE(begin, end);
    220 
    221   // Remove the Thumb specifier bit; no effect if begin does not point to T32 code.
    222   const uintptr_t base = reinterpret_cast<uintptr_t>(begin) & ~1;
    223 
    224   const bool is_t32 = (reinterpret_cast<uintptr_t>(begin) & 1) != 0;
    225   disasm_->SetCodeAddress(GetPc(base));
    226 
    227   if (is_t32) {
    228     // The Thumb specifier bits cancel each other.
    229     disasm_->DisassembleT32Buffer(reinterpret_cast<const uint16_t*>(base), end - begin);
    230   } else {
    231     disasm_->DisassembleA32Buffer(reinterpret_cast<const uint32_t*>(base), end - begin);
    232   }
    233 
    234   os << output_.str();
    235   output_.str(std::string());
    236 }
    237 
    238 }  // namespace arm
    239 }  // namespace art
    240