diff options
| author | mitaclaw <140017135+mitaclaw@users.noreply.github.com> | 2024-07-28 19:12:21 -0700 |
|---|---|---|
| committer | mitaclaw <140017135+mitaclaw@users.noreply.github.com> | 2024-10-19 00:14:54 -0700 |
| commit | ca9222a16b477869616b3938c374ed7a497802b4 (patch) | |
| tree | cf2401e7505fb71441f37e63bafca9405e67206c /Source/Core/Common/HostDisassembler.cpp | |
| parent | a0987829e5c3440a43b6db768e6f94c930d367e5 (diff) | |
Move UICommon/Disassembler to Common/HostDisassembler
A preliminary commit for a cleaner diff and an easier review
Diffstat (limited to 'Source/Core/Common/HostDisassembler.cpp')
| -rw-r--r-- | Source/Core/Common/HostDisassembler.cpp | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/Source/Core/Common/HostDisassembler.cpp b/Source/Core/Common/HostDisassembler.cpp new file mode 100644 index 0000000000..d21536ecc4 --- /dev/null +++ b/Source/Core/Common/HostDisassembler.cpp @@ -0,0 +1,208 @@ +// Copyright 2008 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "Common/HostDisassembler.h" + +#include <sstream> + +#if defined(HAVE_LLVM) +#include <fmt/format.h> +#include <llvm-c/Disassembler.h> +#include <llvm-c/Target.h> +#elif defined(_M_X86_64) +#include <disasm.h> // Bochs +#endif + +#include "Common/Assert.h" +#include "Common/VariantUtil.h" +#include "Core/PowerPC/JitInterface.h" +#include "Core/System.h" + +#if defined(HAVE_LLVM) +class HostDisassemblerLLVM : public HostDisassembler +{ +public: + HostDisassemblerLLVM(const std::string& host_disasm, int inst_size = -1, + const std::string& cpu = ""); + ~HostDisassemblerLLVM() + { + if (m_can_disasm) + LLVMDisasmDispose(m_llvm_context); + } + +private: + bool m_can_disasm; + LLVMDisasmContextRef m_llvm_context; + int m_instruction_size; + + std::string DisassembleHostBlock(const u8* code_start, const u32 code_size, + u32* host_instructions_count, u64 starting_pc) override; +}; + +HostDisassemblerLLVM::HostDisassemblerLLVM(const std::string& host_disasm, int inst_size, + const std::string& cpu) + : m_can_disasm(false), m_instruction_size(inst_size) +{ + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllDisassemblers(); + + m_llvm_context = + LLVMCreateDisasmCPU(host_disasm.c_str(), cpu.c_str(), nullptr, 0, nullptr, nullptr); + + // Couldn't create llvm context + if (!m_llvm_context) + return; + + LLVMSetDisasmOptions(m_llvm_context, LLVMDisassembler_Option_AsmPrinterVariant | + LLVMDisassembler_Option_PrintLatency); + + m_can_disasm = true; +} + +std::string HostDisassemblerLLVM::DisassembleHostBlock(const u8* code_start, const u32 code_size, + u32* host_instructions_count, + u64 starting_pc) +{ + if (!m_can_disasm) + return "(No LLVM context)"; + + u8* disasmPtr = (u8*)code_start; + const u8* end = code_start + code_size; + + std::ostringstream x86_disasm; + while ((u8*)disasmPtr < end) + { + char inst_disasm[256]; + size_t inst_size = LLVMDisasmInstruction(m_llvm_context, disasmPtr, (u64)(end - disasmPtr), + starting_pc, inst_disasm, 256); + + x86_disasm << "0x" << std::hex << starting_pc << "\t"; + if (!inst_size) + { + x86_disasm << "Invalid inst:"; + + if (m_instruction_size != -1) + { + // If we are on an architecture that has a fixed instruction size + // We can continue onward past this bad instruction. + std::string inst_str; + for (int i = 0; i < m_instruction_size; ++i) + inst_str += fmt::format("{:02x}", disasmPtr[i]); + + x86_disasm << inst_str << std::endl; + disasmPtr += m_instruction_size; + } + else + { + // We can't continue if we are on an architecture that has flexible instruction sizes + // Dump the rest of the block instead + std::string code_block; + for (int i = 0; (disasmPtr + i) < end; ++i) + code_block += fmt::format("{:02x}", disasmPtr[i]); + + x86_disasm << code_block << std::endl; + break; + } + } + else + { + x86_disasm << inst_disasm << std::endl; + disasmPtr += inst_size; + starting_pc += inst_size; + } + + (*host_instructions_count)++; + } + + return x86_disasm.str(); +} +#elif defined(_M_X86_64) +class HostDisassemblerX86 : public HostDisassembler +{ +public: + HostDisassemblerX86(); + +private: + disassembler m_disasm; + + std::string DisassembleHostBlock(const u8* code_start, const u32 code_size, + u32* host_instructions_count, u64 starting_pc) override; +}; + +HostDisassemblerX86::HostDisassemblerX86() +{ + m_disasm.set_syntax_intel(); +} + +std::string HostDisassemblerX86::DisassembleHostBlock(const u8* code_start, const u32 code_size, + u32* host_instructions_count, u64 starting_pc) +{ + u64 disasmPtr = (u64)code_start; + const u8* end = code_start + code_size; + + std::ostringstream x86_disasm; + while ((u8*)disasmPtr < end) + { + char inst_disasm[256]; + disasmPtr += m_disasm.disasm64(disasmPtr, disasmPtr, (u8*)disasmPtr, inst_disasm); + x86_disasm << inst_disasm << std::endl; + (*host_instructions_count)++; + } + + return x86_disasm.str(); +} +#endif + +std::unique_ptr<HostDisassembler> GetNewDisassembler(const std::string& arch) +{ +#if defined(HAVE_LLVM) + if (arch == "x86") + return std::make_unique<HostDisassemblerLLVM>("x86_64-none-unknown"); + if (arch == "aarch64") + return std::make_unique<HostDisassemblerLLVM>("aarch64-none-unknown", 4, "cortex-a57"); + if (arch == "armv7") + return std::make_unique<HostDisassemblerLLVM>("armv7-none-unknown", 4, "cortex-a15"); +#elif defined(_M_X86_64) + if (arch == "x86") + return std::make_unique<HostDisassemblerX86>(); +#endif + return std::make_unique<HostDisassembler>(); +} + +DisassembleResult DisassembleBlock(HostDisassembler* disasm, u32 address) +{ + auto res = Core::System::GetInstance().GetJitInterface().GetHostCode(address); + + return std::visit(overloaded{[&](JitInterface::GetHostCodeError error) { + DisassembleResult result; + switch (error) + { + case JitInterface::GetHostCodeError::NoJitActive: + result.text = "(No JIT active)"; + break; + case JitInterface::GetHostCodeError::NoTranslation: + result.text = "(No translation)"; + break; + default: + ASSERT(false); + break; + } + result.entry_address = address; + result.instruction_count = 0; + result.code_size = 0; + return result; + }, + [&](JitInterface::GetHostCodeResult host_result) { + DisassembleResult new_result; + u32 instruction_count = 0; + new_result.text = disasm->DisassembleHostBlock( + host_result.code, host_result.code_size, &instruction_count, + (u64)host_result.code); + new_result.entry_address = host_result.entry_address; + new_result.code_size = host_result.code_size; + new_result.instruction_count = instruction_count; + return new_result; + }}, + res); +} |
