dolphin/Source/Core/UICommon/Disassembler.cpp
Ryan Houdek d0ae3f7d24 Break out the disassembler code from the WXWidgets UI.
This cleans up some of the code between core and UI for disassembling and dumping code blocks.
Should help the QT UI in bringing up its debug UI since it won't have to deal with this garbage now.
2015-05-31 18:16:59 -05:00

177 lines
4.6 KiB
C++

#include <disasm.h> // Bochs
#if defined(HAS_LLVM)
// PowerPC.h defines PC.
// This conflicts with a function that has an argument named PC
#undef PC
#include <llvm-c/Disassembler.h>
#include <llvm-c/Target.h>
#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);
}