diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f0bc063..e990ca1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -111,6 +111,7 @@ set(HEADER_FILES SeerStructVisualizerWidget.h SeerVarVisualizerWidget.h SeerImageVisualizerWidget.h + SeerMonitorVisualizerWidget.h SeerRegisterValuesBrowserWidget.h SeerRegisterEditValueDialog.h SeerRegisterProfileDialog.h @@ -224,6 +225,7 @@ set(SOURCE_FILES SeerStructVisualizerWidget.cpp SeerVarVisualizerWidget.cpp SeerImageVisualizerWidget.cpp + SeerMonitorVisualizerWidget.cpp SeerRegisterValuesBrowserWidget.cpp SeerRegisterEditValueDialog.cpp SeerRegisterProfileDialog.cpp diff --git a/src/QHistoryLineEdit.h b/src/QHistoryLineEdit.h index e9a1990..acf0668 100644 --- a/src/QHistoryLineEdit.h +++ b/src/QHistoryLineEdit.h @@ -34,50 +34,50 @@ class QHistoryLineEdit : public QLineEdit { QHistoryLineEdit(const QString& contents, QWidget* parent = 0); QHistoryLineEdit(QWidget* parent = 0); - void enableReturnPressedOnClear (); + void enableReturnPressedOnClear (); - int lineCount () const; + int lineCount () const; - void setHistory (const QStringList& history); - QStringList history() const; + void setHistory (const QStringList& history); + QStringList history () const; - void setWordCompleter (QCompleter* completer); - void setWordCompleterPrefix (const QString& prefix); - void setWordCompleterMinChars (int minChars); - void setWordCompleterMaxSuggestions (int max); + void setWordCompleter (QCompleter* completer); + void setWordCompleterPrefix (const QString& prefix); + void setWordCompleterMinChars (int minChars); + void setWordCompleterMaxSuggestions (int max); public slots: - void execute (); + void execute (); signals: - void lineExecuted (QString text); - void lostFocus (); - void gainedFocus (); - void escapePressed (); + void lineExecuted (QString text); + void lostFocus (); + void gainedFocus (); + void escapePressed (); protected: - void keyPressEvent (QKeyEvent* event) Q_DECL_OVERRIDE; - void wheelEvent (QWheelEvent* event) Q_DECL_OVERRIDE; - void focusOutEvent (QFocusEvent* event) Q_DECL_OVERRIDE; - void focusInEvent (QFocusEvent* event) Q_DECL_OVERRIDE; + void keyPressEvent (QKeyEvent* event) Q_DECL_OVERRIDE; + void wheelEvent (QWheelEvent* event) Q_DECL_OVERRIDE; + void focusOutEvent (QFocusEvent* event) Q_DECL_OVERRIDE; + void focusInEvent (QFocusEvent* event) Q_DECL_OVERRIDE; - void previousLine (); - void nextLine (); + void previousLine (); + void nextLine (); - QString current_word () const; + QString current_word () const; private slots: - void autoComplete (const QString& completion); + void autoComplete (const QString& completion); private: - int _wordStart () const; + int _wordStart () const; - int _currentLine; - QStringList _lines; - QString _unfinished; - QCompleter* _completer; - QString _completionPrefix; - int _completionMinchars; - int _completionMax; + int _currentLine; + QStringList _lines; + QString _unfinished; + QCompleter* _completer; + QString _completionPrefix; + int _completionMinchars; + int _completionMax; }; diff --git a/src/SeerGdbWidget.cpp b/src/SeerGdbWidget.cpp index db04112..46cf197 100644 --- a/src/SeerGdbWidget.cpp +++ b/src/SeerGdbWidget.cpp @@ -10,6 +10,7 @@ #include "SeerStructVisualizerWidget.h" #include "SeerVarVisualizerWidget.h" #include "SeerImageVisualizerWidget.h" +#include "SeerMonitorVisualizerWidget.h" #include "SeerHelpPageDialog.h" #include "SeerUtl.h" #include "QHContainerWidget.h" @@ -864,6 +865,10 @@ void SeerGdbWidget::handleGdbCommands (const QStringList& commands) { } } +void SeerGdbWidget::handleGdbMonitorCommand (int id, const QString& command) { + handleGdbCommand(QString::number(id)+"-monitor-exec " + command); +} + void SeerGdbWidget::handleGdbExit () { handleGdbCommand("-gdb-exit"); @@ -3051,6 +3056,21 @@ void SeerGdbWidget::handleGdbImageVisualizer () { handleGdbImageAddExpression(""); } +void SeerGdbWidget::handleGdbMonitorVisualizer () { + + if (executableLaunchMode() == "") { + return; + } + + SeerMonitorVisualizerWidget* w = new SeerMonitorVisualizerWidget(0); + w->show(); + + // Connect things. + QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerMonitorVisualizerWidget::handleText); + QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerMonitorVisualizerWidget::handleText); + QObject::connect(w, &SeerMonitorVisualizerWidget::executeGdbMonitorCommand, this, &SeerGdbWidget::handleGdbMonitorCommand); +} + void SeerGdbWidget::handleSplitterMoved (int pos, int index) { Q_UNUSED(pos); diff --git a/src/SeerGdbWidget.h b/src/SeerGdbWidget.h index d8e8b60..a41e00c 100644 --- a/src/SeerGdbWidget.h +++ b/src/SeerGdbWidget.h @@ -216,6 +216,7 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm { void handleManualCommandExecute (QString command); void handleGdbCommand (const QString& command, bool ignoreErrors=false); void handleGdbCommands (const QStringList& commands); + void handleGdbMonitorCommand (int id, const QString& command); void handleGdbExit (); void handleGdbRunExecutable (const QString& breakMode, bool loadSessionBreakpoints); void handleGdbAttachExecutable (bool loadSessionBreakpoints); @@ -356,6 +357,7 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm { void handleGdbStructVisualizer (); void handleGdbVarVisualizer (); void handleGdbImageVisualizer (); + void handleGdbMonitorVisualizer (); void handleSplitterMoved (int pos, int index); void handleGdbAssemblyDisassemblyFlavor (); void handleGdbAssemblySymbolDemangling (); diff --git a/src/SeerMacroEditorDialog.ui b/src/SeerMacroEditorDialog.ui index 209f3c9..40896d1 100644 --- a/src/SeerMacroEditorDialog.ui +++ b/src/SeerMacroEditorDialog.ui @@ -21,7 +21,7 @@ - Insert gdb commands on multiple lines + Insert commands on multiple lines diff --git a/src/SeerMacroToolButton.cpp b/src/SeerMacroToolButton.cpp index 4e2a834..f24065c 100644 --- a/src/SeerMacroToolButton.cpp +++ b/src/SeerMacroToolButton.cpp @@ -28,27 +28,31 @@ SeerMacroToolButton::SeerMacroToolButton(QWidget* parent) : QToolButton(parent) connect(_holdTimer, &QTimer::timeout, this, &SeerMacroToolButton::handleHoldTriggered); } -void SeerMacroToolButton::setMacroName (const QString& name) { +void SeerMacroToolButton::setMacroName (const QString& name, const QString& context) { // Set the macro name. If it's "", nullify our state. - _macroName = name; + _macroName = name; + _macroContext = context; if (_macroName == "") { + _macroContext = ""; _macroFileName = ""; return; } // Add combination shortcut for re-open closed file (Ctrl + Shift + T) - QShortcut* shortcut = new QShortcut(QKeySequence(QString("Ctrl+Shift+")+_macroName[1]), this); + if (macroContext() == "") { + QShortcut* shortcut = new QShortcut(QKeySequence(QString("Ctrl+Shift+")+_macroName[1]), this); - QObject::connect(shortcut, &QShortcut::activated, this, &QToolButton::click); + QObject::connect(shortcut, &QShortcut::activated, this, &QToolButton::click); + } // Create the macro filename where the macro is to be written. QSettings settings; QFileInfo fileInfo(settings.fileName()); - _macroFileName = fileInfo.absolutePath() + "/macros/" + _macroName + ".macro"; + _macroFileName = fileInfo.absolutePath() + "/macros/" + macroContext() + "/" + _macroName + ".macro"; // Read settings now we have a proper macro name. readMacro(); @@ -59,6 +63,11 @@ const QString& SeerMacroToolButton::macroName () const { return _macroName; } +const QString& SeerMacroToolButton::macroContext () const { + + return _macroContext; +} + const QString& SeerMacroToolButton::macroFileName () const { return _macroFileName; diff --git a/src/SeerMacroToolButton.h b/src/SeerMacroToolButton.h index 430108c..6275afb 100644 --- a/src/SeerMacroToolButton.h +++ b/src/SeerMacroToolButton.h @@ -15,8 +15,9 @@ class SeerMacroToolButton : public QToolButton { public: explicit SeerMacroToolButton(QWidget* parent = nullptr); - void setMacroName (const QString& name); + void setMacroName (const QString& name, const QString& context = ""); const QString& macroName () const; + const QString& macroContext () const; const QString& macroFileName () const; void setCommands (const QStringList& commands); @@ -39,6 +40,7 @@ class SeerMacroToolButton : public QToolButton { QTimer* _holdTimer; QMenu* _menu; QPoint _pressPos; + QString _macroContext; QString _macroName; QString _macroFileName; QStringList _commands; diff --git a/src/SeerMainWindow.cpp b/src/SeerMainWindow.cpp index 77001ae..686d4cd 100644 --- a/src/SeerMainWindow.cpp +++ b/src/SeerMainWindow.cpp @@ -104,13 +104,14 @@ SeerMainWindow::SeerMainWindow(QWidget* parent) : QMainWindow(parent) { // Set up Visualizer menu. QMenu* menuVisualizer = new QMenu(this); - QAction* visualizerMemoryAction = menuVisualizer->addAction("Memory"); + QAction* visualizerMemoryAction = menuVisualizer->addAction("Memory"); menuVisualizer->addSeparator(); - QAction* visualizerArrayAction = menuVisualizer->addAction("Array"); - QAction* visualizerMatrixAction = menuVisualizer->addAction("Matrix"); - QAction* visualizerVarAction = menuVisualizer->addAction("Struct"); - QAction* visualizerStructAction = menuVisualizer->addAction("Basic Struct"); - QAction* visualizerImageAction = menuVisualizer->addAction("Image"); + QAction* visualizerArrayAction = menuVisualizer->addAction("Array"); + QAction* visualizerMatrixAction = menuVisualizer->addAction("Matrix"); + QAction* visualizerVarAction = menuVisualizer->addAction("Struct"); + QAction* visualizerStructAction = menuVisualizer->addAction("Basic Struct"); + QAction* visualizerImageAction = menuVisualizer->addAction("Image"); + QAction* visualizerGdbMonitorAction = menuVisualizer->addAction("GDB Monitor"); actionVisualizers->setMenu(menuVisualizer); @@ -138,6 +139,7 @@ SeerMainWindow::SeerMainWindow(QWidget* parent) : QMainWindow(parent) { QObject::connect(actionViewStructVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewVarVisualizer); QObject::connect(actionViewBasicStructVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewStructVisualizer); QObject::connect(actionViewImageVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewImageVisualizer); + QObject::connect(actionViewGdbMonitorVisualizer, &QAction::triggered, this, &SeerMainWindow::handleViewGdbMonitorVisualizer); QObject::connect(actionViewAssembly, &QAction::triggered, this, &SeerMainWindow::handleViewAssembly); QObject::connect(actionConsoleAttached, &QAction::triggered, this, &SeerMainWindow::handleViewConsoleAttached); QObject::connect(actionConsoleDetached, &QAction::triggered, this, &SeerMainWindow::handleViewConsoleDetached); @@ -197,6 +199,7 @@ SeerMainWindow::SeerMainWindow(QWidget* parent) : QMainWindow(parent) { QObject::connect(visualizerVarAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbVarVisualizer); QObject::connect(visualizerStructAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbStructVisualizer); QObject::connect(visualizerImageAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbImageVisualizer); + QObject::connect(visualizerGdbMonitorAction, &QAction::triggered, gdbWidget, &SeerGdbWidget::handleGdbMonitorVisualizer); QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::astrixTextOutput, runStatus, &SeerRunStatusIndicator::handleText); QObject::connect(gdbWidget->gdbMonitor(), &GdbMonitor::equalTextOutput, runStatus, &SeerRunStatusIndicator::handleText); @@ -707,6 +710,11 @@ void SeerMainWindow::handleViewImageVisualizer () { gdbWidget->handleGdbImageVisualizer(); } +void SeerMainWindow::handleViewGdbMonitorVisualizer () { + + gdbWidget->handleGdbMonitorVisualizer(); +} + void SeerMainWindow::handleViewAssembly () { gdbWidget->editorManager()->showAssembly(); diff --git a/src/SeerMainWindow.h b/src/SeerMainWindow.h index 716e4a9..d7a8817 100644 --- a/src/SeerMainWindow.h +++ b/src/SeerMainWindow.h @@ -89,6 +89,7 @@ class SeerMainWindow : public QMainWindow, protected Ui::SeerMainWindowForm { void handleViewStructVisualizer (); void handleViewVarVisualizer (); void handleViewImageVisualizer (); + void handleViewGdbMonitorVisualizer (); void handleViewAssembly (); void handleViewAssemblyShown (bool shown); void handleViewConsoleAttached (); diff --git a/src/SeerMainWindow.ui b/src/SeerMainWindow.ui index 80d5960..6f8401b 100644 --- a/src/SeerMainWindow.ui +++ b/src/SeerMainWindow.ui @@ -76,6 +76,7 @@ + @@ -813,6 +814,15 @@ QAction::NoRole + + + + :/seer/resources/thenounproject/memory.svg:/seer/resources/thenounproject/memory.svg + + + GDB Monitor Visualizer + + diff --git a/src/SeerMonitorVisualizerWidget.cpp b/src/SeerMonitorVisualizerWidget.cpp new file mode 100644 index 0000000..d4769c9 --- /dev/null +++ b/src/SeerMonitorVisualizerWidget.cpp @@ -0,0 +1,132 @@ +// SPDX-FileCopyrightText: 2026 Ernie Pasveer +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "SeerMonitorVisualizerWidget.h" +#include "SeerHelpPageDialog.h" +#include "SeerUtl.h" +#include +#include +#include +#include +#include + +SeerMonitorVisualizerWidget::SeerMonitorVisualizerWidget (QWidget* parent) : QWidget(parent) { + + // Init variables. + _monitorId = Seer::createID(); // Create id for gdb monitor messages. + + // Set up UI. + setupUi(this); + + // Setup the widgets + setWindowIcon(QIcon(":/seer/resources/icons/hicolor/64x64/seergdb.png")); + setWindowTitle("Seer - GDB Monitor Visualizer"); + setAttribute(Qt::WA_DeleteOnClose); + + m1ToolButton->setMacroName("M1", "gdbmonitor"); + m2ToolButton->setMacroName("M2", "gdbmonitor"); + m3ToolButton->setMacroName("M3", "gdbmonitor"); + m4ToolButton->setMacroName("M4", "gdbmonitor"); + m5ToolButton->setMacroName("M5", "gdbmonitor"); + m6ToolButton->setMacroName("M6", "gdbmonitor"); + m7ToolButton->setMacroName("M7", "gdbmonitor"); + m8ToolButton->setMacroName("M8", "gdbmonitor"); + m9ToolButton->setMacroName("M9", "gdbmonitor"); + m0ToolButton->setMacroName("M0", "gdbmonitor"); + + // Default font. + QFont font; + font.setFamily("monospace"); + font.setStyleHint(QFont::Monospace); + font.setFixedPitch(true); + + // Set the widget's font. + QTextCharFormat format = textEdit->currentCharFormat(); + format.setFont(font); + textEdit->setCurrentCharFormat(format); + textEdit->setFont(font); + + // Connect things. + QObject::connect(monitorCommandLineEdit, &QLineEdit::returnPressed, this, &SeerMonitorVisualizerWidget::handleCommandLineEdit); + QObject::connect(clearToolButton, &QToolButton::clicked, this, &SeerMonitorVisualizerWidget::handleClearButton); + QObject::connect(printToolButton, &QToolButton::clicked, this, &SeerMonitorVisualizerWidget::handlePrintButton); + QObject::connect(helpToolButton, &QToolButton::clicked, this, &SeerMonitorVisualizerWidget::handleHelpButton); + QObject::connect(macroButtonGroup, &QButtonGroup::buttonClicked, this, &SeerMonitorVisualizerWidget::handleMacroToolButtonClicked); + + // Restore window settings. + readSettings(); +} + +SeerMonitorVisualizerWidget::~SeerMonitorVisualizerWidget () { +} + +void SeerMonitorVisualizerWidget::handleText (const QString& text) { + qDebug() << text; +} + +void SeerMonitorVisualizerWidget::handleCommandLineEdit () { + + QString command = monitorCommandLineEdit->text(); + + monitorCommandLineEdit->clear(); + + emit executeGdbMonitorCommand(_monitorId, command); +} + +void SeerMonitorVisualizerWidget::handleClearButton () { +} + +void SeerMonitorVisualizerWidget::handlePrintButton () { +} + +void SeerMonitorVisualizerWidget::handleHelpButton () { + + SeerHelpPageDialog* help = new SeerHelpPageDialog; + help->loadFile(":/seer/resources/help/ArrayVisualizer.md"); + help->show(); + help->raise(); +} + +void SeerMonitorVisualizerWidget::handleMacroToolButtonClicked (QAbstractButton* button) { + + if (button == nullptr) { + return; + } + + SeerMacroToolButton* tb = qobject_cast(button); + + for (auto& command : tb->commands()) { + if (command == "") { + continue; + } + + emit executeGdbMonitorCommand(_monitorId, command); + } +} + +void SeerMonitorVisualizerWidget::writeSettings() { + + QSettings settings; + + settings.beginGroup("gdbmonitorvisualizerwindow"); { + settings.setValue("size", size()); + } settings.endGroup(); +} + +void SeerMonitorVisualizerWidget::readSettings() { + + QSettings settings; + + settings.beginGroup("gdbmonitorvisualizerwindow"); { + resize(settings.value("size", QSize(800, 400)).toSize()); + } settings.endGroup(); +} + +void SeerMonitorVisualizerWidget::resizeEvent (QResizeEvent* event) { + + writeSettings(); + + QWidget::resizeEvent(event); +} + diff --git a/src/SeerMonitorVisualizerWidget.h b/src/SeerMonitorVisualizerWidget.h new file mode 100644 index 0000000..410ade9 --- /dev/null +++ b/src/SeerMonitorVisualizerWidget.h @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2026 Ernie Pasveer +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include "ui_SeerMonitorVisualizerWidget.h" + +class SeerMonitorVisualizerWidget : public QWidget, protected Ui::SeerMonitorVisualizerWidgetForm { + + Q_OBJECT + + public: + explicit SeerMonitorVisualizerWidget (QWidget* parent = 0); + ~SeerMonitorVisualizerWidget (); + + signals: + void executeGdbMonitorCommand (int monitorid, QString command); + + public slots: + void handleText (const QString& text); + + protected slots: + void handleCommandLineEdit (); + void handleClearButton (); + void handlePrintButton (); + void handleHelpButton (); + void handleMacroToolButtonClicked (QAbstractButton* button); + + protected: + void writeSettings (); + void readSettings (); + void resizeEvent (QResizeEvent* event); + + private: + int _monitorId; +}; + diff --git a/src/SeerMonitorVisualizerWidget.ui b/src/SeerMonitorVisualizerWidget.ui new file mode 100644 index 0000000..6dd6758 --- /dev/null +++ b/src/SeerMonitorVisualizerWidget.ui @@ -0,0 +1,281 @@ + + + SeerMonitorVisualizerWidgetForm + + + + 0 + 0 + 823 + 634 + + + + Seer - Gdb Monitor + + + + + + true + + + [output from gdb monitor] + + + + + + + + + M1 macro. Click to execute. Hold down to edit. + + + M1 + + + macroButtonGroup + + + + + + + M2 macro. Click to execute. Hold down to edit. + + + M2 + + + macroButtonGroup + + + + + + + M3 macro. Click to execute. Hold down to edit. + + + M3 + + + macroButtonGroup + + + + + + + M4 macro. Click to execute. Hold down to edit. + + + M4 + + + macroButtonGroup + + + + + + + M5 macro. Click to execute. Hold down to edit. + + + M5 + + + macroButtonGroup + + + + + + + M6 macro. Click to execute. Hold down to edit. + + + M6 + + + macroButtonGroup + + + + + + + M7 macro. Click to execute. Hold down to edit. + + + M7 + + + macroButtonGroup + + + + + + + M8 macro. Click to execute. Hold down to edit. + + + M8 + + + macroButtonGroup + + + + + + + M9 macro. Click to execute. Hold down to edit. + + + M9 + + + macroButtonGroup + + + + + + + M0 macro. Click to execute. Hold down to edit. + + + M0 + + + macroButtonGroup + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Monitor Command: + + + + + + + + 100 + 0 + + + + Enter a GDB monitor command. + + + true + + + + + + + Clear monitor output. + + + ... + + + + :/seer/resources/RelaxLightIcons/edit-delete.svg:/seer/resources/RelaxLightIcons/edit-delete.svg + + + + + + + Print the monitor contents. + + + ... + + + + :/seer/resources/RelaxLightIcons/document-print.svg:/seer/resources/RelaxLightIcons/document-print.svg + + + + + + + Help for the GDB monitor. + + + ... + + + + :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg + + + + + + + + + + SeerMacroToolButton + QToolButton +
SeerMacroToolButton.h
+
+ + QHistoryLineEdit + QLineEdit +
QHistoryLineEdit.h
+
+
+ + monitorCommandLineEdit + m1ToolButton + m2ToolButton + m3ToolButton + m4ToolButton + m5ToolButton + m6ToolButton + m7ToolButton + m8ToolButton + m9ToolButton + m0ToolButton + clearToolButton + printToolButton + helpToolButton + textEdit + + + + + + + + +
diff --git a/src/resource.qrc b/src/resource.qrc index f3560a8..c0d1114 100644 --- a/src/resource.qrc +++ b/src/resource.qrc @@ -92,6 +92,7 @@ resources/mi-python/MIObjectiveC.py resources/mi-python/MISignals.py resources/mi-python/MIStart.py + resources/mi-python/MIMonitor.py diff --git a/src/resources/mi-python/MIMonitor.py b/src/resources/mi-python/MIMonitor.py new file mode 100644 index 0000000..064dc00 --- /dev/null +++ b/src/resources/mi-python/MIMonitor.py @@ -0,0 +1,33 @@ +# SPDX-FileCopyrightText: 2026 Ernie Pasveer +# +# SPDX-License-Identifier: MIT + +import re + +# +# Python MI command to support gdb's "start" commands. +# + +class MIMonitor(gdb.MICommand): + """ + Send a command to gdb's monitor. + + -monitor-exec Rin a command in gdb's monitor. + + See: + https://sourceware.org/gdb/current/onlinedocs/gdb.html/Server.html + """ + + def __init__(self, name, mode): + self._mode = mode + super(MIMonitor, self).__init__(name) + + def invoke(self, argv): + if self._mode == "exec": + gdb.execute ("monitor " + " ".join(argv), to_string=True) + return None + else: + raise gdb.GdbError("monitor: Invalid parameter: %s" % self._mode) + +MIMonitor("-monitor-exec", "exec") +