Reimplement debugger resize & disassembly (#2876)

* Reimplement debugger resize
fix interrupt

* add splitter to disassembly
fix debugger regression of last commit
fix gotoaddr pos

* travis sth sth

* add drag & drop to cg_disasm

* check for invalid address on set breakpoint
reenable debugger controls on Emu.IsReady()

* check for valid address more thoroughly
This commit is contained in:
Megamouse 2017-06-16 20:35:58 +02:00 committed by Ivan
parent aca5c73fb3
commit 31cedb6192
6 changed files with 173 additions and 78 deletions

View File

@ -1,7 +1,8 @@
#include "stdafx.h"
#include "cg_disasm_window.h"
#include "Emu/System.h"
#include <QSplitter>
#include <QMenu>
#include <QMenuBar>
#include <QMessageBox>
@ -11,51 +12,53 @@
#include <QDockWidget>
#include <QCoreApplication>
#include <QFontDatabase>
#include <QMimeData>
#include "Emu/RSX/CgBinaryProgram.h"
inline QString qstr(const std::string& _in) { return QString::fromUtf8(_in.data(), _in.size()); }
inline std::string sstr(const QString& _in) { return _in.toUtf8().toStdString(); }
cg_disasm_window::cg_disasm_window(QWidget* parent): QTabWidget()
cg_disasm_window::cg_disasm_window(std::shared_ptr<gui_settings> xSettings, QWidget* parent): QWidget(), xgui_settings(xSettings)
{
setWindowTitle(tr("Cg Disasm"));
setAttribute(Qt::WA_DeleteOnClose);
setMinimumSize(200, 150); // seems fine on win 10
setAcceptDrops(true);
setMinimumSize(QSize(200, 150)); // seems fine on win 10
resize(QSize(620, 395));
m_path_last = xgui_settings->GetValue(GUI::fd_cg_disasm).toString();
tab_disasm = new QWidget(this);
tab_glsl = new QWidget(this);
addTab(tab_disasm, "ASM");
addTab(tab_glsl, "GLSL");
QVBoxLayout* layout_disasm = new QVBoxLayout();
m_disasm_text = new QTextEdit();
m_disasm_text->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_disasm_text = new QTextEdit(this);
m_disasm_text->setReadOnly(true);
m_disasm_text->setWordWrapMode(QTextOption::NoWrap);
m_disasm_text->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
layout_disasm->addWidget(m_disasm_text);
tab_disasm->setLayout(layout_disasm);
QVBoxLayout* layout_glsl = new QVBoxLayout();
m_glsl_text = new QTextEdit();
m_glsl_text->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_glsl_text = new QTextEdit(this);
m_glsl_text->setReadOnly(true);
m_glsl_text->setWordWrapMode(QTextOption::NoWrap);
m_glsl_text->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
layout_glsl->addWidget(m_glsl_text);
tab_glsl->setLayout(layout_glsl);
QSplitter* splitter = new QSplitter();
splitter->addWidget(m_disasm_text);
splitter->addWidget(m_glsl_text);
QHBoxLayout* layout = new QHBoxLayout();
layout->addWidget(splitter);
setLayout(layout);
m_disasm_text->setContextMenuPolicy(Qt::CustomContextMenu);
m_glsl_text->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_disasm_text, &QWidget::customContextMenuRequested, this, &cg_disasm_window::ShowContextMenu);
connect(m_glsl_text, &QWidget::customContextMenuRequested, this, &cg_disasm_window::ShowContextMenu);
ShowDisasm();
}
void cg_disasm_window::ShowContextMenu(const QPoint &pos) // this is a slot
void cg_disasm_window::ShowContextMenu(const QPoint &pos)
{
QMenu myMenu;
QPoint globalPos = mapToGlobal(pos);
QAction* clear = new QAction(tr("&Clear"));
QAction* open = new QAction(tr("Open &Cg binary program"));
@ -70,11 +73,73 @@ void cg_disasm_window::ShowContextMenu(const QPoint &pos) // this is a slot
if (filePath == NULL) return;
m_path_last = QFileInfo(filePath).path();
CgBinaryDisasm disasm(sstr(filePath));
ShowDisasm();
});
myMenu.exec(QCursor::pos());
}
void cg_disasm_window::ShowDisasm()
{
if (QFileInfo(m_path_last).isFile())
{
CgBinaryDisasm disasm(sstr(m_path_last));
disasm.BuildShaderBody();
m_disasm_text->setText(qstr(disasm.GetArbShader()));
m_glsl_text->setText(qstr(disasm.GetGlslShader()));
});
myMenu.exec(globalPos);
}
else if (!m_path_last.isEmpty())
{
LOG_ERROR(LOADER, "CgDisasm: Failed to open %s", sstr(m_path_last));
}
}
bool cg_disasm_window::IsValidFile(const QMimeData& md, bool save)
{
for (auto url : md.urls())
{
for (QString suff : {"fpo", "vpo"})
{
if (QFileInfo(url.fileName()).suffix().toLower() == suff)
{
if (save)
{
m_path_last = url.toLocalFile();
xgui_settings->SetValue(GUI::fd_cg_disasm, m_path_last);
}
return true;
}
}
}
return false;
}
void cg_disasm_window::dropEvent(QDropEvent* ev)
{
if (IsValidFile(*ev->mimeData(), true))
{
ShowDisasm();
}
}
void cg_disasm_window::dragEnterEvent(QDragEnterEvent* ev)
{
if (IsValidFile(*ev->mimeData()))
{
ev->accept();
}
}
void cg_disasm_window::dragMoveEvent(QDragMoveEvent* ev)
{
if (IsValidFile(*ev->mimeData()))
{
ev->accept();
}
}
void cg_disasm_window::dragLeaveEvent(QDragLeaveEvent* ev)
{
ev->accept();
}

View File

@ -2,25 +2,38 @@
#define CGDISASMWINDOW_H
#include <QTextEdit>
#include <QMainWindow>
#include <QDropEvent>
class cg_disasm_window : public QTabWidget
#include "stdafx.h"
#include "gui_settings.h"
class cg_disasm_window : public QWidget
{
Q_OBJECT
private slots:
void ShowContextMenu(const QPoint &pos);
void ShowDisasm();
bool IsValidFile(const QMimeData& md, bool save = false);
private:
QString m_path_last;
QTextEdit* m_disasm_text;
QTextEdit* m_glsl_text;
QWidget* tab_disasm;
QWidget* tab_glsl;
QList<QUrl> m_urls;
QAction *openCgBinaryProgram;
std::shared_ptr<gui_settings> xgui_settings;
public:
explicit cg_disasm_window(QWidget *parent);
explicit cg_disasm_window(std::shared_ptr<gui_settings> xSettings, QWidget *parent);
protected:
void dropEvent(QDropEvent* ev);
void dragEnterEvent(QDragEnterEvent* ev);
void dragMoveEvent(QDragMoveEvent* ev);
void dragLeaveEvent(QDragLeaveEvent* ev);
};
#endif // CGDISASMWINDOW_H

View File

@ -1,5 +1,9 @@
#include "debugger_frame.h"
#include <QSplitter>
#include <QApplication>
#include <QFontDatabase>
inline QString qstr(const std::string& _in) { return QString::fromUtf8(_in.data(), _in.size()); }
debugger_frame::debugger_frame(QWidget *parent) : QDockWidget(tr("Debugger"), parent)
@ -30,7 +34,7 @@ debugger_frame::debugger_frame(QWidget *parent) : QDockWidget(tr("Debugger"), pa
m_btn_run = new QPushButton(tr("Run"), this);
m_btn_pause = new QPushButton(tr("Pause"), this);
EnableButtons(Emu.IsRunning() || Emu.IsPaused());
EnableButtons(!Emu.IsStopped());
hbox_b_main->addWidget(m_go_to_addr);
hbox_b_main->addWidget(m_go_to_pc);
@ -48,9 +52,12 @@ debugger_frame::debugger_frame(QWidget *parent) : QDockWidget(tr("Debugger"), pa
m_list->setFont(mono);
m_regs->setFont(mono);
QSplitter* splitter = new QSplitter(this);
splitter->addWidget(m_list);
splitter->addWidget(m_regs);
QHBoxLayout* hbox_w_list = new QHBoxLayout();
hbox_w_list->addWidget(m_list);
hbox_w_list->addWidget(m_regs);
hbox_w_list->addWidget(splitter);
vbox_p_main->addLayout(hbox_b_main);
vbox_p_main->addLayout(hbox_w_list);
@ -190,25 +197,36 @@ void debugger_frame::UpdateUnitList()
return;
}
QVariant old_cpu = m_choice_units->currentData();
m_choice_units->clear();
const auto on_select = [&](u32, cpu_thread& cpu)
{
QVariant var_cpu = qVariantFromValue((void *)&cpu);
m_choice_units->addItem(qstr(cpu.get_name()), var_cpu);
if (old_cpu == var_cpu) m_choice_units->setCurrentIndex(m_choice_units->count() - 1);
};
idm::select<ppu_thread>(on_select);
idm::select<ARMv7Thread>(on_select);
idm::select<RawSPUThread>(on_select);
idm::select<SPUThread>(on_select);
{
const QSignalBlocker blocker(m_choice_units);
idm::select<ppu_thread>(on_select);
idm::select<ARMv7Thread>(on_select);
idm::select<RawSPUThread>(on_select);
idm::select<SPUThread>(on_select);
}
OnSelectUnit();
m_choice_units->update();
}
void debugger_frame::OnSelectUnit()
{
if (m_choice_units->count() < 1) return;
if (m_choice_units->count() < 1 || m_current_choice == m_choice_units->currentText()) return;
m_current_choice = m_choice_units->currentText();
m_disasm.reset();
@ -242,38 +260,6 @@ void debugger_frame::OnSelectUnit()
DoUpdate();
}
//void debugger_frame::resizeEvent(QResizeEvent* event)
//{
// if (0)
// {
// if (!m_list->rowCount())
// {
// m_list->InsertItem(m_list->rowCount(), "");
// }
//
// int size = 0;
// m_list->clear();
// int item = 0;
// while (size < m_list->GetSize().GetHeight())
// {
// item = m_list->rowCount();
// m_list->InsertItem(item, "");
// QRect rect;
// m_list->GetItemRect(item, rect);
//
// size = rect.GetBottom();
// }
//
// if (item)
// {
// m_list->removeRow(--item);
// }
//
// m_item_count = item;
// ShowAddr(m_pc);
// }
//}
void debugger_frame::DoUpdate()
{
Show_PC();
@ -360,7 +346,9 @@ void debugger_frame::Show_Val()
connect(p_pc, &QLineEdit::textChanged, l_changeLabel);
connect(button_ok, &QAbstractButton::clicked, diag, &QDialog::accept);
connect(button_cancel, &QAbstractButton::clicked, diag, &QDialog::reject);;
connect(button_cancel, &QAbstractButton::clicked, diag, &QDialog::reject);
diag->move(QCursor::pos());
if (diag->exec() == QDialog::Accepted)
{
@ -537,7 +525,7 @@ void debugger_list::keyPressEvent(QKeyEvent* event)
void debugger_list::mouseDoubleClickEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton && (Emu.IsRunning() || Emu.IsPaused()))
if (event->button() == Qt::LeftButton && !Emu.IsStopped())
{
long i = currentRow();
if (i < 0) return;
@ -552,7 +540,12 @@ void debugger_list::mouseDoubleClickEvent(QMouseEvent* event)
}
else
{
AddBreakPoint(pc);
const auto cpu = m_debugFrame->cpu.lock();
if (g_system == system_type::ps3 && cpu->id_type() == 1 && vm::check_addr(pc))
{
AddBreakPoint(pc);
}
}
ShowAddr(start_pc);
@ -566,3 +559,28 @@ void debugger_list::wheelEvent(QWheelEvent* event)
ShowAddr(m_pc - (event->modifiers() == Qt::ControlModifier ? m_item_count * (value + 1) : m_item_count + value) * 4);
}
void debugger_list::resizeEvent(QResizeEvent* event)
{
if (count() < 1 || visualItemRect(item(0)).height() < 1)
{
return;
}
m_item_count = (rect().height() - frameWidth()*2) / visualItemRect(item(0)).height();
clear();
for (u32 i = 0; i < m_item_count; ++i)
{
insertItem(i, new QListWidgetItem(""));
}
if (horizontalScrollBar())
{
m_item_count--;
delete item(m_item_count);
}
ShowAddr(m_pc - m_item_count * 4);
}

View File

@ -19,16 +19,12 @@
#include "instruction_editor_dialog.h"
#include "register_editor_dialog.h"
#include <QApplication>
#include <QDockWidget>
#include <QListWidget>
#include <QPushButton>
#include <QLineEdit>
#include <QComboBox>
#include <QKeyEvent>
#include <QWheelEvent>
#include <QInputDialog>
#include <QFontDatabase>
#include <QTimer>
#include <QTextEdit>
@ -49,6 +45,7 @@ class debugger_frame : public QDockWidget
QPushButton* m_btn_run;
QPushButton* m_btn_pause;
QComboBox* m_choice_units;
QString m_current_choice;
u64 m_threads_created = 0;
u64 m_threads_deleted = 0;
@ -69,7 +66,6 @@ public:
u32 GetPc() const;
u32 CentrePc(u32 pc) const;
//void resizeEvent(QResizeEvent* event);
void DoUpdate();
void WriteRegs();
void EnableButtons(bool enable);
@ -114,6 +110,7 @@ protected:
void keyPressEvent(QKeyEvent* event);
void mouseDoubleClickEvent(QMouseEvent* event);
void wheelEvent(QWheelEvent* event);
void resizeEvent(QResizeEvent* event);
};
#endif // DEBUGGERFRAME_H

View File

@ -64,6 +64,7 @@ namespace GUI
const GUI_SAVE fd_boot_elf = GUI_SAVE( main_window, "lastExplorePathELF", "" );
const GUI_SAVE fd_boot_game = GUI_SAVE( main_window, "lastExplorePathGAME", "" );
const GUI_SAVE fd_decrypt_sprx = GUI_SAVE( main_window, "lastExplorePathSPRX", "" );
const GUI_SAVE fd_cg_disasm = GUI_SAVE( main_window, "lastExplorePathCGD", "" );
const GUI_SAVE mw_debugger = GUI_SAVE( main_window, "debuggerVisible", false );
const GUI_SAVE mw_logger = GUI_SAVE( main_window, "loggerVisible", true );

View File

@ -742,6 +742,7 @@ void main_window::OnEmuStop()
void main_window::OnEmuReady()
{
debuggerFrame->EnableButtons(true);
#ifdef _WIN32
thumb_playPause->setToolTip(Emu.IsReady() ? tr("Start") : tr("Resume"));
thumb_playPause->setIcon(icon_play);
@ -1162,7 +1163,7 @@ void main_window::CreateConnects()
sdid->show();
});
connect(toolsCgDisasmAct, &QAction::triggered, [=](){
cg_disasm_window* cgdw = new cg_disasm_window(this);
cg_disasm_window* cgdw = new cg_disasm_window(guiSettings, this);
cgdw->show();
});
connect(toolskernel_explorerAct, &QAction::triggered, [=](){