From bafb39ebc5d7b3a3485cd983c333c37ef56a0215 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Sun, 28 Jan 2018 17:56:26 +0000
Subject: [PATCH] A64: Add Disassemble method

---
 include/dynarmic/A64/a64.h          |  7 ++++
 src/CMakeLists.txt                  |  3 ++
 src/backend_x64/a32_interface.cpp   | 34 +----------------
 src/backend_x64/a64_interface.cpp   |  9 +++++
 src/backend_x64/block_of_code.cpp   |  4 ++
 src/backend_x64/block_of_code.h     |  2 +
 src/backend_x64/disassemble_x64.cpp | 58 +++++++++++++++++++++++++++++
 src/backend_x64/disassemble_x64.h   | 13 +++++++
 8 files changed, 98 insertions(+), 32 deletions(-)
 create mode 100644 src/backend_x64/disassemble_x64.cpp
 create mode 100644 src/backend_x64/disassemble_x64.h

diff --git a/include/dynarmic/A64/a64.h b/include/dynarmic/A64/a64.h
index 73a19706..26238583 100644
--- a/include/dynarmic/A64/a64.h
+++ b/include/dynarmic/A64/a64.h
@@ -10,6 +10,7 @@
 #include <cstddef>
 #include <cstdint>
 #include <memory>
+#include <string>
 
 #include <dynarmic/A64/config.h>
 
@@ -100,6 +101,12 @@ public:
      */
     bool IsExecuting() const;
 
+    /**
+     * Debugging: Disassemble all of compiled code.
+     * @return A string containing disassembly of all host machine code produced.
+     */
+    std::string Disassemble() const;
+
 private:
     struct Impl;
     std::unique_ptr<Impl> impl;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 48c1c673..0ec2974b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -132,6 +132,9 @@ if (ARCHITECTURE_x86_64)
          backend_x64/callback.h
          backend_x64/constant_pool.cpp
          backend_x64/constant_pool.h
+         backend_x64/devirtualize.h
+         backend_x64/disassemble_x64.cpp
+         backend_x64/disassemble_x64.h
          backend_x64/emit_x64.cpp
          backend_x64/emit_x64.h
          backend_x64/emit_x64_crc32.cpp
diff --git a/src/backend_x64/a32_interface.cpp b/src/backend_x64/a32_interface.cpp
index 1583c042..48d63457 100644
--- a/src/backend_x64/a32_interface.cpp
+++ b/src/backend_x64/a32_interface.cpp
@@ -19,6 +19,7 @@
 #include "backend_x64/block_of_code.h"
 #include "backend_x64/callback.h"
 #include "backend_x64/devirtualize.h"
+#include "backend_x64/disassemble_x64.h"
 #include "backend_x64/jitstate_info.h"
 #include "common/assert.h"
 #include "common/common_types.h"
@@ -73,38 +74,7 @@ struct Jit::Impl {
     std::string Disassemble(const IR::LocationDescriptor& descriptor) {
         auto block = GetBasicBlock(descriptor);
         std::string result = fmt::format("address: {}\nsize: {} bytes\n", block.entrypoint, block.size);
-
-#ifdef DYNARMIC_USE_LLVM
-        LLVMInitializeX86TargetInfo();
-        LLVMInitializeX86TargetMC();
-        LLVMInitializeX86Disassembler();
-        LLVMDisasmContextRef llvm_ctx = LLVMCreateDisasm("x86_64", nullptr, 0, nullptr, nullptr);
-        LLVMSetDisasmOptions(llvm_ctx, LLVMDisassembler_Option_AsmPrinterVariant);
-
-        const u8* pos = static_cast<const u8*>(block.entrypoint);
-        const u8* end = pos + block.size;
-        size_t remaining = block.size;
-
-        while (pos < end) {
-            char buffer[80];
-            size_t inst_size = LLVMDisasmInstruction(llvm_ctx, const_cast<u8*>(pos), remaining, (u64)pos, buffer, sizeof(buffer));
-            ASSERT(inst_size);
-            for (const u8* i = pos; i < pos + inst_size; i++)
-                result += fmt::format("{:02x} ", *i);
-            for (size_t i = inst_size; i < 10; i++)
-                result += "   ";
-            result += buffer;
-            result += '\n';
-
-            pos += inst_size;
-            remaining -= inst_size;
-        }
-
-        LLVMDisasmDispose(llvm_ctx);
-#else
-        result.append("(recompile with DYNARMIC_USE_LLVM=ON to disassemble the generated x86_64 code)\n");
-#endif
-
+        result += DisassembleX64(block.entrypoint, reinterpret_cast<const char*>(block.entrypoint) + block.size);
         return result;
     }
 
diff --git a/src/backend_x64/a64_interface.cpp b/src/backend_x64/a64_interface.cpp
index fa88aa46..e80930e3 100644
--- a/src/backend_x64/a64_interface.cpp
+++ b/src/backend_x64/a64_interface.cpp
@@ -13,6 +13,7 @@
 #include "backend_x64/a64_jitstate.h"
 #include "backend_x64/block_of_code.h"
 #include "backend_x64/devirtualize.h"
+#include "backend_x64/disassemble_x64.h"
 #include "backend_x64/jitstate_info.h"
 #include "common/assert.h"
 #include "common/scope_exit.h"
@@ -160,6 +161,10 @@ public:
         return is_executing;
     }
 
+    std::string Disassemble() const {
+        return DisassembleX64(block_of_code.GetCodeBegin(), block_of_code.getCurr());
+    }
+
 private:
     static CodePtr GetCurrentBlockThunk(void* thisptr) {
         Jit::Impl* this_ = reinterpret_cast<Jit::Impl*>(thisptr);
@@ -318,4 +323,8 @@ bool Jit::IsExecuting() const {
     return impl->IsExecuting();
 }
 
+std::string Jit::Disassemble() const {
+    return impl->Disassemble();
+}
+
 } // namespace Dynarmic::A64
diff --git a/src/backend_x64/block_of_code.cpp b/src/backend_x64/block_of_code.cpp
index 46aec346..e2d7a354 100644
--- a/src/backend_x64/block_of_code.cpp
+++ b/src/backend_x64/block_of_code.cpp
@@ -210,6 +210,10 @@ void BlockOfCode::SwitchToNearCode() {
     SetCodePtr(near_code_ptr);
 }
 
+CodePtr BlockOfCode::GetCodeBegin() const {
+    return near_code_begin;
+}
+
 void* BlockOfCode::AllocateFromCodeSpace(size_t alloc_size) {
     if (size_ + alloc_size >= maxSize_) {
         throw Xbyak::Error(Xbyak::ERR_CODE_IS_TOO_BIG);
diff --git a/src/backend_x64/block_of_code.h b/src/backend_x64/block_of_code.h
index 59ec0e6e..e839bac5 100644
--- a/src/backend_x64/block_of_code.h
+++ b/src/backend_x64/block_of_code.h
@@ -77,6 +77,8 @@ public:
     void SwitchToFarCode();
     void SwitchToNearCode();
 
+    CodePtr GetCodeBegin() const;
+
     const void* GetReturnFromRunCodeAddress() const {
         return return_from_run_code[0];
     }
diff --git a/src/backend_x64/disassemble_x64.cpp b/src/backend_x64/disassemble_x64.cpp
new file mode 100644
index 00000000..a93e41fb
--- /dev/null
+++ b/src/backend_x64/disassemble_x64.cpp
@@ -0,0 +1,58 @@
+/* This file is part of the dynarmic project.
+ * Copyright (c) 2018 MerryMage
+ * This software may be used and distributed according to the terms of the GNU
+ * General Public License version 2 or any later version.
+ */
+
+#include <string>
+
+#include <fmt/format.h>
+
+#ifdef DYNARMIC_USE_LLVM
+#include <llvm-c/Disassembler.h>
+#include <llvm-c/Target.h>
+#endif
+
+#include "backend_x64/disassemble_x64.h"
+#include "common/assert.h"
+#include "common/common_types.h"
+
+namespace Dynarmic::BackendX64 {
+
+std::string DisassembleX64(const void* begin, const void* end) {
+    std::string result;
+
+#ifdef DYNARMIC_USE_LLVM
+    LLVMInitializeX86TargetInfo();
+    LLVMInitializeX86TargetMC();
+    LLVMInitializeX86Disassembler();
+    LLVMDisasmContextRef llvm_ctx = LLVMCreateDisasm("x86_64", nullptr, 0, nullptr, nullptr);
+    LLVMSetDisasmOptions(llvm_ctx, LLVMDisassembler_Option_AsmPrinterVariant);
+
+    const u8* pos = reinterpret_cast<const u8*>(begin);
+    size_t remaining = reinterpret_cast<size_t>(end) - reinterpret_cast<size_t>(pos);
+    while (pos < end) {
+        char buffer[80];
+        size_t inst_size = LLVMDisasmInstruction(llvm_ctx, const_cast<u8*>(pos), remaining, reinterpret_cast<u64>(pos), buffer, sizeof(buffer));
+        ASSERT(inst_size);
+        for (const u8* i = pos; i < pos + inst_size; i++)
+            result += fmt::format("{:02x} ", *i);
+        for (size_t i = inst_size; i < 10; i++)
+            result += "   ";
+        result += buffer;
+        result += '\n';
+
+        pos += inst_size;
+        remaining -= inst_size;
+    }
+
+    LLVMDisasmDispose(llvm_ctx);
+#else
+    result += fmt::format("(recompile with DYNARMIC_USE_LLVM=ON to disassemble the generated x86_64 code)\n");
+    result += fmt::format("start: {:016x}, end: {:016x}\n", begin, end);
+#endif
+
+    return result;
+}
+
+} // namespace Dynarmic::BackendX64
diff --git a/src/backend_x64/disassemble_x64.h b/src/backend_x64/disassemble_x64.h
new file mode 100644
index 00000000..f1daf7ee
--- /dev/null
+++ b/src/backend_x64/disassemble_x64.h
@@ -0,0 +1,13 @@
+/* This file is part of the dynarmic project.
+ * Copyright (c) 2018 MerryMage
+ * This software may be used and distributed according to the terms of the GNU
+ * General Public License version 2 or any later version.
+ */
+
+#include <string>
+
+namespace Dynarmic::BackendX64 {
+
+std::string DisassembleX64(const void* pos, const void* end);
+
+} // namespace Dynarmic::BackendX64