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:
BufferMemoryObject(const uint8_t * pBytes,uint64_t pLength)49   BufferMemoryObject(const uint8_t *pBytes, uint64_t pLength)
50     : mBytes(pBytes), mLength(pLength) {
51   }
52 
getBase() const53   virtual uint64_t getBase() const { return 0; }
getExtent() const54   virtual uint64_t getExtent() const { return mLength; }
55 
readByte(uint64_t pAddr,uint8_t * pByte) const56   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 
Disassemble(llvm::raw_ostream & pOutput,const char * pTriple,const char * pFuncName,const uint8_t * pFunc,size_t pFuncSize)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 
Disassemble(OutputFile & pOutput,const char * pTriple,const char * pFuncName,const uint8_t * pFunc,size_t FuncSize)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 
Disassemble(llvm::raw_ostream & pOutput,const char * pTriple,const char * pFuncName,const uint8_t * pFunc,size_t pFuncSize)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 
Disassemble(OutputFile & pOutput,const char * pTriple,const char * pFuncName,const uint8_t * pFunc,size_t pFuncSize)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