bcc::Disassemble() API. BUG=6841435.

Change-Id: Ie249f47ba2856aac300061e53dfd34b3ada999f7
diff --git a/include/bcc/Support/Disassembler.h b/include/bcc/Support/Disassembler.h
index 799a562..0ec0eed 100644
--- a/include/bcc/Support/Disassembler.h
+++ b/include/bcc/Support/Disassembler.h
@@ -17,30 +17,36 @@
 #ifndef BCC_SUPPORT_DISASSEMBLER_H
 #define BCC_SUPPORT_DISASSEMBLER_H
 
-#include "bcc/Config/Config.h"
-
-#if USE_DISASSEMBLER
-
-#include <string>
+#include <stdint.h>
+#include <stddef.h>
 
 namespace llvm {
-  class Target;
-  class TargetMachine;
-}
+  class raw_ostream;
+} // end namespace llvm
 
 namespace bcc {
 
-void InitializeDisassembler();
+class OutputFile;
 
-void Disassemble(char const *OutputFileName,
-                 llvm::Target const *Target,
-                 llvm::TargetMachine *TM,
-                 std::string const &Name,
-                 unsigned char const *Func,
-                 size_t FuncSize);
+enum DisassembleResult {
+  kDisassembleSuccess,
+  kDisassemblerNotAvailable,
+  kDisassembleInvalidOutput,
+  kDisassembleFailedPrepareOutput,
+  kDisassembleUnknownTarget,
+  kDisassembleFailedSetup,
+  kDisassembleOutOfMemory,
+  kDisassembleInvalidInstruction,
+};
+
+DisassembleResult Disassemble(llvm::raw_ostream &pOutput, const char *pTriple,
+                              const char *pFuncName, const uint8_t *pFunc,
+                              size_t pFuncSize);
+
+DisassembleResult Disassemble(OutputFile &pOutput, const char *pTriple,
+                              const char *pFuncName, const uint8_t *pFunc,
+                              size_t pFuncSize);
 
 } // end namespace bcc
 
-#endif // USE_DISASSEMBLER
-
 #endif // BCC_SUPPORT_DISASSEMBLER_H
diff --git a/lib/Support/Android.mk b/lib/Support/Android.mk
index 339009d..ca4aa61 100644
--- a/lib/Support/Android.mk
+++ b/lib/Support/Android.mk
@@ -23,6 +23,7 @@
 
 libbcc_support_SRC_FILES := \
   CompilerConfig.cpp \
+  Disassembler.cpp \
   FileBase.cpp \
   Initialization.cpp \
   InputFile.cpp \
@@ -32,10 +33,6 @@
   TargetCompilerConfigs.cpp \
   TargetLinkerConfigs.cpp
 
-ifeq ($(libbcc_USE_DISASSEMBLER),1)
-libbcc_support_SRC_FILES += Disassembler.cpp
-endif
-
 #=====================================================================
 # Device Static Library: libbccSupport
 #=====================================================================
diff --git a/lib/Support/Disassembler.cpp b/lib/Support/Disassembler.cpp
index 4b78c15..5a1d017 100644
--- a/lib/Support/Disassembler.cpp
+++ b/lib/Support/Disassembler.cpp
@@ -16,27 +16,28 @@
 
 #include "bcc/Support/Disassembler.h"
 
+#include "bcc/Config/Config.h"
+#if USE_DISASSEMBLER
+
+#include <string>
+
 #include <llvm/LLVMContext.h>
 
 #include <llvm/MC/MCAsmInfo.h>
 #include <llvm/MC/MCDisassembler.h>
 #include <llvm/MC/MCInst.h>
 #include <llvm/MC/MCInstPrinter.h>
+#include <llvm/MC/MCInstrInfo.h>
+#include <llvm/MC/MCRegisterInfo.h>
+#include <llvm/MC/MCSubtargetInfo.h>
 
 #include <llvm/Support/MemoryObject.h>
 #include <llvm/Support/TargetRegistry.h>
-#include <llvm/Support/TargetSelect.h>
 #include <llvm/Support/raw_ostream.h>
 
-#include <llvm/Target/TargetData.h>
-#include <llvm/Target/TargetMachine.h>
-#include <llvm/Target/TargetOptions.h>
-
-#include "bcc/Config/Config.h"
+#include "bcc/Support/OutputFile.h"
 #include "bcc/Support/Log.h"
 
-#if USE_DISASSEMBLER
-
 namespace {
 
 class BufferMemoryObject : public llvm::MemoryObject {
@@ -45,17 +46,17 @@
   uint64_t mLength;
 
 public:
-  BufferMemoryObject(const uint8_t *Bytes, uint64_t Length)
-    : mBytes(Bytes), mLength(Length) {
+  BufferMemoryObject(const uint8_t *pBytes, uint64_t pLength)
+    : mBytes(pBytes), mLength(pLength) {
   }
 
   virtual uint64_t getBase() const { return 0; }
   virtual uint64_t getExtent() const { return mLength; }
 
-  virtual int readByte(uint64_t Addr, uint8_t *Byte) const {
-    if (Addr > getExtent())
+  virtual int readByte(uint64_t pAddr, uint8_t *pByte) const {
+    if (pAddr > getExtent())
       return -1;
-    *Byte = mBytes[Addr];
+    *pByte = mBytes[pAddr];
     return 0;
   }
 };
@@ -64,96 +65,164 @@
 
 namespace bcc {
 
-void InitializeDisassembler() {
-#if defined(PROVIDE_ARM_CODEGEN)
-  LLVMInitializeARMDisassembler();
-#endif
+DisassembleResult Disassemble(llvm::raw_ostream &pOutput, const char *pTriple,
+                              const char *pFuncName, const uint8_t *pFunc,
+                              size_t pFuncSize) {
+  DisassembleResult result = kDisassembleSuccess;
+  uint64_t i = 0;
 
-#if defined(PROVIDE_MIPS_CODEGEN)
-  LLVMInitializeMipsDisassembler();
-#endif
+  const llvm::MCSubtargetInfo *subtarget_info = NULL;
+  const llvm::MCDisassembler *disassembler = NULL;
+  const llvm::MCInstrInfo *mc_inst_info = NULL;
+  const llvm::MCRegisterInfo *mc_reg_info = NULL;
+  const llvm::MCAsmInfo *asm_info = NULL;
+  llvm::MCInstPrinter *inst_printer = NULL;
 
-#if defined(PROVIDE_X86_CODEGEN)
-  LLVMInitializeX86Disassembler();
-#endif
-}
+  BufferMemoryObject *input_function = NULL;
 
-void Disassemble(char const *OutputFileName,
-                 llvm::Target const *Target,
-                 llvm::TargetMachine *TM,
-                 std::string const &Name,
-                 unsigned char const *Func,
-                 size_t FuncSize) {
+  std::string error;
+  const llvm::Target* target =
+      llvm::TargetRegistry::lookupTarget(pTriple, error);
 
-  std::string ErrorInfo;
-
-  // Open the disassembler output file
-  llvm::raw_fd_ostream OS(OutputFileName, ErrorInfo,
-                          llvm::raw_fd_ostream::F_Append);
-
-  if (!ErrorInfo.empty()) {
-    ALOGE("Unable to open disassembler output file: %s\n", OutputFileName);
-    return;
+  if (target == NULL) {
+    ALOGE("Invalid target triple for disassembler: %s (%s)!",
+          pTriple, error.c_str());
+    return kDisassembleUnknownTarget;
   }
 
-  ALOGI("Writing LLVM disassembly to file: %s\n", OutputFileName);
+  subtarget_info =
+      target->createMCSubtargetInfo(pTriple, /* CPU */"", /* Features */"");;
+
+  if (subtarget_info == NULL) {
+    result = kDisassembleFailedSetup;
+    goto bail;
+  }
+
+  disassembler = target->createMCDisassembler(*subtarget_info);
+
+  mc_inst_info = target->createMCInstrInfo();
+
+  mc_reg_info = target->createMCRegInfo(pTriple);
+
+  asm_info = target->createMCAsmInfo(pTriple);
+
+  if ((disassembler == NULL) || (mc_inst_info == NULL) ||
+      (mc_reg_info == NULL) || (asm_info == NULL)) {
+    result = kDisassembleFailedSetup;
+    goto bail;
+  }
+
+  inst_printer = target->createMCInstPrinter(asm_info->getAssemblerDialect(),
+                                             *asm_info, *mc_inst_info,
+                                             *mc_reg_info, *subtarget_info);
+
+  if (inst_printer == NULL) {
+    result = kDisassembleFailedSetup;
+    goto bail;
+  }
+
+  input_function = new (std::nothrow) BufferMemoryObject(pFunc, pFuncSize);
+
+  if (input_function == NULL) {
+    result = kDisassembleOutOfMemory;
+    goto bail;
+  }
+
   // Disassemble the given function
-  OS << "Disassembled code: " << Name << "\n";
+  pOutput << "Disassembled code: " << pFuncName << "\n";
 
-  const llvm::MCAsmInfo *AsmInfo;
-  const llvm::MCSubtargetInfo *SubtargetInfo;
-  const llvm::MCDisassembler *Disassembler;
-  llvm::MCInstPrinter *IP;
+  while (i < pFuncSize) {
+    llvm::MCInst inst;
+    uint64_t inst_size;
 
-  const std::string& TripleName(Compiler::getTargetTriple());
+    llvm::MCDisassembler::DecodeStatus decode_result =
+        disassembler->getInstruction(inst, inst_size, *input_function, i,
+                                     llvm::nulls(), llvm::nulls());
 
-  AsmInfo = Target->createMCAsmInfo(Compiler::getTargetTriple());
-  SubtargetInfo = Target->createMCSubtargetInfo(TripleName, "", "");
-  Disassembler = Target->createMCDisassembler(*SubtargetInfo);
+    switch (decode_result) {
+      case llvm::MCDisassembler::Fail: {
+        ALOGW("Invalid instruction encoding encountered at %llu of function %s "
+              "under %s.", i, pFuncName, pTriple);
+        i++;
+        break;
+      }
+      case llvm::MCDisassembler::SoftFail: {
+        ALOGW("Potentially undefined instruction encoding encountered at %llu "
+              "of function %s under %s.", i, pFuncName, pTriple);
+        // fall-through
+      }
+      case llvm::MCDisassembler::Success : {
+        const uint8_t *inst_addr = pFunc + i;
 
-  const llvm::MCInstrInfo *MII = Target->createMCInstrInfo();
-  const llvm::MCRegisterInfo *MRI = Target->createMCRegInfo(TripleName);
+        pOutput.indent(4);
+        pOutput << "0x";
+        pOutput.write_hex(reinterpret_cast<uintptr_t>(inst_addr));
+        pOutput << ": 0x";
+        pOutput.write_hex(*reinterpret_cast<const uint32_t *>(inst_addr));
+        inst_printer->printInst(&inst, pOutput, /* Annot */"");
+        pOutput << "\n";
 
-  IP = Target->createMCInstPrinter(AsmInfo->getAssemblerDialect(),
-                                   *AsmInfo,
-                                   *MII,
-                                   *MRI,
-                                   *SubtargetInfo);
-
-  const BufferMemoryObject *BufferMObj = new BufferMemoryObject(Func, FuncSize);
-
-  uint64_t Size;
-  uint64_t Index;
-
-  for (Index = 0; Index < FuncSize; Index += Size) {
-    llvm::MCInst Inst;
-
-    if (Disassembler->getInstruction(Inst, Size, *BufferMObj, Index,
-                           /* REMOVED */ llvm::nulls(), llvm::nulls())) {
-      OS.indent(4);
-      OS.write("0x", 2);
-      OS.write_hex((uint32_t)Func + Index);
-      OS.write(": 0x", 4);
-      OS.write_hex(*(uint32_t *)(Func + Index));
-      IP->printInst(&Inst, OS, "");
-      OS << "\n";
-    } else {
-      if (Size == 0)
-        Size = 1;  // skip illegible bytes
+        i += inst_size;
+        break;
+      }
     }
   }
 
-  OS << "\n";
+  pOutput << "\n";
 
-  delete BufferMObj;
+bail:
+  // Clean up
+  delete input_function;
+  delete inst_printer;
+  delete asm_info;
+  delete mc_reg_info;
+  delete mc_inst_info;
+  delete disassembler;
+  delete subtarget_info;
 
-  delete AsmInfo;
-  delete Disassembler;
-  delete IP;
+  return result;
+}
 
-  OS.close();
+DisassembleResult Disassemble(OutputFile &pOutput, const char *pTriple,
+                              const char *pFuncName, const uint8_t *pFunc,
+                              size_t FuncSize) {
+  // Check the state of the specified output file.
+  if (pOutput.hasError()) {
+    return kDisassembleInvalidOutput;
+  }
+
+  // Open the output file decorated in llvm::raw_ostream.
+  llvm::raw_ostream *output = pOutput.dup();
+  if (output == NULL) {
+    return kDisassembleFailedPrepareOutput;
+  }
+
+  // Delegate the request.
+  DisassembleResult result =
+      Disassemble(*output, pTriple, pFuncName, pFunc, FuncSize);
+
+  // Close the output before return.
+  delete output;
+
+  return result;
 }
 
 } // namespace bcc
 
+#else
+
+bcc::DisassembleResult Disassemble(llvm::raw_ostream &pOutput,
+                                   const char *pTriple, const char *pFuncName,
+                                   const uint8_t *pFunc, size_t pFuncSize) {
+  return bcc::kDisassemblerNotAvailable;
+}
+
+bcc::DisassembleResult bcc::Disassemble(OutputFile &pOutput,
+                                        const char *pTriple,
+                                        const char *pFuncName,
+                                        const uint8_t *pFunc,
+                                        size_t pFuncSize) {
+  return bcc::kDisassemblerNotAvailable;
+}
+
 #endif // USE_DISASSEMBLER
diff --git a/lib/Support/Initialization.cpp b/lib/Support/Initialization.cpp
index 335ac44..6951a05 100644
--- a/lib/Support/Initialization.cpp
+++ b/lib/Support/Initialization.cpp
@@ -49,6 +49,9 @@
 
 #if defined(PROVIDE_ARM_CODEGEN)
   LLVMInitializeARMAsmPrinter();
+# if USE_DISASSEMBLER
+  LLVMInitializeARMDisassembler();
+# endif
   LLVMInitializeARMTargetMC();
   LLVMInitializeARMTargetInfo();
   LLVMInitializeARMTarget();
@@ -60,6 +63,9 @@
 
 #if defined(PROVIDE_MIPS_CODEGEN)
   LLVMInitializeMipsAsmPrinter();
+# if USE_DISASSEMBLER
+  LLVMInitializeMipsDisassembler();
+# endif
   LLVMInitializeMipsTargetMC();
   LLVMInitializeMipsTargetInfo();
   LLVMInitializeMipsTarget();
@@ -71,6 +77,9 @@
 
 #if defined(PROVIDE_X86_CODEGEN)
   LLVMInitializeX86AsmPrinter();
+# if USE_DISASSEMBLER
+  LLVMInitializeX86Disassembler();
+# endif
   LLVMInitializeX86TargetMC();
   LLVMInitializeX86TargetInfo();
   LLVMInitializeX86Target();
@@ -80,10 +89,6 @@
   LLVMInitializeX86DiagnosticLineInfo();
 #endif
 
-#if USE_DISASSEMBLER
-  InitializeDisassembler();
-#endif
-
   is_initialized = true;
 
   return;