Home | History | Annotate | Download | only in Support
      1 /*
      2  * Copyright 2011-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 "bcc/Support/Disassembler.h"
     18 
     19 #include "bcc/Config/Config.h"
     20 #if USE_DISASSEMBLER
     21 
     22 #include <string>
     23 
     24 #include <llvm/IR/LLVMContext.h>
     25 
     26 #include <llvm/MC/MCAsmInfo.h>
     27 #include <llvm/MC/MCDisassembler.h>
     28 #include <llvm/MC/MCInst.h>
     29 #include <llvm/MC/MCInstPrinter.h>
     30 #include <llvm/MC/MCInstrInfo.h>
     31 #include <llvm/MC/MCRegisterInfo.h>
     32 #include <llvm/MC/MCSubtargetInfo.h>
     33 
     34 #include <llvm/Support/MemoryObject.h>
     35 #include <llvm/Support/TargetRegistry.h>
     36 #include <llvm/Support/raw_ostream.h>
     37 
     38 #include "bcc/Support/OutputFile.h"
     39 #include "bcc/Support/Log.h"
     40 
     41 namespace {
     42 
     43 class BufferMemoryObject : public llvm::MemoryObject {
     44 private:
     45   const uint8_t *mBytes;
     46   uint64_t mLength;
     47 
     48 public:
     49   BufferMemoryObject(const uint8_t *pBytes, uint64_t pLength)
     50     : mBytes(pBytes), mLength(pLength) {
     51   }
     52 
     53   virtual uint64_t getBase() const { return 0; }
     54   virtual uint64_t getExtent() const { return mLength; }
     55 
     56   virtual int readByte(uint64_t pAddr, uint8_t *pByte) const {
     57     if (pAddr > getExtent())
     58       return -1;
     59     *pByte = mBytes[pAddr];
     60     return 0;
     61   }
     62 };
     63 
     64 } // namespace anonymous
     65 
     66 namespace bcc {
     67 
     68 DisassembleResult Disassemble(llvm::raw_ostream &pOutput, const char *pTriple,
     69                               const char *pFuncName, const uint8_t *pFunc,
     70                               size_t pFuncSize) {
     71   DisassembleResult result = kDisassembleSuccess;
     72   uint64_t i = 0;
     73 
     74   const llvm::MCSubtargetInfo *subtarget_info = NULL;
     75   const llvm::MCDisassembler *disassembler = NULL;
     76   const llvm::MCInstrInfo *mc_inst_info = NULL;
     77   const llvm::MCRegisterInfo *mc_reg_info = NULL;
     78   const llvm::MCAsmInfo *asm_info = NULL;
     79   llvm::MCInstPrinter *inst_printer = NULL;
     80 
     81   BufferMemoryObject *input_function = NULL;
     82 
     83   std::string error;
     84   const llvm::Target* target =
     85       llvm::TargetRegistry::lookupTarget(pTriple, error);
     86 
     87   if (target == NULL) {
     88     ALOGE("Invalid target triple for disassembler: %s (%s)!",
     89           pTriple, error.c_str());
     90     return kDisassembleUnknownTarget;
     91   }
     92 
     93   subtarget_info =
     94       target->createMCSubtargetInfo(pTriple, /* CPU */"", /* Features */"");;
     95 
     96   if (subtarget_info == NULL) {
     97     result = kDisassembleFailedSetup;
     98     goto bail;
     99   }
    100 
    101   disassembler = target->createMCDisassembler(*subtarget_info);
    102 
    103   mc_inst_info = target->createMCInstrInfo();
    104 
    105   mc_reg_info = target->createMCRegInfo(pTriple);
    106 
    107   asm_info = target->createMCAsmInfo(pTriple);
    108 
    109   if ((disassembler == NULL) || (mc_inst_info == NULL) ||
    110       (mc_reg_info == NULL) || (asm_info == NULL)) {
    111     result = kDisassembleFailedSetup;
    112     goto bail;
    113   }
    114 
    115   inst_printer = target->createMCInstPrinter(asm_info->getAssemblerDialect(),
    116                                              *asm_info, *mc_inst_info,
    117                                              *mc_reg_info, *subtarget_info);
    118 
    119   if (inst_printer == NULL) {
    120     result = kDisassembleFailedSetup;
    121     goto bail;
    122   }
    123 
    124   input_function = new (std::nothrow) BufferMemoryObject(pFunc, pFuncSize);
    125 
    126   if (input_function == NULL) {
    127     result = kDisassembleOutOfMemory;
    128     goto bail;
    129   }
    130 
    131   // Disassemble the given function
    132   pOutput << "Disassembled code: " << pFuncName << "\n";
    133 
    134   while (i < pFuncSize) {
    135     llvm::MCInst inst;
    136     uint64_t inst_size;
    137 
    138     llvm::MCDisassembler::DecodeStatus decode_result =
    139         disassembler->getInstruction(inst, inst_size, *input_function, i,
    140                                      llvm::nulls(), llvm::nulls());
    141 
    142     switch (decode_result) {
    143       case llvm::MCDisassembler::Fail: {
    144         ALOGW("Invalid instruction encoding encountered at %llu of function %s "
    145               "under %s.", i, pFuncName, pTriple);
    146         i++;
    147         break;
    148       }
    149       case llvm::MCDisassembler::SoftFail: {
    150         ALOGW("Potentially undefined instruction encoding encountered at %llu "
    151               "of function %s under %s.", i, pFuncName, pTriple);
    152         // fall-through
    153       }
    154       case llvm::MCDisassembler::Success : {
    155         const uint8_t *inst_addr = pFunc + i;
    156 
    157         pOutput.indent(4);
    158         pOutput << "0x";
    159         pOutput.write_hex(reinterpret_cast<uintptr_t>(inst_addr));
    160         pOutput << ": 0x";
    161         pOutput.write_hex(*reinterpret_cast<const uint32_t *>(inst_addr));
    162         inst_printer->printInst(&inst, pOutput, /* Annot */"");
    163         pOutput << "\n";
    164 
    165         i += inst_size;
    166         break;
    167       }
    168     }
    169   }
    170 
    171   pOutput << "\n";
    172 
    173 bail:
    174   // Clean up
    175   delete input_function;
    176   delete inst_printer;
    177   delete asm_info;
    178   delete mc_reg_info;
    179   delete mc_inst_info;
    180   delete disassembler;
    181   delete subtarget_info;
    182 
    183   return result;
    184 }
    185 
    186 DisassembleResult Disassemble(OutputFile &pOutput, const char *pTriple,
    187                               const char *pFuncName, const uint8_t *pFunc,
    188                               size_t FuncSize) {
    189   // Check the state of the specified output file.
    190   if (pOutput.hasError()) {
    191     return kDisassembleInvalidOutput;
    192   }
    193 
    194   // Open the output file decorated in llvm::raw_ostream.
    195   llvm::raw_ostream *output = pOutput.dup();
    196   if (output == NULL) {
    197     return kDisassembleFailedPrepareOutput;
    198   }
    199 
    200   // Delegate the request.
    201   DisassembleResult result =
    202       Disassemble(*output, pTriple, pFuncName, pFunc, FuncSize);
    203 
    204   // Close the output before return.
    205   delete output;
    206 
    207   return result;
    208 }
    209 
    210 } // namespace bcc
    211 
    212 #else
    213 
    214 bcc::DisassembleResult Disassemble(llvm::raw_ostream &pOutput,
    215                                    const char *pTriple, const char *pFuncName,
    216                                    const uint8_t *pFunc, size_t pFuncSize) {
    217   return bcc::kDisassemblerNotAvailable;
    218 }
    219 
    220 bcc::DisassembleResult bcc::Disassemble(OutputFile &pOutput,
    221                                         const char *pTriple,
    222                                         const char *pFuncName,
    223                                         const uint8_t *pFunc,
    224                                         size_t pFuncSize) {
    225   return bcc::kDisassemblerNotAvailable;
    226 }
    227 
    228 #endif // USE_DISASSEMBLER
    229