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 = nullptr; 75 const llvm::MCDisassembler *disassembler = nullptr; 76 const llvm::MCInstrInfo *mc_inst_info = nullptr; 77 const llvm::MCRegisterInfo *mc_reg_info = nullptr; 78 const llvm::MCAsmInfo *asm_info = nullptr; 79 llvm::MCInstPrinter *inst_printer = nullptr; 80 81 BufferMemoryObject *input_function = nullptr; 82 83 std::string error; 84 const llvm::Target* target = 85 llvm::TargetRegistry::lookupTarget(pTriple, error); 86 87 if (target == nullptr) { 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 == nullptr) { 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 == nullptr) || (mc_inst_info == nullptr) || 110 (mc_reg_info == nullptr) || (asm_info == nullptr)) { 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 == nullptr) { 120 result = kDisassembleFailedSetup; 121 goto bail; 122 } 123 124 input_function = new (std::nothrow) BufferMemoryObject(pFunc, pFuncSize); 125 126 if (input_function == nullptr) { 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 == nullptr) { 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