Implements LLVM based disassembler for the debugger.
This will work for all of our platforms, x86, ARMv7, and AArch64. Main issue with this is that LLVM's cmake files aren't correctly finding the LLVM install. Not sure if this is Ubuntu's issue or not, it may just work on other operating systems. We could potentially improve this, you can pass in a specific CPU in to the LLVM disassembler. This would probably affect latency times that are reported by LLVM's disassembly? This needs to be further investigated later.
This commit is contained in:
parent
3ab921d5b0
commit
cb10bef9a4
|
@ -405,6 +405,16 @@ if(NOT ANDROID)
|
|||
message("OpenAL NOT found, disabling OpenAL sound backend")
|
||||
endif(OPENAL_FOUND)
|
||||
|
||||
include(FindLLVM OPTIONAL)
|
||||
if (LLVM_FOUND)
|
||||
add_definitions(-DHAS_LLVM=1)
|
||||
set(HAS_LLVM 1)
|
||||
|
||||
include_directories(${LLVM_INCLUDE_DIRS})
|
||||
|
||||
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
|
||||
endif()
|
||||
|
||||
set(USE_X11 0)
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# This file only exists because LLVM's cmake files are broken.
|
||||
# This affects both LLVM 3.4 and 3.5.
|
||||
# Hopefully when they fix their cmake system we don't need this garbage.
|
||||
list(APPEND LLVM_CONFIG_EXECUTABLES "llvm-config")
|
||||
list(APPEND LLVM_CONFIG_EXECUTABLES "llvm-config-3.5")
|
||||
list(APPEND LLVM_CONFIG_EXECUTABLES "llvm-config-3.4")
|
||||
|
||||
foreach(LLVM_CONFIG_NAME ${LLVM_CONFIG_EXECUTABLES})
|
||||
find_program(LLVM_CONFIG_EXE NAMES ${LLVM_CONFIG_NAME})
|
||||
if (LLVM_CONFIG_EXE)
|
||||
set(LLVM_FOUND 1)
|
||||
execute_process(COMMAND ${LLVM_CONFIG_EXE} --includedir --prefix OUTPUT_VARIABLE LLVM_INCLUDE_DIRS
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE )
|
||||
execute_process(COMMAND ${LLVM_CONFIG_EXE} --ldflags --prefix OUTPUT_VARIABLE LLVM_DEFINITIONS
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE )
|
||||
execute_process(COMMAND ${LLVM_CONFIG_EXE} --libs Core --prefix OUTPUT_VARIABLE LLVM_LIBRARIES
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE )
|
||||
execute_process(COMMAND ${LLVM_CONFIG_EXE} --version --prefix OUTPUT_VARIABLE LLVM_PACKAGE_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE )
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
|
@ -178,7 +178,7 @@ if(ANDROID)
|
|||
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} ${DOLPHIN_EXE})
|
||||
elseif(wxWidgets_FOUND)
|
||||
add_executable(${DOLPHIN_EXE} ${SRCS} ${GUI_SRCS})
|
||||
target_link_libraries(${DOLPHIN_EXE} ${LIBS} ${WXLIBS})
|
||||
target_link_libraries(${DOLPHIN_EXE} ${LIBS} ${WXLIBS} ${LLVM_LIBRARIES})
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
include(BundleUtilities)
|
||||
set(BUNDLE_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${DOLPHIN_EXE}.app)
|
||||
|
|
|
@ -7,6 +7,14 @@
|
|||
#include <disasm.h> // Bochs
|
||||
#include <sstream>
|
||||
|
||||
#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 <wx/button.h>
|
||||
#include <wx/chartype.h>
|
||||
#include <wx/defs.h>
|
||||
|
@ -33,6 +41,68 @@
|
|||
#include "DolphinWX/WxUtils.h"
|
||||
#include "DolphinWX/Debugger/JitWindow.h"
|
||||
|
||||
#if defined(HAS_LLVM)
|
||||
// This class declaration should be in the header
|
||||
// Due to the conflict with the PC define and the function with PC as an argument
|
||||
// it has to be in this file instead.
|
||||
// Once that conflict is resolved this can be moved to the header
|
||||
class HostDisassemblerLLVM : public HostDisassembler
|
||||
{
|
||||
public:
|
||||
HostDisassemblerLLVM(const std::string host_disasm);
|
||||
~HostDisassemblerLLVM()
|
||||
{
|
||||
if (m_can_disasm)
|
||||
LLVMDisasmDispose(m_llvm_context);
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_can_disasm;
|
||||
LLVMDisasmContextRef m_llvm_context;
|
||||
|
||||
std::string DisassembleHostBlock(const u8* code_start, const u32 code_size, u32* host_instructions_count) override;
|
||||
};
|
||||
|
||||
HostDisassemblerLLVM::HostDisassemblerLLVM(const std::string host_disasm)
|
||||
: m_can_disasm(false)
|
||||
{
|
||||
LLVMInitializeAllTargetInfos();
|
||||
LLVMInitializeAllTargetMCs();
|
||||
LLVMInitializeAllDisassemblers();
|
||||
|
||||
m_llvm_context = LLVMCreateDisasm(host_disasm.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)";
|
||||
|
||||
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 += LLVMDisasmInstruction(m_llvm_context, (u8*)disasmPtr, (u64)(end - disasmPtr), (u64)disasmPtr, inst_disasm, 256);
|
||||
x86_disasm << inst_disasm << std::endl;
|
||||
(*host_instructions_count)++;
|
||||
}
|
||||
|
||||
return x86_disasm.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string HostDisassembler::DisassembleBlock(u32* address, u32* host_instructions_count, u32* code_size)
|
||||
{
|
||||
if (!jit)
|
||||
|
@ -143,8 +213,14 @@ CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos,
|
|||
sizerSplit->Fit(this);
|
||||
sizerBig->Fit(this);
|
||||
|
||||
#ifdef _M_X86
|
||||
#if defined(_M_X86) && defined(HAS_LLVM)
|
||||
m_disassembler.reset(new HostDisassemblerLLVM("x86_64-none-unknown"));
|
||||
#elif defined(_M_X86)
|
||||
m_disassembler.reset(new HostDisassemblerX86());
|
||||
#elif defined(_M_ARM_64) && defined(HAS_LLVM)
|
||||
m_disassembler.reset(new HostDisassemblerLLVM("aarch64-none-unknown"));
|
||||
#elif defined(_M_ARM_32) && defined(HAS_LLVM)
|
||||
m_disassembler.reset(new HostDisassemblerLLVM("armv7-none-unknown"));
|
||||
#else
|
||||
m_disassembler.reset(new HostDisassembler());
|
||||
#endif
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
std::string DisassembleBlock(u32* address, u32* host_instructions_count, u32* code_size);
|
||||
|
||||
private:
|
||||
virtual std::string DisassembleHostBlock(const u8* code_start, const u32 code_size, u32* host_instructions_count) { return ""; }
|
||||
virtual std::string DisassembleHostBlock(const u8* code_start, const u32 code_size, u32* host_instructions_count) { return "(No disassembler)"; }
|
||||
};
|
||||
|
||||
class HostDisassemblerX86 : public HostDisassembler
|
||||
|
|
Loading…
Reference in New Issue