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/disasm-aarch32.h"
     30 #include "aarch32/instructions-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 int32_t offset = label.GetImmediate();
     67           os() << "[pc, #" << offset << "]";
     68           PrintLiteral(type, offset);
     69           return *this;
     70         }
     71         default:
     72           return DisassemblerStream::operator<<(label);
     73       }
     74     }
     75 
     76     DisassemblerStream& operator<<(vixl::aarch32::Register reg) OVERRIDE {
     77       if (reg.Is(tr)) {
     78         os() << "tr";
     79         return *this;
     80       } else {
     81         return DisassemblerStream::operator<<(reg);
     82       }
     83     }
     84 
     85     DisassemblerStream& operator<<(const MemOperand& operand) OVERRIDE {
     86       // VIXL must use a PrintLabel object whenever the base register is PC;
     87       // the following check verifies this invariant, and guards against bugs.
     88       DCHECK(!operand.GetBaseRegister().Is(pc));
     89       DisassemblerStream::operator<<(operand);
     90 
     91       if (operand.GetBaseRegister().Is(tr) && operand.IsImmediate()) {
     92         os() << " ; ";
     93         options_->thread_offset_name_function_(os(), operand.GetOffsetImmediate());
     94       }
     95 
     96       return *this;
     97     }
     98 
     99     DisassemblerStream& operator<<(const vixl::aarch32::AlignedMemOperand& operand) OVERRIDE {
    100       // VIXL must use a PrintLabel object whenever the base register is PC;
    101       // the following check verifies this invariant, and guards against bugs.
    102       DCHECK(!operand.GetBaseRegister().Is(pc));
    103       return DisassemblerStream::operator<<(operand);
    104     }
    105 
    106    private:
    107     void PrintLiteral(LocationType type, int32_t offset);
    108 
    109     const CustomDisassembler* disasm_;
    110     const DisassemblerOptions* options_;
    111   };
    112 
    113  public:
    114   CustomDisassembler(std::ostream& os, const DisassemblerOptions* options)
    115       : PrintDisassembler(&disassembler_stream_),
    116         disassembler_stream_(os, this, options),
    117         is_t32_(true) {}
    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   void SetIsT32(bool is_t32) {
    124     is_t32_ = is_t32;
    125   }
    126 
    127   bool GetIsT32() const {
    128     return is_t32_;
    129   }
    130 
    131  private:
    132   CustomDisassemblerStream disassembler_stream_;
    133   // Whether T32 stream is decoded.
    134   bool is_t32_;
    135 };
    136 
    137 void DisassemblerArm::CustomDisassembler::CustomDisassemblerStream::PrintLiteral(LocationType type,
    138                                                                                  int32_t offset) {
    139   // Literal offsets are not required to be aligned, so we may need unaligned access.
    140   typedef const int16_t unaligned_int16_t __attribute__ ((aligned (1)));
    141   typedef const uint16_t unaligned_uint16_t __attribute__ ((aligned (1)));
    142   typedef const int32_t unaligned_int32_t __attribute__ ((aligned (1)));
    143   typedef const int64_t unaligned_int64_t __attribute__ ((aligned (1)));
    144   typedef const float unaligned_float __attribute__ ((aligned (1)));
    145   typedef const double unaligned_double __attribute__ ((aligned (1)));
    146 
    147   // Zeros are used for the LocationType values this function does not care about.
    148   const size_t literal_size[kVst4Location + 1] = {
    149       0, 0, 0, 0, sizeof(uint8_t), sizeof(unaligned_uint16_t), sizeof(unaligned_int32_t),
    150       sizeof(unaligned_int64_t), sizeof(int8_t), sizeof(unaligned_int16_t),
    151       sizeof(unaligned_float), sizeof(unaligned_double)};
    152   const uintptr_t begin = reinterpret_cast<uintptr_t>(options_->base_address_);
    153   const uintptr_t end = reinterpret_cast<uintptr_t>(options_->end_address_);
    154   uintptr_t literal_addr =
    155       RoundDown(disasm_->GetCodeAddress(), vixl::aarch32::kRegSizeInBytes) + offset;
    156   literal_addr += disasm_->GetIsT32() ? vixl::aarch32::kT32PcDelta : vixl::aarch32::kA32PcDelta;
    157 
    158   if (!options_->absolute_addresses_) {
    159     literal_addr += begin;
    160   }
    161 
    162   os() << "  ; ";
    163 
    164   // Bail out if not within expected buffer range to avoid trying to fetch invalid literals
    165   // (we can encounter them when interpreting raw data as instructions).
    166   if (literal_addr < begin || literal_addr > end - literal_size[type]) {
    167     os() << "(?)";
    168   } else {
    169     switch (type) {
    170       case kLoadByteLocation:
    171         os() << *reinterpret_cast<const uint8_t*>(literal_addr);
    172         break;
    173       case kLoadHalfWordLocation:
    174         os() << *reinterpret_cast<unaligned_uint16_t*>(literal_addr);
    175         break;
    176       case kLoadWordLocation: {
    177         const int32_t value = *reinterpret_cast<unaligned_int32_t*>(literal_addr);
    178         os() << "0x" << std::hex << std::setw(8) << std::setfill('0') << value;
    179         break;
    180       }
    181       case kLoadDoubleWordLocation: {
    182         const int64_t value = *reinterpret_cast<unaligned_int64_t*>(literal_addr);
    183         os() << "0x" << std::hex << std::setw(16) << std::setfill('0') << value;
    184         break;
    185       }
    186       case kLoadSignedByteLocation:
    187         os() << *reinterpret_cast<const int8_t*>(literal_addr);
    188         break;
    189       case kLoadSignedHalfWordLocation:
    190         os() << *reinterpret_cast<unaligned_int16_t*>(literal_addr);
    191         break;
    192       case kLoadSinglePrecisionLocation:
    193         os() << *reinterpret_cast<unaligned_float*>(literal_addr);
    194         break;
    195       case kLoadDoublePrecisionLocation:
    196         os() << *reinterpret_cast<unaligned_double*>(literal_addr);
    197         break;
    198       default:
    199         UNIMPLEMENTED(FATAL) << "Unexpected literal type: " << type;
    200     }
    201   }
    202 }
    203 
    204 DisassemblerArm::DisassemblerArm(DisassemblerOptions* options)
    205     : Disassembler(options), disasm_(std::make_unique<CustomDisassembler>(output_, options)) {}
    206 
    207 size_t DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin) {
    208   uintptr_t next;
    209   // Remove the Thumb specifier bit; no effect if begin does not point to T32 code.
    210   const uintptr_t instr_ptr = reinterpret_cast<uintptr_t>(begin) & ~1;
    211 
    212   const bool is_t32 = (reinterpret_cast<uintptr_t>(begin) & 1) != 0;
    213   disasm_->SetCodeAddress(GetPc(instr_ptr));
    214   disasm_->SetIsT32(is_t32);
    215 
    216   if (is_t32) {
    217     const uint16_t* const ip = reinterpret_cast<const uint16_t*>(instr_ptr);
    218     const uint16_t* const end_address = reinterpret_cast<const uint16_t*>(
    219         GetDisassemblerOptions()->end_address_);
    220     next = reinterpret_cast<uintptr_t>(disasm_->DecodeT32At(ip, end_address));
    221   } else {
    222     const uint32_t* const ip = reinterpret_cast<const uint32_t*>(instr_ptr);
    223     next = reinterpret_cast<uintptr_t>(disasm_->DecodeA32At(ip));
    224   }
    225 
    226   os << output_.str();
    227   output_.str(std::string());
    228   return next - instr_ptr;
    229 }
    230 
    231 void DisassemblerArm::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) {
    232   DCHECK_LE(begin, end);
    233 
    234   // Remove the Thumb specifier bit; no effect if begin does not point to T32 code.
    235   const uintptr_t base = reinterpret_cast<uintptr_t>(begin) & ~1;
    236 
    237   const bool is_t32 = (reinterpret_cast<uintptr_t>(begin) & 1) != 0;
    238   disasm_->SetCodeAddress(GetPc(base));
    239   disasm_->SetIsT32(is_t32);
    240 
    241   if (is_t32) {
    242     // The Thumb specifier bits cancel each other.
    243     disasm_->DisassembleT32Buffer(reinterpret_cast<const uint16_t*>(base), end - begin);
    244   } else {
    245     disasm_->DisassembleA32Buffer(reinterpret_cast<const uint32_t*>(base), end - begin);
    246   }
    247 
    248   os << output_.str();
    249   output_.str(std::string());
    250 }
    251 
    252 }  // namespace arm
    253 }  // namespace art
    254