123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- // Copyright 2008 Dolphin Emulator Project
- // SPDX-License-Identifier: GPL-2.0-or-later
- #include "UICommon/Disassembler.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);
- }
|