Permalink
Browse files

Merge pull request #6624 from spycrab/qt_dbg_jit

Qt/Debugger: Implement "JIT" widget
  • Loading branch information...
leoetlino committed May 12, 2018
2 parents 85e3e61 + 1dfcffc commit a712cfe3390f8ebc6f223bfb8ed20d0eb9cada94
@@ -72,6 +72,7 @@ add_executable(dolphin-emu
Debugger/BreakpointWidget.cpp
Debugger/CodeViewWidget.cpp
Debugger/CodeWidget.cpp
Debugger/JITWidget.cpp
Debugger/MemoryViewWidget.cpp
Debugger/MemoryWidget.cpp
Debugger/NewBreakpointDialog.cpp
@@ -250,7 +250,7 @@ void CodeViewWidget::OnContextMenu()
AddAction(menu, tr("Run &To Here"), this, &CodeViewWidget::OnRunToHere);
auto* function_action =
AddAction(menu, tr("&Add function"), this, &CodeViewWidget::OnAddFunction);
auto* ppc_action = AddAction(menu, tr("PPC vs x86"), this, &CodeViewWidget::OnPPCComparison);
auto* ppc_action = AddAction(menu, tr("PPC vs Host"), this, &CodeViewWidget::OnPPCComparison);
auto* insert_blr_action = AddAction(menu, tr("&Insert blr"), this, &CodeViewWidget::OnInsertBLR);
auto* insert_nop_action = AddAction(menu, tr("Insert &nop"), this, &CodeViewWidget::OnInsertNOP);
auto* replace_action =
@@ -152,6 +152,9 @@ void CodeWidget::ConnectWidgets()
connect(m_code_view, &CodeViewWidget::SymbolsChanged, this, &CodeWidget::UpdateSymbols);
connect(m_code_view, &CodeViewWidget::BreakpointsChanged, this,
[this] { emit BreakpointsChanged(); });
connect(m_code_view, &CodeViewWidget::RequestPPCComparison, this,
&CodeWidget::RequestPPCComparison);
}
void CodeWidget::OnSearchAddress()
@@ -7,6 +7,8 @@
#include <QDockWidget>
#include <QString>
#include "Common/CommonTypes.h"
class CodeViewWidget;
class QCloseEvent;
class QLineEdit;
@@ -35,6 +37,7 @@ class CodeWidget : public QDockWidget
void Update();
signals:
void BreakpointsChanged();
void RequestPPCComparison(u32 addr);
private:
void CreateWidgets();
@@ -0,0 +1,205 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt2/Debugger/JITWidget.h"
#include <QPushButton>
#include <QSplitter>
#include <QTableWidget>
#include <QTextBrowser>
#include <QVBoxLayout>
#include "Common/GekkoDisassembler.h"
#include "Common/StringUtil.h"
#include "Core/PowerPC/PPCAnalyst.h"
#include "UICommon/Disassembler.h"
#include "DolphinQt2/Settings.h"
JITWidget::JITWidget(QWidget* parent) : QDockWidget(parent)
{
setWindowTitle(tr("JIT Blocks"));
setAllowedAreas(Qt::AllDockWidgetAreas);
auto& settings = Settings::GetQSettings();
CreateWidgets();
restoreGeometry(settings.value(QStringLiteral("jitwidget/geometry")).toByteArray());
setFloating(settings.value(QStringLiteral("jitwidget/floating")).toBool());
m_table_splitter->restoreState(
settings.value(QStringLiteral("jitwidget/tablesplitter")).toByteArray());
m_asm_splitter->restoreState(
settings.value(QStringLiteral("jitwidget/asmsplitter")).toByteArray());
connect(&Settings::Instance(), &Settings::JITVisibilityChanged,
[this](bool visible) { setHidden(!visible); });
connect(&Settings::Instance(), &Settings::DebugModeToggled,
[this](bool enabled) { setHidden(!enabled || !Settings::Instance().IsJITVisible()); });
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, &JITWidget::Update);
setHidden(!Settings::Instance().IsJITVisible() || !Settings::Instance().IsDebugModeEnabled());
ConnectWidgets();
#if defined(_M_X86)
m_disassembler = GetNewDisassembler("x86");
#elif defined(_M_ARM_64)
m_disassembler = GetNewDisassembler("aarch64");
#else
m_disassembler = GetNewDisassembler("UNK");
#endif
Update();
}
JITWidget::~JITWidget()
{
auto& settings = Settings::GetQSettings();
settings.setValue(QStringLiteral("jitwidget/geometry"), saveGeometry());
settings.setValue(QStringLiteral("jitwidget/floating"), isFloating());
settings.setValue(QStringLiteral("jitwidget/tablesplitter"), m_table_splitter->saveState());
settings.setValue(QStringLiteral("jitwidget/asmsplitter"), m_asm_splitter->saveState());
}
void JITWidget::CreateWidgets()
{
m_table_widget = new QTableWidget;
m_table_widget->setColumnCount(7);
m_table_widget->setHorizontalHeaderLabels(
{tr("Address"), tr("PPC Size"), tr("Host Size"),
// i18n: The symbolic name of a code block
tr("Symbol"),
// i18n: These are the kinds of flags that a CPU uses (e.g. carry),
// not the kinds of flags that represent e.g. countries
tr("Flags"),
// i18n: The number of times a code block has been executed
tr("NumExec"),
// i18n: Performance cost, not monetary cost
tr("Cost")});
m_ppc_asm_widget = new QTextBrowser;
m_host_asm_widget = new QTextBrowser;
m_table_splitter = new QSplitter(Qt::Vertical);
m_asm_splitter = new QSplitter(Qt::Horizontal);
m_refresh_button = new QPushButton(tr("Refresh"));
m_table_splitter->addWidget(m_table_widget);
m_table_splitter->addWidget(m_asm_splitter);
m_asm_splitter->addWidget(m_ppc_asm_widget);
m_asm_splitter->addWidget(m_host_asm_widget);
QWidget* widget = new QWidget;
auto* layout = new QVBoxLayout;
widget->setLayout(layout);
layout->addWidget(m_table_splitter);
layout->addWidget(m_refresh_button);
setWidget(widget);
}
void JITWidget::ConnectWidgets()
{
connect(m_refresh_button, &QPushButton::pressed, this, &JITWidget::Update);
}
void JITWidget::Compare(u32 address)
{
m_address = address;
Update();
}
void JITWidget::Update()
{
if (!m_address)
{
m_ppc_asm_widget->setHtml(QStringLiteral("<i>%1</i>").arg(tr("(ppc)")));
m_host_asm_widget->setHtml(QStringLiteral("<i>%1</i>").arg(tr("(host)")));
return;
}
// TODO: Actually do something with the table (Wx doesn't)
// Get host side code disassembly
u32 host_instructions_count = 0;
u32 host_code_size = 0;
std::string host_instructions_disasm;
host_instructions_disasm =
DisassembleBlock(m_disassembler.get(), &m_address, &host_instructions_count, &host_code_size);
m_host_asm_widget->setHtml(
QStringLiteral("<pre>%1</pre>").arg(QString::fromStdString(host_instructions_disasm)));
// == Fill in ppc box
u32 ppc_addr = m_address;
PPCAnalyst::CodeBuffer code_buffer(32000);
PPCAnalyst::BlockStats st;
PPCAnalyst::BlockRegStats gpa;
PPCAnalyst::BlockRegStats fpa;
PPCAnalyst::CodeBlock code_block;
PPCAnalyst::PPCAnalyzer analyzer;
analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE);
analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_BRANCH_FOLLOW);
code_block.m_stats = &st;
code_block.m_gpa = &gpa;
code_block.m_fpa = &fpa;
if (analyzer.Analyze(ppc_addr, &code_block, &code_buffer, 32000) != 0xFFFFFFFF)
{
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 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.
ppc_disasm << std::dec << std::endl;
// Add some generic analysis
if (st.isFirstBlockOfFunction)
ppc_disasm << "(first block of function)" << std::endl;
if (st.isLastBlockOfFunction)
ppc_disasm << "(last block of function)" << std::endl;
ppc_disasm << st.numCycles << " estimated cycles" << std::endl;
ppc_disasm << "Num instr: PPC: " << code_block.m_num_instructions
<< " Host: " << host_instructions_count << " (blowup: "
<< 100 * host_instructions_count / code_block.m_num_instructions - 100 << "%)"
<< std::endl;
ppc_disasm << "Num bytes: PPC: " << code_block.m_num_instructions * 4
<< " Host: " << host_code_size
<< " (blowup: " << 100 * host_code_size / (4 * code_block.m_num_instructions) - 100
<< "%)" << std::endl;
m_ppc_asm_widget->setHtml(
QStringLiteral("<pre>%1</pre>").arg(QString::fromStdString(ppc_disasm.str())));
}
else
{
m_host_asm_widget->setHtml(
QStringLiteral("<pre>%1</pre>")
.arg(QString::fromStdString(StringFromFormat("(non-code address: %08x)", m_address))));
m_ppc_asm_widget->setHtml(QStringLiteral("<i>---</i>"));
}
}
void JITWidget::closeEvent(QCloseEvent*)
{
Settings::Instance().SetJITVisible(false);
}
@@ -0,0 +1,44 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QDockWidget>
#include <memory>
#include "Common/CommonTypes.h"
class QCloseEvent;
class QSplitter;
class QTextBrowser;
class QTableWidget;
class QPushButton;
class HostDisassembler;
class JITWidget : public QDockWidget
{
Q_OBJECT
public:
explicit JITWidget(QWidget* parent = nullptr);
~JITWidget();
void Compare(u32 address);
private:
void Update();
void CreateWidgets();
void ConnectWidgets();
void closeEvent(QCloseEvent*) override;
QTableWidget* m_table_widget;
QTextBrowser* m_ppc_asm_widget;
QTextBrowser* m_host_asm_widget;
QSplitter* m_table_splitter;
QSplitter* m_asm_splitter;
QPushButton* m_refresh_button;
std::unique_ptr<HostDisassembler> m_disassembler;
u32 m_address = 0;
};
@@ -95,6 +95,7 @@
<QtMoc Include="Debugger\BreakpointWidget.h" />
<QtMoc Include="Debugger\CodeWidget.h" />
<QtMoc Include="Debugger\CodeViewWidget.h" />
<QtMoc Include="Debugger\JITWidget.h" />
<QtMoc Include="Debugger\MemoryWidget.h" />
<QtMoc Include="Debugger\MemoryViewWidget.h" />
<QtMoc Include="Debugger\NewBreakpointDialog.h" />
@@ -173,6 +174,7 @@
<ClCompile Include="$(QtMocOutPrefix)InfoWidget.cpp" />
<ClCompile Include="$(QtMocOutPrefix)InterfacePane.cpp" />
<ClCompile Include="$(QtMocOutPrefix)IOWindow.cpp" />
<ClCompile Include="$(QtMocOutPrefix)JITWidget.cpp" />
<ClCompile Include="$(QtMocOutPrefix)GridProxyModel.cpp" />
<ClCompile Include="$(QtMocOutPrefix)ListProxyModel.cpp" />
<ClCompile Include="$(QtMocOutPrefix)LogConfigWidget.cpp" />
@@ -254,6 +256,7 @@
<ClCompile Include="Config\SettingsWindow.cpp" />
<ClCompile Include="Debugger\CodeViewWidget.cpp" />
<ClCompile Include="Debugger\CodeWidget.cpp" />
<ClCompile Include="Debugger\JITWidget.cpp" />
<ClCompile Include="Debugger\MemoryWidget.cpp" />
<ClCompile Include="Debugger\MemoryViewWidget.cpp" />
<ClCompile Include="FIFOPlayerWindow.cpp" />
@@ -55,6 +55,7 @@
#include "DolphinQt2/Config/SettingsWindow.h"
#include "DolphinQt2/Debugger/BreakpointWidget.h"
#include "DolphinQt2/Debugger/CodeWidget.h"
#include "DolphinQt2/Debugger/JITWidget.h"
#include "DolphinQt2/Debugger/MemoryWidget.h"
#include "DolphinQt2/Debugger/RegisterWidget.h"
#include "DolphinQt2/Debugger/WatchWidget.h"
@@ -215,6 +216,7 @@ void MainWindow::CreateComponents()
m_hotkey_window = new MappingWindow(this, MappingWindow::Type::MAPPING_HOTKEYS, 0);
m_jit_widget = new JITWidget(this);
m_log_widget = new LogWidget(this);
m_log_config_widget = new LogConfigWidget(this);
m_fifo_window = new FIFOPlayerWindow(this);
@@ -235,6 +237,7 @@ void MainWindow::CreateComponents()
connect(m_code_widget, &CodeWidget::BreakpointsChanged, m_breakpoint_widget,
&BreakpointWidget::Update);
connect(m_code_widget, &CodeWidget::RequestPPCComparison, m_jit_widget, &JITWidget::Compare);
connect(m_memory_widget, &MemoryWidget::BreakpointsChanged, m_breakpoint_widget,
&BreakpointWidget::Update);
@@ -446,13 +449,15 @@ void MainWindow::ConnectStack()
addDockWidget(Qt::RightDockWidgetArea, m_watch_widget);
addDockWidget(Qt::RightDockWidgetArea, m_breakpoint_widget);
addDockWidget(Qt::RightDockWidgetArea, m_memory_widget);
addDockWidget(Qt::RightDockWidgetArea, m_jit_widget);
tabifyDockWidget(m_log_widget, m_log_config_widget);
tabifyDockWidget(m_log_widget, m_code_widget);
tabifyDockWidget(m_log_widget, m_register_widget);
tabifyDockWidget(m_log_widget, m_watch_widget);
tabifyDockWidget(m_log_widget, m_breakpoint_widget);
tabifyDockWidget(m_log_widget, m_memory_widget);
tabifyDockWidget(m_log_widget, m_jit_widget);
}
QString MainWindow::PromptFileName()
@@ -30,6 +30,7 @@ class FIFOPlayerWindow;
class GCTASInputWindow;
class GraphicsWindow;
class HotkeyScheduler;
class JITWidget;
class LogConfigWidget;
class LogWidget;
class MappingWindow;
@@ -186,6 +187,7 @@ class MainWindow final : public QMainWindow
BreakpointWidget* m_breakpoint_widget;
CodeWidget* m_code_widget;
JITWidget* m_jit_widget;
LogWidget* m_log_widget;
LogConfigWidget* m_log_config_widget;
MemoryWidget* m_memory_widget;
Oops, something went wrong.

0 comments on commit a712cfe

Please sign in to comment.