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.
This commit is contained in:
parent
210d7c4d54
commit
d0ae3f7d24
|
@ -116,20 +116,44 @@ namespace JitInterface
|
|||
|
||||
void WriteProfileResults(const std::string& filename)
|
||||
{
|
||||
ProfileStats prof_stats;
|
||||
GetProfileResults(&prof_stats);
|
||||
|
||||
File::IOFile f(filename, "w");
|
||||
if (!f)
|
||||
{
|
||||
PanicAlert("Failed to open %s", filename.c_str());
|
||||
return;
|
||||
}
|
||||
fprintf(f.GetHandle(), "origAddr\tblkName\tcost\ttimeCost\tpercent\ttimePercent\tOvAllinBlkTime(ms)\tblkCodeSize\n");
|
||||
for (auto& stat : prof_stats.block_stats)
|
||||
{
|
||||
std::string name = g_symbolDB.GetDescription(stat.addr);
|
||||
double percent = 100.0 * (double)stat.cost / (double)prof_stats.cost_sum;
|
||||
double timePercent = 100.0 * (double)stat.tick_counter / (double)prof_stats.timecost_sum;
|
||||
fprintf(f.GetHandle(), "%08x\t%s\t%" PRIu64 "\t%" PRIu64 "\t%.2f\t%.2f\t%.2f\t%i\n",
|
||||
stat.addr, name.c_str(), stat.cost,
|
||||
stat.tick_counter, percent, timePercent,
|
||||
(double)stat.tick_counter*1000.0/(double)prof_stats.countsPerSec, stat.block_size);
|
||||
}
|
||||
}
|
||||
|
||||
void GetProfileResults(ProfileStats* prof_stats)
|
||||
{
|
||||
prof_stats->cost_sum = 0;
|
||||
prof_stats->timecost_sum = 0;
|
||||
prof_stats->block_stats.clear();
|
||||
prof_stats->block_stats.reserve(jit->GetBlockCache()->GetNumBlocks());
|
||||
|
||||
// Can't really do this with no jit core available
|
||||
if (!jit)
|
||||
return;
|
||||
|
||||
PowerPC::CPUState old_state = PowerPC::GetState();
|
||||
if (old_state == PowerPC::CPUState::CPU_RUNNING)
|
||||
PowerPC::Pause();
|
||||
Core::EState old_state = Core::GetState();
|
||||
if (old_state == Core::CORE_RUN)
|
||||
Core::SetState(Core::CORE_PAUSE);
|
||||
|
||||
std::vector<BlockStat> stats;
|
||||
stats.reserve(jit->GetBlockCache()->GetNumBlocks());
|
||||
u64 cost_sum = 0;
|
||||
u64 timecost_sum = 0;
|
||||
u64 countsPerSec;
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec);
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&prof_stats->countsPerSec);
|
||||
for (int i = 0; i < jit->GetBlockCache()->GetNumBlocks(); i++)
|
||||
{
|
||||
const JitBlock *block = jit->GetBlockCache()->GetBlock(i);
|
||||
|
@ -138,37 +162,60 @@ namespace JitInterface
|
|||
u64 timecost = block->ticCounter;
|
||||
// Todo: tweak.
|
||||
if (block->runCount >= 1)
|
||||
stats.emplace_back(i, cost);
|
||||
cost_sum += cost;
|
||||
timecost_sum += timecost;
|
||||
prof_stats->block_stats.emplace_back(i, block->originalAddress,
|
||||
cost, timecost, block->codeSize);
|
||||
prof_stats->cost_sum += cost;
|
||||
prof_stats->timecost_sum += timecost;
|
||||
}
|
||||
|
||||
sort(stats.begin(), stats.end());
|
||||
File::IOFile f(filename, "w");
|
||||
if (!f)
|
||||
sort(prof_stats->block_stats.begin(), prof_stats->block_stats.end());
|
||||
if (old_state == Core::CORE_RUN)
|
||||
Core::SetState(Core::CORE_RUN);
|
||||
}
|
||||
|
||||
int GetHostCode(u32* address, const u8** code, u32* code_size)
|
||||
{
|
||||
if (!jit)
|
||||
{
|
||||
PanicAlert("Failed to open %s", filename.c_str());
|
||||
return;
|
||||
*code_size = 0;
|
||||
return 1;
|
||||
}
|
||||
fprintf(f.GetHandle(), "origAddr\tblkName\tcost\ttimeCost\tpercent\ttimePercent\tOvAllinBlkTime(ms)\tblkCodeSize\n");
|
||||
for (auto& stat : stats)
|
||||
|
||||
int block_num = jit->GetBlockCache()->GetBlockNumberFromStartAddress(*address);
|
||||
if (block_num < 0)
|
||||
{
|
||||
const JitBlock *block = jit->GetBlockCache()->GetBlock(stat.blockNum);
|
||||
if (block)
|
||||
for (int i = 0; i < 500; i++)
|
||||
{
|
||||
std::string name = g_symbolDB.GetDescription(block->originalAddress);
|
||||
double percent = 100.0 * (double)stat.cost / (double)cost_sum;
|
||||
double timePercent = 100.0 * (double)block->ticCounter / (double)timecost_sum;
|
||||
fprintf(f.GetHandle(), "%08x\t%s\t%" PRIu64 "\t%" PRIu64 "\t%.2f\t%.2f\t%.2f\t%i\n",
|
||||
block->originalAddress, name.c_str(), stat.cost,
|
||||
block->ticCounter, percent, timePercent,
|
||||
(double)block->ticCounter*1000.0/(double)countsPerSec, block->codeSize);
|
||||
block_num = jit->GetBlockCache()->GetBlockNumberFromStartAddress(*address - 4 * i);
|
||||
if (block_num >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (block_num >= 0)
|
||||
{
|
||||
JitBlock* block = jit->GetBlockCache()->GetBlock(block_num);
|
||||
if (!(block->originalAddress <= *address &&
|
||||
block->originalSize + block->originalAddress >= *address))
|
||||
block_num = -1;
|
||||
}
|
||||
|
||||
// Do not merge this "if" with the above - block_num changes inside it.
|
||||
if (block_num < 0)
|
||||
{
|
||||
*code_size = 0;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (old_state == PowerPC::CPUState::CPU_RUNNING)
|
||||
PowerPC::Start();
|
||||
JitBlock* block = jit->GetBlockCache()->GetBlock(block_num);
|
||||
|
||||
*code = (const u8*)jit->GetBlockCache()->GetCompiledCodeFromBlock(block_num);
|
||||
|
||||
*code_size = block->codeSize;
|
||||
*address = block->originalAddress;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool HandleFault(uintptr_t access_address, SContext* ctx)
|
||||
{
|
||||
return jit->HandleFault(access_address, ctx);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "Common/ChunkFile.h"
|
||||
#include "Core/MachineContext.h"
|
||||
#include "Core/PowerPC/CPUCoreBase.h"
|
||||
#include "Core/PowerPC/Profiler.h"
|
||||
|
||||
namespace JitInterface
|
||||
{
|
||||
|
@ -25,6 +26,8 @@ namespace JitInterface
|
|||
|
||||
// Debugging
|
||||
void WriteProfileResults(const std::string& filename);
|
||||
void GetProfileResults(ProfileStats* prof_stats);
|
||||
int GetHostCode(u32* address, const u8** code, u32* code_size);
|
||||
|
||||
// Memory Utilities
|
||||
bool HandleFault(uintptr_t access_address, SContext* ctx);
|
||||
|
|
|
@ -44,13 +44,24 @@
|
|||
|
||||
struct BlockStat
|
||||
{
|
||||
BlockStat(int bn, u64 c) : blockNum(bn), cost(c) {}
|
||||
BlockStat(int bn, u32 _addr, u64 c, u64 ticks, u32 size) :
|
||||
blockNum(bn), addr(_addr), cost(c), tick_counter(ticks), block_size(size) {}
|
||||
int blockNum;
|
||||
u32 addr;
|
||||
u64 cost;
|
||||
u64 tick_counter;
|
||||
u32 block_size;
|
||||
|
||||
bool operator <(const BlockStat &other) const
|
||||
{ return cost > other.cost; }
|
||||
};
|
||||
struct ProfileStats
|
||||
{
|
||||
std::vector<BlockStat> block_stats;
|
||||
u64 cost_sum;
|
||||
u64 timecost_sum;
|
||||
u64 countsPerSec;
|
||||
};
|
||||
|
||||
namespace Profiler
|
||||
{
|
||||
|
|
|
@ -7,14 +7,6 @@
|
|||
#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/listctrl.h>
|
||||
#include <wx/panel.h>
|
||||
|
@ -23,177 +15,12 @@
|
|||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GekkoDisassembler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/PPCAnalyst.h"
|
||||
#include "Core/PowerPC/JitCommon/JitBase.h"
|
||||
#include "Core/PowerPC/JitCommon/JitCache.h"
|
||||
#include "DolphinWX/Globals.h"
|
||||
#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, 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
|
||||
|
||||
std::string HostDisassembler::DisassembleBlock(u32* address, u32* host_instructions_count, u32* code_size)
|
||||
{
|
||||
if (!jit)
|
||||
{
|
||||
*host_instructions_count = 0;
|
||||
*code_size = 0;
|
||||
return "(No JIT active)";
|
||||
}
|
||||
|
||||
int block_num = jit->GetBlockCache()->GetBlockNumberFromStartAddress(*address);
|
||||
if (block_num < 0)
|
||||
{
|
||||
for (int i = 0; i < 500; i++)
|
||||
{
|
||||
block_num = jit->GetBlockCache()->GetBlockNumberFromStartAddress(*address - 4 * i);
|
||||
if (block_num >= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (block_num >= 0)
|
||||
{
|
||||
JitBlock* block = jit->GetBlockCache()->GetBlock(block_num);
|
||||
if (!(block->originalAddress <= *address &&
|
||||
block->originalSize + block->originalAddress >= *address))
|
||||
block_num = -1;
|
||||
}
|
||||
|
||||
// Do not merge this "if" with the above - block_num changes inside it.
|
||||
if (block_num < 0)
|
||||
{
|
||||
host_instructions_count = 0;
|
||||
code_size = 0;
|
||||
return "(No translation)";
|
||||
}
|
||||
}
|
||||
|
||||
JitBlock* block = jit->GetBlockCache()->GetBlock(block_num);
|
||||
|
||||
const u8* code = (const u8*)jit->GetBlockCache()->GetCompiledCodeFromBlock(block_num);
|
||||
|
||||
*code_size = block->codeSize;
|
||||
*address = block->originalAddress;
|
||||
return DisassembleHostBlock(code, block->codeSize, host_instructions_count);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
#include "UICommon/Disassembler.h"
|
||||
|
||||
CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos,
|
||||
const wxSize& size, long style, const wxString& name)
|
||||
|
@ -219,16 +46,14 @@ CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos,
|
|||
sizerSplit->Fit(this);
|
||||
sizerBig->Fit(this);
|
||||
|
||||
#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", 4, "cortex-a57"));
|
||||
#elif defined(_M_ARM_32) && defined(HAS_LLVM)
|
||||
m_disassembler.reset(new HostDisassemblerLLVM("armv7-none-unknown", 4, "cortex-a15"));
|
||||
#if defined(_M_X86)
|
||||
m_disassembler.reset(GetNewDisassembler("x86"));
|
||||
#elif defined(_M_ARM_64)
|
||||
m_disassembler.reset(GetNewDisassembler("aarch64"));
|
||||
#elif defined(_M_ARM_32)
|
||||
m_disassembler.reset(GetNewDisassembler("armv7"));
|
||||
#else
|
||||
m_disassembler.reset(new HostDisassembler());
|
||||
m_disassembler.reset(GetNewDisassembler("UNK"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -250,7 +75,7 @@ void CJitWindow::Compare(u32 em_address)
|
|||
u32 host_instructions_count = 0;
|
||||
u32 host_code_size = 0;
|
||||
std::string host_instructions_disasm;
|
||||
host_instructions_disasm = m_disassembler->DisassembleBlock(&em_address, &host_instructions_count, &host_code_size);
|
||||
host_instructions_disasm = DisassembleBlock(m_disassembler.get(), &em_address, &host_instructions_count, &host_code_size);
|
||||
|
||||
x86_box->SetValue(host_instructions_disasm);
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <disasm.h> // Bochs
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
|
@ -12,6 +11,7 @@
|
|||
#include <wx/panel.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "UICommon/Disassembler.h"
|
||||
|
||||
class wxButton;
|
||||
class wxListBox;
|
||||
|
@ -26,26 +26,6 @@ public:
|
|||
void Update() override;
|
||||
};
|
||||
|
||||
class HostDisassembler
|
||||
{
|
||||
public:
|
||||
virtual ~HostDisassembler() {}
|
||||
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 "(No disassembler)"; }
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
class CJitWindow : public wxPanel
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
set(SRCS UICommon.cpp)
|
||||
set(SRCS Disassembler.cpp
|
||||
UICommon.cpp)
|
||||
|
||||
set(LIBS common)
|
||||
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
#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);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class HostDisassembler
|
||||
{
|
||||
public:
|
||||
virtual ~HostDisassembler() {}
|
||||
virtual std::string DisassembleHostBlock(const u8* code_start, const u32 code_size, u32* host_instructions_count) { return "(No disassembler)"; }
|
||||
};
|
||||
|
||||
HostDisassembler* GetNewDisassembler(const std::string& arch);
|
||||
std::string DisassembleBlock(HostDisassembler* disasm, u32* address, u32* host_instructions_count, u32* code_size);
|
|
@ -44,11 +44,13 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="UICommon.cpp" />
|
||||
<ClCompile Include="Disassembler.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="UICommon.h" />
|
||||
<ClInclude Include="Disassembler.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
Loading…
Reference in New Issue