diff --git a/Source/Core/DolphinWX/Debugger/JitWindow.cpp b/Source/Core/DolphinWX/Debugger/JitWindow.cpp index e9cd5cd409..e17546181d 100644 --- a/Source/Core/DolphinWX/Debugger/JitWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/JitWindow.cpp @@ -5,6 +5,8 @@ #include #include #include // Bochs +#include + #include #include #include @@ -31,6 +33,73 @@ #include "DolphinWX/WxUtils.h" #include "DolphinWX/Debugger/JitWindow.h" +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(); +} + enum { IDM_REFRESH_LIST = 23350, @@ -73,6 +142,12 @@ CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos, sizerSplit->Fit(this); sizerBig->Fit(this); + +#ifdef _M_X86 + m_disassembler.reset(new HostDisassemblerX86()); +#else + m_disassembler.reset(new HostDisassembler()); +#endif } void CJitWindow::OnRefresh(wxCommandEvent& /*event*/) @@ -89,62 +164,16 @@ void CJitWindow::ViewAddr(u32 em_address) void CJitWindow::Compare(u32 em_address) { - u8 *xDis = new u8[1<<18]; - memset(xDis, 0, 1<<18); + // Get host side code disassembly + 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); - disassembler x64disasm; - x64disasm.set_syntax_intel(); - - int block_num = jit->GetBlockCache()->GetBlockNumberFromStartAddress(em_address); - if (block_num < 0) - { - for (int i = 0; i < 500; i++) - { - block_num = jit->GetBlockCache()->GetBlockNumberFromStartAddress(em_address - 4 * i); - if (block_num >= 0) - break; - } - - if (block_num >= 0) - { - JitBlock *block = jit->GetBlockCache()->GetBlock(block_num); - if (!(block->originalAddress <= em_address && - block->originalSize + block->originalAddress >= em_address)) - block_num = -1; - } - - // Do not merge this "if" with the above - block_num changes inside it. - if (block_num < 0) - { - ppc_box->SetValue(_(StringFromFormat("(non-code address: %08x)", em_address))); - x86_box->SetValue(_("(no translation)")); - delete[] xDis; - return; - } - } - JitBlock *block = jit->GetBlockCache()->GetBlock(block_num); - - // 800031f0 - // == Fill in x86 box - - const u8 *code = (const u8 *)jit->GetBlockCache()->GetCompiledCodeFromBlock(block_num); - u64 disasmPtr = (u64)code; - const u8 *end = code + block->codeSize; - char *sptr = (char*)xDis; - - int num_x86_instructions = 0; - while ((u8*)disasmPtr < end) - { - disasmPtr += x64disasm.disasm64(disasmPtr, disasmPtr, (u8*)disasmPtr, sptr); - sptr += strlen(sptr); - *sptr++ = 13; - *sptr++ = 10; - num_x86_instructions++; - } - x86_box->SetValue(StrToWxStr((char*)xDis)); + x86_box->SetValue(host_instructions_disasm); // == Fill in ppc box - u32 ppc_addr = block->originalAddress; + u32 ppc_addr = em_address; PPCAnalyst::CodeBuffer code_buffer(32000); PPCAnalyst::BlockStats st; PPCAnalyst::BlockRegStats gpa; @@ -157,42 +186,45 @@ void CJitWindow::Compare(u32 em_address) code_block.m_gpa = &gpa; code_block.m_fpa = &fpa; - if (analyzer.Analyze(ppc_addr, &code_block, &code_buffer, block->codeSize) != 0xFFFFFFFF) + if (analyzer.Analyze(ppc_addr, &code_block, &code_buffer, 32000) != 0xFFFFFFFF) { - sptr = (char*)xDis; + std::ostringstream ppc_disasm; for (u32 i = 0; i < code_block.m_num_instructions; i++) { const PPCAnalyst::CodeOp &op = code_buffer.codebuffer[i]; - std::string temp = GekkoDisassembler::Disassemble(op.inst.hex, op.address); - sptr += sprintf(sptr, "%08x %s\n", op.address, temp.c_str()); + std::string opcode = GekkoDisassembler::Disassemble(op.inst.hex, op.address); + ppc_disasm << std::setfill('0') << std::setw(8) << std::hex << op.address; + ppc_disasm << " " << opcode << std::endl; } // Add stats to the end of the ppc box since it's generally the shortest. - sptr += sprintf(sptr, "\n"); + ppc_disasm << std::dec << std::endl; // Add some generic analysis if (st.isFirstBlockOfFunction) - sptr += sprintf(sptr, "(first block of function)\n"); + ppc_disasm << "(first block of function)" << std::endl; if (st.isLastBlockOfFunction) - sptr += sprintf(sptr, "(last block of function)\n"); + ppc_disasm << "(last block of function)" << std::endl; - sptr += sprintf(sptr, "%i estimated cycles\n", st.numCycles); + ppc_disasm << st.numCycles << " estimated cycles" << std::endl; - sptr += sprintf(sptr, "Num instr: PPC: %i x86: %i (blowup: %i%%)\n", - code_block.m_num_instructions, num_x86_instructions, 100 * num_x86_instructions / code_block.m_num_instructions - 100); - sptr += sprintf(sptr, "Num bytes: PPC: %i x86: %i (blowup: %i%%)\n", - code_block.m_num_instructions * 4, block->codeSize, 100 * block->codeSize / (4 * code_block.m_num_instructions) - 100); + ppc_disasm << "Num instr: PPC: " << code_block.m_num_instructions + << " x86: " << host_instructions_count + << " (blowup: " << 100 * host_instructions_count / code_block.m_num_instructions - 100 + << "%)" << std::endl; - ppc_box->SetValue(StrToWxStr((char*)xDis)); + ppc_disasm << "Num bytes: PPC: " << code_block.m_num_instructions * 4 + << " x86: " << host_code_size + << " (blowup: " << 100 * host_code_size / (4 * code_block.m_num_instructions) - 100 + << "%)" << std::endl; + + ppc_box->SetValue(ppc_disasm.str()); } else { - ppc_box->SetValue(StrToWxStr(StringFromFormat( - "(non-code address: %08x)", em_address))); + ppc_box->SetValue(StringFromFormat("(non-code address: %08x)", em_address)); x86_box->SetValue("---"); } - - delete[] xDis; } void CJitWindow::Update() diff --git a/Source/Core/DolphinWX/Debugger/JitWindow.h b/Source/Core/DolphinWX/Debugger/JitWindow.h index 577daf3452..02f4d01cdc 100644 --- a/Source/Core/DolphinWX/Debugger/JitWindow.h +++ b/Source/Core/DolphinWX/Debugger/JitWindow.h @@ -4,7 +4,10 @@ #pragma once +#include // Bochs +#include #include + #include #include #include @@ -30,6 +33,26 @@ public: void Update() override; }; +class HostDisassembler +{ +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 ""; } +}; + +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 { public: @@ -48,6 +71,7 @@ private: void Compare(u32 em_address); JitBlockList* block_list; + std::unique_ptr m_disassembler; wxButton* button_refresh; wxTextCtrl* ppc_box; wxTextCtrl* x86_box;