Disassembler.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright 2008 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "UICommon/Disassembler.h"
  4. #include <sstream>
  5. #if defined(HAVE_LLVM)
  6. #include <fmt/format.h>
  7. #include <llvm-c/Disassembler.h>
  8. #include <llvm-c/Target.h>
  9. #elif defined(_M_X86_64)
  10. #include <disasm.h> // Bochs
  11. #endif
  12. #include "Common/Assert.h"
  13. #include "Common/VariantUtil.h"
  14. #include "Core/PowerPC/JitInterface.h"
  15. #include "Core/System.h"
  16. #if defined(HAVE_LLVM)
  17. class HostDisassemblerLLVM : public HostDisassembler
  18. {
  19. public:
  20. HostDisassemblerLLVM(const std::string& host_disasm, int inst_size = -1,
  21. const std::string& cpu = "");
  22. ~HostDisassemblerLLVM()
  23. {
  24. if (m_can_disasm)
  25. LLVMDisasmDispose(m_llvm_context);
  26. }
  27. private:
  28. bool m_can_disasm;
  29. LLVMDisasmContextRef m_llvm_context;
  30. int m_instruction_size;
  31. std::string DisassembleHostBlock(const u8* code_start, const u32 code_size,
  32. u32* host_instructions_count, u64 starting_pc) override;
  33. };
  34. HostDisassemblerLLVM::HostDisassemblerLLVM(const std::string& host_disasm, int inst_size,
  35. const std::string& cpu)
  36. : m_can_disasm(false), m_instruction_size(inst_size)
  37. {
  38. LLVMInitializeAllTargetInfos();
  39. LLVMInitializeAllTargetMCs();
  40. LLVMInitializeAllDisassemblers();
  41. m_llvm_context =
  42. LLVMCreateDisasmCPU(host_disasm.c_str(), cpu.c_str(), nullptr, 0, nullptr, nullptr);
  43. // Couldn't create llvm context
  44. if (!m_llvm_context)
  45. return;
  46. LLVMSetDisasmOptions(m_llvm_context, LLVMDisassembler_Option_AsmPrinterVariant |
  47. LLVMDisassembler_Option_PrintLatency);
  48. m_can_disasm = true;
  49. }
  50. std::string HostDisassemblerLLVM::DisassembleHostBlock(const u8* code_start, const u32 code_size,
  51. u32* host_instructions_count,
  52. u64 starting_pc)
  53. {
  54. if (!m_can_disasm)
  55. return "(No LLVM context)";
  56. u8* disasmPtr = (u8*)code_start;
  57. const u8* end = code_start + code_size;
  58. std::ostringstream x86_disasm;
  59. while ((u8*)disasmPtr < end)
  60. {
  61. char inst_disasm[256];
  62. size_t inst_size = LLVMDisasmInstruction(m_llvm_context, disasmPtr, (u64)(end - disasmPtr),
  63. starting_pc, inst_disasm, 256);
  64. x86_disasm << "0x" << std::hex << starting_pc << "\t";
  65. if (!inst_size)
  66. {
  67. x86_disasm << "Invalid inst:";
  68. if (m_instruction_size != -1)
  69. {
  70. // If we are on an architecture that has a fixed instruction size
  71. // We can continue onward past this bad instruction.
  72. std::string inst_str;
  73. for (int i = 0; i < m_instruction_size; ++i)
  74. inst_str += fmt::format("{:02x}", disasmPtr[i]);
  75. x86_disasm << inst_str << std::endl;
  76. disasmPtr += m_instruction_size;
  77. }
  78. else
  79. {
  80. // We can't continue if we are on an architecture that has flexible instruction sizes
  81. // Dump the rest of the block instead
  82. std::string code_block;
  83. for (int i = 0; (disasmPtr + i) < end; ++i)
  84. code_block += fmt::format("{:02x}", disasmPtr[i]);
  85. x86_disasm << code_block << std::endl;
  86. break;
  87. }
  88. }
  89. else
  90. {
  91. x86_disasm << inst_disasm << std::endl;
  92. disasmPtr += inst_size;
  93. starting_pc += inst_size;
  94. }
  95. (*host_instructions_count)++;
  96. }
  97. return x86_disasm.str();
  98. }
  99. #elif defined(_M_X86_64)
  100. class HostDisassemblerX86 : public HostDisassembler
  101. {
  102. public:
  103. HostDisassemblerX86();
  104. private:
  105. disassembler m_disasm;
  106. std::string DisassembleHostBlock(const u8* code_start, const u32 code_size,
  107. u32* host_instructions_count, u64 starting_pc) override;
  108. };
  109. HostDisassemblerX86::HostDisassemblerX86()
  110. {
  111. m_disasm.set_syntax_intel();
  112. }
  113. std::string HostDisassemblerX86::DisassembleHostBlock(const u8* code_start, const u32 code_size,
  114. u32* host_instructions_count, u64 starting_pc)
  115. {
  116. u64 disasmPtr = (u64)code_start;
  117. const u8* end = code_start + code_size;
  118. std::ostringstream x86_disasm;
  119. while ((u8*)disasmPtr < end)
  120. {
  121. char inst_disasm[256];
  122. disasmPtr += m_disasm.disasm64(disasmPtr, disasmPtr, (u8*)disasmPtr, inst_disasm);
  123. x86_disasm << inst_disasm << std::endl;
  124. (*host_instructions_count)++;
  125. }
  126. return x86_disasm.str();
  127. }
  128. #endif
  129. std::unique_ptr<HostDisassembler> GetNewDisassembler(const std::string& arch)
  130. {
  131. #if defined(HAVE_LLVM)
  132. if (arch == "x86")
  133. return std::make_unique<HostDisassemblerLLVM>("x86_64-none-unknown");
  134. if (arch == "aarch64")
  135. return std::make_unique<HostDisassemblerLLVM>("aarch64-none-unknown", 4, "cortex-a57");
  136. if (arch == "armv7")
  137. return std::make_unique<HostDisassemblerLLVM>("armv7-none-unknown", 4, "cortex-a15");
  138. #elif defined(_M_X86_64)
  139. if (arch == "x86")
  140. return std::make_unique<HostDisassemblerX86>();
  141. #endif
  142. return std::make_unique<HostDisassembler>();
  143. }
  144. DisassembleResult DisassembleBlock(HostDisassembler* disasm, u32 address)
  145. {
  146. auto res = Core::System::GetInstance().GetJitInterface().GetHostCode(address);
  147. return std::visit(overloaded{[&](JitInterface::GetHostCodeError error) {
  148. DisassembleResult result;
  149. switch (error)
  150. {
  151. case JitInterface::GetHostCodeError::NoJitActive:
  152. result.text = "(No JIT active)";
  153. break;
  154. case JitInterface::GetHostCodeError::NoTranslation:
  155. result.text = "(No translation)";
  156. break;
  157. default:
  158. ASSERT(false);
  159. break;
  160. }
  161. result.entry_address = address;
  162. result.instruction_count = 0;
  163. result.code_size = 0;
  164. return result;
  165. },
  166. [&](JitInterface::GetHostCodeResult host_result) {
  167. DisassembleResult new_result;
  168. u32 instruction_count = 0;
  169. new_result.text = disasm->DisassembleHostBlock(
  170. host_result.code, host_result.code_size, &instruction_count,
  171. (u64)host_result.code);
  172. new_result.entry_address = host_result.entry_address;
  173. new_result.code_size = host_result.code_size;
  174. new_result.instruction_count = instruction_count;
  175. return new_result;
  176. }},
  177. res);
  178. }