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
41namespace {
42
43class BufferMemoryObject : public llvm::MemoryObject {
44private:
45  const uint8_t *mBytes;
46  uint64_t mLength;
47
48public:
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
66namespace bcc {
67
68DisassembleResult 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
173bail:
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
186DisassembleResult 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
214bcc::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
220bcc::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