From c1f08ce58d13936cb7b427bb3273a974c47873c6 Mon Sep 17 00:00:00 2001 From: MRG95 Date: Sun, 22 Oct 2017 03:34:36 -0400 Subject: [PATCH] Added breakpoint list Added a list widget that displays all the currently active breakpoints. You can rename each one for convenience, delete them in bulk, or double click to jump to that address. --- rpcs3/rpcs3qt/debugger_frame.cpp | 108 ++++++++++++++++++++++++++++++- rpcs3/rpcs3qt/debugger_frame.h | 11 +++- 2 files changed, 115 insertions(+), 4 deletions(-) diff --git a/rpcs3/rpcs3qt/debugger_frame.cpp b/rpcs3/rpcs3qt/debugger_frame.cpp index dd5e397f73..0d678b0258 100644 --- a/rpcs3/rpcs3qt/debugger_frame.cpp +++ b/rpcs3/rpcs3qt/debugger_frame.cpp @@ -4,6 +4,7 @@ #include #include #include +#include constexpr auto qstr = QString::fromStdString; extern bool user_asked_for_frame_capture; @@ -22,6 +23,10 @@ debugger_frame::debugger_frame(std::shared_ptr settings, QWidget * QHBoxLayout* hbox_b_main = new QHBoxLayout(); m_list = new debugger_list(this); + m_breakpoints_list = new QListWidget(this); + m_breakpoints_list->setEditTriggers(QAbstractItemView::NoEditTriggers); + m_breakpoints_list->setContextMenuPolicy(Qt::CustomContextMenu); + m_breakpoints_list->setSelectionMode(QAbstractItemView::ExtendedSelection); m_choice_units = new QComboBox(this); m_choice_units->setSizeAdjustPolicy(QComboBox::AdjustToContents); m_choice_units->setMaxVisibleItems(30); @@ -33,6 +38,11 @@ debugger_frame::debugger_frame(std::shared_ptr settings, QWidget * m_choice_units->completer()->setMaxVisibleItems(30); m_choice_units->completer()->setFilterMode(Qt::MatchContains); + m_breakpoints_list_delete = new QAction("Delete", m_breakpoints_list); + m_breakpoints_list_delete->setShortcut(Qt::Key_Delete); + m_breakpoints_list_delete->setShortcutContext(Qt::WidgetShortcut); + m_breakpoints_list->addAction(m_breakpoints_list_delete); + m_go_to_addr = new QPushButton(tr("Go To Address"), this); m_go_to_pc = new QPushButton(tr("Go To PC"), this); m_btn_capture = new QPushButton(tr("Capture"), this); @@ -58,9 +68,15 @@ debugger_frame::debugger_frame(std::shared_ptr settings, QWidget * m_list->setFont(m_mono); m_regs->setFont(m_mono); + m_right_splitter = new QSplitter(this); + m_right_splitter->setOrientation(Qt::Vertical); + m_right_splitter->addWidget(m_regs); + m_right_splitter->addWidget(m_breakpoints_list); + m_right_splitter->setStretchFactor(0, 1); + m_splitter = new QSplitter(this); m_splitter->addWidget(m_list); - m_splitter->addWidget(m_regs); + m_splitter->addWidget(m_right_splitter); QHBoxLayout* hbox_w_list = new QHBoxLayout(); hbox_w_list->addWidget(m_splitter); @@ -117,6 +133,10 @@ debugger_frame::debugger_frame(std::shared_ptr settings, QWidget * connect(m_choice_units, static_cast(&QComboBox::currentIndexChanged), this, &debugger_frame::OnSelectUnit); connect(this, &QDockWidget::visibilityChanged, this, &debugger_frame::EnableUpdateTimer); + connect(m_breakpoints_list, &QListWidget::itemDoubleClicked, this, &debugger_frame::OnBreakpointList_doubleClicked); + connect(m_breakpoints_list, &QListWidget::customContextMenuRequested, this, &debugger_frame::OnBreakpointList_rightClicked); + connect(m_breakpoints_list_delete, &QAction::triggered, this, &debugger_frame::OnBreakpointList_delete); + m_list->ShowAddr(CentrePc(m_list->m_pc)); UpdateUnitList(); } @@ -473,9 +493,56 @@ void debugger_frame::EnableButtons(bool enable) void debugger_frame::ClearBreakpoints() { + //This is required to actually delete the breakpoints, not just visually. + for (std::map::iterator it = g_breakpoints.begin(); it != g_breakpoints.end(); it++) + m_list->RemoveBreakPoint(it->first, false); + g_breakpoints.clear(); } +void debugger_frame::OnBreakpointList_doubleClicked() +{ + m_list->ShowAddr(CentrePc(m_breakpoints_list->currentItem()->data(Qt::UserRole).value())); + m_list->setCurrentRow(16); +} + +void debugger_frame::OnBreakpointList_rightClicked(const QPoint &pos) +{ + if (m_breakpoints_list->itemAt(pos) == NULL) + return; + + QMenu* menu = new QMenu(); + + if (m_breakpoints_list->selectedItems().count() == 1) + { + menu->addAction("Rename"); + menu->addSeparator(); + } + menu->addAction(m_breakpoints_list_delete); + + QAction* selectedItem = menu->exec(QCursor::pos()); + if (selectedItem != NULL) + { + if (selectedItem->text() == "Rename") + { + QListWidgetItem* currentItem = m_breakpoints_list->selectedItems().at(0); + + currentItem->setFlags(currentItem->flags() | Qt::ItemIsEditable); + m_breakpoints_list->editItem(currentItem); + } + } +} + +void debugger_frame::OnBreakpointList_delete() +{ + int selectedCount = m_breakpoints_list->selectedItems().count(); + + for (int i = selectedCount - 1; i >= 0; i--) + { + m_list->RemoveBreakPoint(m_breakpoints_list->item(i)->data(Qt::UserRole).value()); + } +} + debugger_list::debugger_list(debugger_frame* parent) : QListWidget(parent) { m_pc = 0; @@ -543,12 +610,47 @@ void debugger_list::AddBreakPoint(u32 pc) { g_breakpoints.emplace(pc, false); ppu_breakpoint(pc); + + const auto cpu = m_debugFrame->cpu.lock(); + const u32 cpu_offset = g_system == system_type::ps3 && cpu->id_type() != 1 ? static_cast(*cpu).offset : 0; + m_debugFrame->m_disasm->offset = (u8*)vm::base(cpu_offset); + + m_debugFrame->m_disasm->disasm(m_debugFrame->m_disasm->dump_pc = pc); + + QString breakpointItemText = qstr(m_debugFrame->m_disasm->last_opcode); + + breakpointItemText.remove(10, 13); + + QListWidgetItem* breakpointItem = new QListWidgetItem(breakpointItemText); + breakpointItem->setTextColor(m_text_color_bp); + breakpointItem->setBackgroundColor(m_color_bp); + QVariant pcVariant; + pcVariant.setValue(pc); + breakpointItem->setData(Qt::UserRole, pcVariant); + m_debugFrame->m_breakpoints_list->addItem(breakpointItem); } -void debugger_list::RemoveBreakPoint(u32 pc) +void debugger_list::RemoveBreakPoint(u32 pc, bool eraseFromMap) { - g_breakpoints.erase(pc); + if(eraseFromMap) + g_breakpoints.erase(pc); ppu_breakpoint(pc); + + int breakpointsListCount = m_debugFrame->m_breakpoints_list->count(); + + for (int i = 0; i < breakpointsListCount; i++) + { + QListWidgetItem* currentItem = m_debugFrame->m_breakpoints_list->item(i); + + if (currentItem->data(Qt::UserRole).value() == pc) + { + delete m_debugFrame->m_breakpoints_list->takeItem(i); + break; + } + } + + ShowAddr(m_pc - (m_item_count) * 4); + } void debugger_list::keyPressEvent(QKeyEvent* event) diff --git a/rpcs3/rpcs3qt/debugger_frame.h b/rpcs3/rpcs3qt/debugger_frame.h index b2f096c482..ff7e1d662d 100644 --- a/rpcs3/rpcs3qt/debugger_frame.h +++ b/rpcs3/rpcs3qt/debugger_frame.h @@ -36,6 +36,7 @@ class debugger_frame : public QDockWidget Q_OBJECT debugger_list* m_list; + QSplitter* m_right_splitter; QFont m_mono; QTextEdit* m_regs; QPushButton* m_go_to_addr; @@ -61,8 +62,11 @@ class debugger_frame : public QDockWidget std::shared_ptr xgui_settings; + QAction* m_breakpoints_list_delete; + public: std::unique_ptr m_disasm; + QListWidget* m_breakpoints_list; std::weak_ptr cpu; public: @@ -93,6 +97,9 @@ Q_SIGNALS: public Q_SLOTS: void DoStep(); private Q_SLOTS: + void OnBreakpointList_doubleClicked(); + void OnBreakpointList_rightClicked(const QPoint &pos); + void OnBreakpointList_delete(); void OnSelectUnit(); void Show_Val(); void Show_PC(); @@ -117,11 +124,11 @@ public: public: debugger_list(debugger_frame* parent); void ShowAddr(u32 addr); + void RemoveBreakPoint(u32 pc, bool eraseFromMap = true); private: bool IsBreakPoint(u32 pc); void AddBreakPoint(u32 pc); - void RemoveBreakPoint(u32 pc); protected: void keyPressEvent(QKeyEvent* event); @@ -129,3 +136,5 @@ protected: void wheelEvent(QWheelEvent* event); void resizeEvent(QResizeEvent* event); }; + +Q_DECLARE_METATYPE(u32); \ No newline at end of file