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