#include // Bochs #if defined(HAS_LLVM) // PowerPC.h defines PC. // This conflicts with a function that has an argument named PC #undef PC #include #include #endif #include "Common/StringUtil.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/JitCommon/JitBase.h" #include "Core/PowerPC/JitCommon/JitCache.h" #include "UICommon/Disassembler.h" 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) override; }; #if defined(HAS_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) 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, 0, 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) { 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), (u64)disasmPtr, inst_disasm, 256); 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 += StringFromFormat("%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 += StringFromFormat("%02x", disasmPtr[i]); x86_disasm << code_block << std::endl; break; } } else { x86_disasm << inst_disasm << std::endl; disasmPtr += inst_size; } (*host_instructions_count)++; } return x86_disasm.str(); } #endif HostDisassemblerX86::HostDisassemblerX86() { m_disasm.set_syntax_intel(); } std::string HostDisassemblerX86::DisassembleHostBlock(const u8* code_start, const u32 code_size, u32* host_instructions_count) { 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(); } HostDisassembler* GetNewDisassembler(const std::string& arch) { #if defined(HAS_LLVM) if (arch == "x86") return new HostDisassemblerLLVM("x86_64-none-unknown"); else if (arch == "aarch64") return new HostDisassemblerLLVM("aarch64-none-unknown", 4, "cortex-a57"); else if (arch == "armv7") return new HostDisassemblerLLVM("armv7-none-unknown", 4, "cortex-a15"); #elif defined(_M_X86) if (arch == "x86") new HostDisassemblerX86(); #endif return new HostDisassembler(); } std::string DisassembleBlock(HostDisassembler* disasm, u32* address, u32* host_instructions_count, u32* code_size) { const u8* code; int res = JitInterface::GetHostCode(address, &code, code_size); if (res == 1) { *host_instructions_count = 0; return "(No JIT active)"; } else if (res == 2) { host_instructions_count = 0; return "(No translation)"; } return disasm->DisassembleHostBlock(code, *code_size, host_instructions_count); }