Merge pull request #398 from epasveer/377-suggestion-consider-publishing-this-project-on-flathub

377 suggestion consider publishing this project on flathub
This commit is contained in:
Ernie Pasveer
2025-12-10 11:05:42 -06:00
committed by GitHub
24 changed files with 517 additions and 239 deletions
+1
View File
@@ -8,6 +8,7 @@ images/ export-ignore
notes/ export-ignore
scripts/ export-ignore
tests/ export-ignore
flatpak/ export-ignore
notes/Theme_dark.png export-ignore
notes/Theme_light.png export-ignore
+2
View File
@@ -15,6 +15,8 @@
* Control: Add ^D to toggle record playback direction for RR, Undo, and gdb's Record.
* Control: Add SHIFT+F5 (etal) to reverse step (etc.) during record playback for RR, Undo, and gdb's Record.
* GDB: Add Seer config to set gdb architecture.
* GDB: Add an optional 'launcher' program to start gdb. eg: flatpak-spawn.
* Build: Add flatpak generation to github actions.
## [2.6] - 2025-10-07
* Watchpoints: Fixed regression when adding commands to a watchpoint.
+5
View File
@@ -0,0 +1,5 @@
.flatpak-builder
build-dir
repo
seer.flatpak
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
# Build the Seergdb flatpak
flatpak uninstall -y io.github.epasveer.seer
\rm -rf build-dir/ repo/ .flatpak-builder/ seer.flatpak
flatpak run org.flatpak.Builder --force-clean build-dir io.github.epasveer.seer.yml
flatpak run org.flatpak.Builder --force-clean --repo=repo build-dir io.github.epasveer.seer.yml
flatpak build-bundle repo seer.flatpak io.github.epasveer.seer master
flatpak install -y --bundle --user seer.flatpak
+40
View File
@@ -0,0 +1,40 @@
$ vim com.github.epasveer.seer.json
$ ls -l ~/.local/share/flatpak/app/com.github.epasveer.seer/
$ flatpak update
$ flatpak install flathub org.kde.Sdk//6.10
$ flatpak install flathub org.kde.Platform//6.10
$ flatpak list
Name Application ID Version Branch Installation
Flatpak Builder Flatpak org.flatpak.Builder v0-Flathub stable system
...
$ flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
$ flatpak info io.github.epasveer.seer
$ flatpak search gdb
$ flatpak remove io.github.epasveer.seer
$ flatpak-builder --force-clean build-dir io.github.epasveer.seer.yml
$ flatpak-builder --user --install --force-clean build-dir io.github.epasveer.seer.yml
$ flatpak run io.github.epasveer.seer -s /nas/erniep/Development/seer/tests/hellostruct/hellostruct
$ flatpak run io.github.epasveer.seer --gdb-program=/app/bin/gdb -s /nas/erniep/Development/seer/tests/hellostruct/hellostruct
$ flatpak run --command=bash io.github.epasveer.seer
$ flatpak run --command=bash org.gnome.Sdk//46
$ flatpak run --command=bash org.freedesktop.Platform.GL.default
$ flatpak run --command=bash org.freedesktop.Sdk//24.08
$ flatpak run --command=bash org.freedesktop.Sdk/x86_64/25.08
$ flatpak uninstall -y io.github.epasveer.seer
$ \rm -rf build-dir/ repo/ .flatpak-builder/ seer.flatpak
$ flatpak run org.flatpak.Builder --force-clean build-dir io.github.epasveer.seer.yml
$ flatpak run org.flatpak.Builder --force-clean --repo=repo build-dir io.github.epasveer.seer.yml
$ flatpak build-bundle repo seer.flatpak io.github.epasveer.seer master
$ flatpak install -y --bundle --user seer.flatpak
$ flatpak run --command=flatpak-builder-lint org.flatpak.Builder repo repo
$ flatpak run --command=flatpak-builder-lint org.flatpak.Builder manifest io.github.epasveer.seer.yml
+13
View File
@@ -0,0 +1,13 @@
[Desktop Entry]
Version=1.0
Type=Application
Name=seer
GenericName=GDB Frontend
Comment=A GUI frontend to GDB debugger
Icon=io.github.epasveer.seer
Exec=seergdb
Terminal=false
Categories=Development;Debugger;Qt;
Keywords=debug;gdb;debugger;qt;
StartupNotify=true
X-Flatpak=io.github.epasveer.seer
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>io.github.epasveer.seer</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>GPL-3.0-or-later</project_license>
<name>seer</name>
<summary>A GUI frontend to GDB debugger</summary>
<description>
<p>
Seer is a graphical frontend to the GDB debugger that provides a rich development environment for debugging programs.
</p>
<p>Features:</p>
<ul>
<li>Source code browsing and breakpoint management</li>
<li>Variable inspection and modification</li>
<li>Stack frame navigation</li>
<li>Memory inspection</li>
<li>Assembly view</li>
<li>Register view</li>
</ul>
</description>
<launchable type="desktop-id">io.github.epasveer.seer.desktop</launchable>
<screenshots>
<screenshot type="default">
<caption>Main debugging window</caption>
<image>https://raw.githubusercontent.com/epasveer/seer/main/images/mainview.png</image>
</screenshot>
</screenshots>
<url type="homepage">https://github.com/epasveer/seer</url>
<url type="bugtracker">https://github.com/epasveer/seer/issues</url>
<developer_name>Ernie Pasveer</developer_name>
<releases>
<release version="2.5" date="2025-07-19"/>
</releases>
<content_rating type="oars-1.1"/>
</component>
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

+36
View File
@@ -0,0 +1,36 @@
app-id: io.github.epasveer.seer
runtime: org.kde.Platform
runtime-version: '6.10'
sdk: org.kde.Sdk
command: seergdb
finish-args:
- --socket=fallback-x11
- --socket=wayland
- --device=dri
- --share=ipc
- --filesystem=host # Filesystem access for debugging programs
- --talk-name=org.freedesktop.Flatpak # Permission to `flatpak-spawn --host`
modules:
- name: seergdb
buildsystem: simple
sources:
- type: git
url: https://github.com/epasveer/seer.git
# branch: main
branch: 377-suggestion-consider-publishing-this-project-on-flathub
# branch: 393-add-external-define-to-set-default-gdb-to-use
# commit: a04e774023ea69d06b4054f18fedbe26286a6957
# tag: v2.6
build-commands:
- mkdir build
- cd build && cmake -G Ninja -DCMAKE_INSTALL_PREFIX=/app -DCONFIG_SEER_GDB_LAUNCHER="flatpak-spawn --host" ../src
- cd build && ninja
- install -Dm755 build/seergdb /app/bin/seergdb
post-install:
- install -Dm644 flatpak/io.github.epasveer.seer.metainfo.xml /app/share/metainfo/io.github.epasveer.seer.metainfo.xml
- install -Dm644 flatpak/io.github.epasveer.seer.desktop /app/share/applications/io.github.epasveer.seer.desktop
- install -Dm644 flatpak/io.github.epasveer.seer.png /app/share/icons/hicolor/64x64/apps/io.github.epasveer.seer.png
- install -Dm644 flatpak/io.github.epasveer.seer.png /app/share/icons/hicolor/128x128/apps/io.github.epasveer.seer.png
- install -Dm644 flatpak/io.github.epasveer.seer.png /app/share/icons/hicolor/256x256/apps/io.github.epasveer.seer.png
- install -Dm644 flatpak/io.github.epasveer.seer.png /app/share/icons/hicolor/512x512/apps/io.github.epasveer.seer.png
+11 -1
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5.0)
cmake_minimum_required(VERSION 3.10.0)
project(seergdb VERSION 2.7.0 LANGUAGES CXX)
@@ -315,3 +315,13 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE
SEER_GDB_NAME=${CONFIG_SEER_GDB_NAME}
)
# Handle default gdb binary launcher (for flatpak, et al)
# -DCONFIG_SEER_GDB_LAUNCHER="flatpak-spawn --host"
if(NOT DEFINED CONFIG_SEER_GDB_LAUNCHER)
set(CONFIG_SEER_GDB_LAUNCHER "")
endif()
target_compile_definitions(${PROJECT_NAME} PRIVATE
SEER_GDB_LAUNCHER=${CONFIG_SEER_GDB_LAUNCHER}
)
+5 -1
View File
@@ -17,7 +17,11 @@ SeerAboutDialog::SeerAboutDialog (QWidget* parent) : QDialog(parent) {
// Get the About text from the resource.
QFile file(":/seer/resources/ABOUT.md");
file.open(QFile::ReadOnly | QFile::Text);
bool f = file.open(QFile::ReadOnly | QFile::Text);
if (f == false) {
return;
}
QTextStream stream(&file);
+10
View File
@@ -164,6 +164,16 @@ bool SeerConfigDialog::seerClearManualCommandHistory () const {
return _seerConfigPage->clearManualCommandHistory();
}
void SeerConfigDialog::setGdbLauncher (const QString& launcher) {
_gdbConfigPage->setGdbLauncher(launcher);
}
QString SeerConfigDialog::gdbLauncher () const {
return _gdbConfigPage->gdbLauncher();
}
void SeerConfigDialog::setGdbProgram (const QString& program) {
_gdbConfigPage->setGdbProgram(program);
+4
View File
@@ -44,6 +44,10 @@ class SeerConfigDialog : public QDialog, protected Ui::SeerConfigDialogForm {
bool seerClearManualCommandHistory () const;
// Gdb settings.
// Program to launch gdb, rr, etc. Can be blank. Needed by flatpak.
void setGdbLauncher (const QString& launcher);
QString gdbLauncher () const;
void setGdbProgram (const QString& program);
QString gdbProgram () const;
+5 -1
View File
@@ -81,8 +81,12 @@ void SeerConsoleWidget::handleText (const char* buffer, int count) {
}
// Write text to stdout on terminal that started Seer..
// Ignore errors.
if (isStdoutEnabled()) {
write (STDOUT_FILENO, buffer, count);
ssize_t n = ::write (STDOUT_FILENO, buffer, count);
if (n < count) {
qDebug("Can't write stdout to terminal");
}
}
// Write text to Ansi widget.
+3 -3
View File
@@ -527,9 +527,9 @@ void SeerDebugDialog::loadProject (const QString& filename, bool notify) {
// Open the project file.
QFile loadFile(filename);;
loadFile.open(QIODevice::ReadOnly);
if (loadFile.error() != 0) {
bool f = loadFile.open(QIODevice::ReadOnly);
if (f == false) {
QMessageBox::critical(p, "Error", QString("Can't open the Seer project file '%1'.").arg(filename));
return;
}
@@ -537,7 +537,7 @@ void SeerDebugDialog::loadProject (const QString& filename, bool notify) {
// Populate the JSON document from the project file.
QJsonDocument jsonDoc = QJsonDocument::fromJson(loadFile.readAll());
bool f = loadJsonDoc(jsonDoc, filename);
f = loadJsonDoc(jsonDoc, filename);
if (f == false) {
return;
}
+2 -3
View File
@@ -501,9 +501,8 @@ void SeerEditorWidgetSourceArea::open (const QString& fullname, const QString& f
QFile inputFile(filename);
inputFile.open(QIODevice::ReadOnly);
if (!inputFile.isOpen()) {
bool f = inputFile.open(QIODevice::ReadOnly);
if (f == false) {
QMessageBox::critical(this, "Can't read source file.", "Can't read : " + filename + "\nThe file is there but can't be opened.");
+17
View File
@@ -28,6 +28,11 @@ QString SeerGdbConfigPage::gdbProgram () const {
return gdbProgramLineEdit->text();
}
QString SeerGdbConfigPage::gdbLauncher () const {
return gdbLauncherLineEdit->text();
}
QString SeerGdbConfigPage::gdbArguments () const {
return gdbArgumentsLineEdit->text();
@@ -77,6 +82,11 @@ void SeerGdbConfigPage::setGdbProgram (const QString& program) {
gdbProgramLineEdit->setText(program);
}
void SeerGdbConfigPage::setGdbLauncher (const QString& launcher) {
return gdbLauncherLineEdit->setText(launcher);
}
void SeerGdbConfigPage::setGdbArguments (const QString& arguments) {
gdbArgumentsLineEdit->setText(arguments);
@@ -124,6 +134,13 @@ void SeerGdbConfigPage::reset () {
#else
setGdbProgram("/usr/bin/gdb";
#endif
#ifdef SEER_GDB_LAUNCHER
setGdbLauncher(STRINGIFY(SEER_GDB_LAUNCHER));
#else
setGdbLauncher("");
#endif
setGdbArguments("--interpreter=mi");
setGdbAsyncMode(true);
setGdbNonStopMode(false);
+2
View File
@@ -17,6 +17,7 @@ class SeerGdbConfigPage : public QWidget, protected Ui::SeerGdbConfigPage {
~SeerGdbConfigPage ();
QString gdbProgram () const;
QString gdbLauncher () const;
QString gdbArguments () const;
bool gdbAsyncMode () const;
bool gdbNonStopMode () const;
@@ -28,6 +29,7 @@ class SeerGdbConfigPage : public QWidget, protected Ui::SeerGdbConfigPage {
void setGdbProgram (const QString& program);
void setGdbLauncher (const QString& launcher);
void setGdbArguments (const QString& arguments);
void setGdbAsyncMode (bool flag);
void setGdbNonStopMode (bool flag);
+152 -124
View File
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>788</width>
<height>714</height>
<height>881</height>
</rect>
</property>
<property name="windowTitle">
@@ -68,134 +68,160 @@
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="gdbAsyncModeCheckBox">
<property name="toolTip">
<string>Turn gdb 'async' mode on or off.</string>
</property>
<property name="text">
<string>Async mode</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="gdbNonStopModeCheckBox">
<property name="toolTip">
<string>Allow other threads to continue if any thread reaches a breakpoint.</string>
</property>
<property name="text">
<string>Non-stop mode</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="gdbRandomizeStartAddressCheckBox">
<property name="toolTip">
<string>Randomize the process start address.</string>
</property>
<property name="text">
<string>Randomize start address</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="gdbHandleTerminateExceptionCheckBox">
<property name="toolTip">
<string>Handle terminating exceptions when calling functions.</string>
</property>
<property name="text">
<string>Handle terminating-exception</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="gdbEnablePrettyPrintingCheckBox">
<property name="toolTip">
<string>Show variables with gdb's 'pretty-printing' system.</string>
</property>
<property name="text">
<string>Enable pretty-printing</string>
</property>
</widget>
</item>
</layout>
<item row="2" column="0">
<widget class="QLabel" name="gdbLauncherLabel">
<property name="text">
<string>GDB launcher</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="gdbRemoteTargetTypeLabel">
<property name="text">
<string>Remote target type</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="gdbRemoteTargetTypeCombo">
<property name="toolTip">
<string>Select the type of remote target connection.</string>
</property>
<item>
<property name="text">
<string>remote</string>
</property>
</item>
<item>
<property name="text">
<string>extended-remote</string>
</property>
</item>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_1">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>385</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="gdbArchitectureTypeLabel">
<property name="text">
<string>Architecture type</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="gdbArchitectureLineEdit">
<property name="toolTip">
<string>Executable architecture type.</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>385</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
<item row="2" column="1">
<widget class="QLineEdit" name="gdbLauncherLineEdit">
<property name="toolTip">
<string>The program, if needed, to launch the gdb binary.</string>
</property>
<property name="text">
<string/>
</property>
<property name="readOnly">
<bool>false</bool>
</property>
<property name="placeholderText">
<string>If needed, program and arguments to launch gdb.</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="gdbAsyncModeCheckBox">
<property name="toolTip">
<string>Turn gdb 'async' mode on or off.</string>
</property>
<property name="text">
<string>Async mode</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="gdbNonStopModeCheckBox">
<property name="toolTip">
<string>Allow other threads to continue if any thread reaches a breakpoint.</string>
</property>
<property name="text">
<string>Non-stop mode</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="gdbRandomizeStartAddressCheckBox">
<property name="toolTip">
<string>Randomize the process start address.</string>
</property>
<property name="text">
<string>Randomize start address</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="gdbHandleTerminateExceptionCheckBox">
<property name="toolTip">
<string>Handle terminating exceptions when calling functions.</string>
</property>
<property name="text">
<string>Handle terminating-exception</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="gdbEnablePrettyPrintingCheckBox">
<property name="toolTip">
<string>Show variables with gdb's 'pretty-printing' system.</string>
</property>
<property name="text">
<string>Enable pretty-printing</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="gdbRemoteTargetTypeLabel">
<property name="text">
<string>Remote target type</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="gdbRemoteTargetTypeCombo">
<property name="toolTip">
<string>Select the type of remote target connection.</string>
</property>
<item>
<property name="text">
<string>remote</string>
</property>
</item>
<item>
<property name="text">
<string>extended-remote</string>
</property>
</item>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_1">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>385</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="gdbArchitectureTypeLabel">
<property name="text">
<string>Architecture type</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="gdbArchitectureLineEdit">
<property name="toolTip">
<string>Executable architecture type.</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>385</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QTextBrowser" name="textBrowser">
<property name="html">
@@ -212,6 +238,8 @@ li.checked::marker { content: &quot;\2612&quot;; }
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Note, Seer relies on the &amp;quot;mi&amp;quot; interpreter that is built into gdb. If a different debugger is used, it must provide that. So, usually, the &amp;quot;--interpreter=mi&amp;quot; argument is a must.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Sometimes gdb needs to be launched by another program. For example, under flatpak, gdb needs to be launched by flatpak-spawn. This can be defined when compiling Seer. See the CMakefile.txt file. Or manually set here. Normally, this does not need to be set. This launcher is also used for launching RR.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Async mode allows all gdb actions to happen in the background. This allows interrupting of a running program possible. Note, this is disabled for 'connect' mode as background commands may overwhelm the gdbserver.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Non-stop mode, when turned on, will allow other threads to continue to run while another thread reaches a breakpoint.&lt;/p&gt;
+87 -45
View File
@@ -61,11 +61,19 @@ SeerGdbWidget::SeerGdbWidget (QWidget* parent) : QWidget(parent) {
_catchpointsBrowserWidget = 0;
_gdbOutputLog = 0;
_seerOutputLog = 0;
#ifdef SEER_GDB_NAME
_gdbProgram = STRINGIFY(SEER_GDB_NAME);
#else
_gdbProgram = "/usr/bin/gdb";
#endif
#ifdef SEER_GDB_LAUNCHER
_gdbLauncher = STRINGIFY(SEER_GDB_LAUNCHER);
#else
_gdbLauncher = "";
#endif
_gdbArguments = "--interpreter=mi";
_gdbASyncMode = true;
_gdbNonStopMode = false;
@@ -630,6 +638,16 @@ QString SeerGdbWidget::gdbProgram () const {
return _gdbProgram;
}
void SeerGdbWidget::setGdbLauncher (const QString& launchProgram) {
_gdbLauncher = launchProgram;
}
QString SeerGdbWidget::gdbLauncher () const {
return _gdbLauncher;
}
void SeerGdbWidget::setGdbArguments (const QString& arguments) {
_gdbArguments = arguments;
@@ -1034,15 +1052,17 @@ void SeerGdbWidget::handleManualCommandExecute () {
handleGdbCommand(command);
}
void SeerGdbWidget::handleGdbCommand (const QString& command) {
void SeerGdbWidget::handleGdbCommand (const QString& command, bool ignoreErrors) {
qCDebug(LC) << "Command=" << command;
if (_gdbProcess->state() == QProcess::NotRunning) {
QMessageBox::warning(this, "Seer",
QString("The executable has not been started yet or has already exited.\n\n") +
"(" + command + ")",
QMessageBox::Ok);
if (ignoreErrors == false) {
QMessageBox::warning(this, "Seer",
QString("The executable has not been started yet or has already exited.\n\n") +
"(" + command + ")",
QMessageBox::Ok);
}
return;
}
@@ -1679,12 +1699,12 @@ void SeerGdbWidget::handleGdbTerminateExecutable (bool confirm) {
}
}
handleGdbCommand(QString("save breakpoints /tmp/breakpoints.seer.%1").arg(QCoreApplication::applicationPid()));
handleGdbCommand(QString("save breakpoints /tmp/breakpoints.seer.%1").arg(QCoreApplication::applicationPid()), true);
delay(2);
// Give the gdb and 'exit' command.
// This should handle detaching from an attached pid.
handleGdbCommand("-exec-kill");
handleGdbCommand("-exec-kill", true);
// Kill the gdb.
killGdb();
@@ -3640,53 +3660,51 @@ bool SeerGdbWidget::startGdb () {
return false;
}
// Set the gdb program name to use.
bool ok;
// Build the raw command to launch the gdb program.
// Later the raw command will be broken into individual strings (via ' ')
// that the QProcess object expects.
QString rawcommand;
QString rawcommand = gdbProgramOverride();
if (rawcommand == "") {
rawcommand = gdbProgram();
// Is a 'launcher' being used? Like 'flatpak-spawn'.
if (gdbLauncher() != "") {
rawcommand += gdbLauncher() + " ";
}
// Set the gdb program name to use.
if (gdbProgramOverride() != "") {
rawcommand += gdbProgramOverride() + " ";
}else{
rawcommand += gdbProgram() + " ";
}
// Build the gdb argument list.
if (gdbArgumentsOverride() != "") {
rawcommand += gdbArgumentsOverride() + " ";
}else{
rawcommand += gdbArguments() + " ";
}
// Now expand any $VAR environment variables.
bool ok;
QString expandedcommand = Seer::expandEnv(rawcommand, &ok);
//qDebug() << "Raw command : " << rawcommand;
//qDebug() << "Expanded command: " << expandedcommand;
if (ok == false) {
QMessageBox::critical(this, "Error", QString("Can't resolve all environment variables in command to launch gdb:\n'%1'").arg(rawcommand));
return false;
}
// Build the gdb argument list.
QString rawarguments = gdbArgumentsOverride();
if (rawarguments == "") {
rawarguments = gdbArguments();
}
QString expandedarguments = Seer::expandEnv(rawarguments, &ok);
//qDebug() << "Raw arguments : " << rawarguments;
//qDebug() << "Expanded arguments: " << expandedarguments;
if (ok == false) {
QMessageBox::critical(this, "Error", QString("Can't resolve all environment variables in arguments to launch gdb:\n'%1'").arg(rawarguments));
return false;
}
// Split string into words, handling "double quoted" words.
QStringList args = Seer::split(expandedarguments);
QStringList args = Seer::split(expandedcommand);
//qDebug() << args;
// Extract the program name and create a list of arguments.
QString program = args.front();
args.pop_front();
// Give the gdb process the program and the argument list.
_gdbProcess->setProgram(expandedcommand);
_gdbProcess->setProgram(program);
_gdbProcess->setArguments(args);
// We need to set the C language, otherwise the MI interface is translated and our message
@@ -3719,22 +3737,46 @@ bool SeerGdbWidget::startGdbRR () {
return false;
}
// Set the gdb program name to use.
QString command = rrProgram();
QString arguments = rrArguments() + " --tty " + _consoleWidget->terminalDeviceName() + " " + executableRRTraceDirectory();
// Build the raw command to launch the RR program.
// Later the raw command will be broken into individual strings (via ' ')
// that the QProcess object expects.
QString rawcommand;
// Is a 'launcher' being used? Like 'flatpak-spawn'.
if (gdbLauncher() != "") {
rawcommand += gdbLauncher() + " ";
}
// Set the RR program name to use.
rawcommand += rrProgram() + " ";
rawcommand += rrArguments() + " --tty " + _consoleWidget->terminalDeviceName() + " " + executableRRTraceDirectory() + " ";
// Set any extra gdb arguments that RR may want.
if (rrGdbArguments() != "") {
arguments += " -- " + rrGdbArguments();
rawcommand += "-- " + rrGdbArguments() + " ";
}
// Now expand any $VAR environment variables.
bool ok;
QString expandedcommand = Seer::expandEnv(rawcommand, &ok);
//qDebug() << "Raw command : " << rawcommand;
//qDebug() << "Expanded command: " << expandedcommand;
if (ok == false) {
QMessageBox::critical(this, "Error", QString("Can't resolve all environment variables in command to launch RR:\n'%1'").arg(rawcommand));
return false;
}
// Split string into words, handling "double quoted" words.
QStringList args = Seer::split(arguments);
QStringList args = Seer::split(expandedcommand);
//qDebug() << "Expanded command: " << command;
//qDebug() << "Expanded arguments: " << arguments;
// Extract the program name and create a list of arguments.
QString program = args.front();
args.pop_front();
// Give the gdb process the program and the argument list.
_gdbProcess->setProgram(command);
_gdbProcess->setProgram(program);
_gdbProcess->setArguments(args);
// We need to set the C language, otherwise the MI interface is translated and our message
+5 -1
View File
@@ -79,6 +79,9 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm {
const QString& executableBreakMode () const;
// Gdb settings.
void setGdbLauncher (const QString& launchProgram);
QString gdbLauncher () const;
void setGdbProgram (const QString& program);
QString gdbProgram () const;
@@ -228,7 +231,7 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm {
void handleText (const QString& text);
void handleManualCommandExecute ();
void handleGdbCommand (const QString& command);
void handleGdbCommand (const QString& command, bool ignoreErrors=false);
void handleGdbExit ();
void handleGdbRunExecutable (const QString& breakMode, bool loadSessionBreakpoints);
void handleGdbAttachExecutable (bool loadSessionBreakpoints);
@@ -417,6 +420,7 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm {
void delay (int seconds);
bool _isQuitting;
QString _gdbLauncher;
QString _gdbProgram;
QString _gdbArguments;
QString _gdbProgramOverride;
+5 -1
View File
@@ -37,7 +37,11 @@ void SeerHelpPageDialog::loadFile (const QString& filename) {
// Get the Help text from the file.
QFile file(filename);
file.open(QFile::ReadOnly|QFile::Text);
bool f = file.open(QFile::ReadOnly|QFile::Text);
if (f == false) {
return;
}
QTextStream stream(&file);
+15 -1
View File
@@ -534,7 +534,12 @@ void SeerMainWindow::setStyleName (const QString& name) {
return;
}
s.open(QFile::ReadOnly | QFile::Text);
bool f = s.open(QFile::ReadOnly | QFile::Text);
if (f == false) {
qDebug() << "Can't open Stylesheet '" + name + "'!";
return;
}
QTextStream ts(&s);
qApp->setStyleSheet(ts.readAll());
@@ -733,6 +738,7 @@ void SeerMainWindow::handleSettingsConfiguration () {
dlg.setSeerConsoleMode(gdbWidget->consoleMode());
dlg.setSeerConsoleScrollLines(gdbWidget->consoleScrollLines());
dlg.setSeerRememberManualCommandCount(gdbWidget->rememberManualCommandCount());
dlg.setGdbLauncher(gdbWidget->gdbLauncher());
dlg.setGdbProgram(gdbWidget->gdbProgram());
dlg.setGdbArguments(gdbWidget->gdbArguments());
dlg.setGdbAsyncMode(gdbWidget->gdbAsyncMode());
@@ -778,6 +784,7 @@ void SeerMainWindow::handleSettingsConfiguration () {
gdbWidget->setConsoleMode(dlg.seerConsoleMode());
gdbWidget->setConsoleScrollLines(dlg.seerConsoleScrollLines());
gdbWidget->setRememberManualCommandCount(dlg.seerRememberManualCommandCount());
gdbWidget->setGdbLauncher(dlg.gdbLauncher());
gdbWidget->setGdbProgram(dlg.gdbProgram());
gdbWidget->setGdbArguments(dlg.gdbArguments());
gdbWidget->setGdbAsyncMode(dlg.gdbAsyncMode());
@@ -1548,6 +1555,7 @@ void SeerMainWindow::writeConfigSettings () {
} settings.endGroup();
settings.beginGroup("gdb"); {
settings.setValue("launcher", gdbWidget->gdbLauncher());
settings.setValue("program", gdbWidget->gdbProgram());
settings.setValue("arguments", gdbWidget->gdbArguments());
settings.setValue("asyncmode", gdbWidget->gdbAsyncMode());
@@ -1628,6 +1636,12 @@ void SeerMainWindow::readConfigSettings () {
} settings.endGroup();
settings.beginGroup("gdb"); {
#ifdef SEER_GDB_LAUNCHER
gdbWidget->setGdbLauncher(settings.value("launcher", STRINGIFY(SEER_GDB_LAUNCHER)).toString());
#else
gdbWidget->setGdbLauncher(settings.value("launcher", "").toString());
#endif
#ifdef SEER_GDB_NAME
gdbWidget->setGdbProgram(settings.value("program", STRINGIFY(SEER_GDB_NAME)).toString());
#else
+50 -58
View File
@@ -13,45 +13,23 @@
<property name="windowTitle">
<string>SeerRRConfigPage</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="1" column="0">
<widget class="QTextBrowser" name="textBrowser">
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;meta charset=&quot;utf-8&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
hr { height: 1px; border-width: 0; }
li.unchecked::marker { content: &quot;\2610&quot;; }
li.checked::marker { content: &quot;\2612&quot;; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt; font-weight:600;&quot;&gt;Specify the RR program and location, as well as the RR arguments. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt; font-weight:600;&quot;&gt;Changing many of these require saving the new configuration and restarting Seer to take effect&lt;/span&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&lt;br /&gt;&amp;quot;RR program&amp;quot; points to the path and name of the RR program.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&amp;quot;RR arguments&amp;quot; specifies the arguments to pass to RR. It must minimally have 'replay --interpreter=mi'. And other arguments you may need for RR.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&amp;quot;GDB arguments&amp;quot; specified the arguments to pass on to gdb. Usually not needed.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Between these input fields, Seer forms the command:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; $ /usr/bin/rr replay --interpreter=mi [RR-arguments] [trace-directory] [--tty /dev/pts] [-- gdb-arguments] &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'Noto Sans'; font-size:10pt;&quot;&gt;Note, Seer relies on the &amp;quot;mi&amp;quot; interpreter that is built into gdb. So, the &amp;quot;--interpreter=mi&amp;quot; argument is a must. This is specified in the &amp;quot;RR arguments&amp;quot; field.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&lt;br /&gt;The &amp;quot;trace-directory&amp;quot; argument is given when you run Seer in the RR mode.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;The &amp;quot;--tty&amp;quot; device is handled automatically by Seer.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&lt;br /&gt;Here's the RR Wiki page for more info on arguments.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;https://github.com/rr-debugger/rr/wiki/Usage&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="rrGroupBox">
<property name="title">
<string>RR Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QLineEdit" name="rrProgramLineEdit">
<property name="toolTip">
<string>Specify the path and name of the RR debugger.</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="gdbProgramLabel">
<property name="text">
@@ -59,10 +37,17 @@ li.checked::marker { content: &quot;\2612&quot;; }
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="rrProgramLineEdit">
<item row="1" column="0">
<widget class="QLabel" name="rrArgumentsLabel">
<property name="text">
<string>RR arguments</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="gdbArgumentsLineEdit">
<property name="toolTip">
<string>Specify the path and name of the RR debugger.</string>
<string>Any extra arguments to pass to the gdb debugger.</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
@@ -83,14 +68,7 @@ li.checked::marker { content: &quot;\2612&quot;; }
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="rrArgumentsLabel">
<property name="text">
<string>RR arguments</string>
</property>
</widget>
</item>
<item row="1" column="1" rowspan="2">
<item row="1" column="1">
<widget class="QLineEdit" name="rrArgumentsLineEdit">
<property name="toolTip">
<string>Arguments to pass to the RR debugger.</string>
@@ -100,29 +78,43 @@ li.checked::marker { content: &quot;\2612&quot;; }
</property>
</widget>
</item>
<item row="2" column="0" rowspan="2">
<item row="2" column="0">
<widget class="QLabel" name="gdbArgumentsLabel">
<property name="text">
<string>GDB arguments</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="gdbArgumentsLineEdit">
<property name="toolTip">
<string>Any extra arguments to pass to the gdb debugger.</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QTextBrowser" name="textBrowser">
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;meta charset=&quot;utf-8&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
hr { height: 1px; border-width: 0; }
li.unchecked::marker { content: &quot;\2610&quot;; }
li.checked::marker { content: &quot;\2612&quot;; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Specify the RR program and location, as well as the RR arguments. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Changing many of these require saving the new configuration and restarting Seer to take effect&lt;/span&gt;.&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;&lt;br /&gt;&amp;quot;RR program&amp;quot; points to the path and name of the RR program.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;&amp;quot;RR arguments&amp;quot; specifies the arguments to pass to RR. It must minimally have 'replay --interpreter=mi'. And other arguments you may need for RR.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;&amp;quot;GDB arguments&amp;quot; specified the arguments to pass on to gdb. Usually not needed.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;RR will be started by the launcher specified in the GDB config tab.&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;Between these input fields, Seer forms the command:&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt; $ /usr/bin/rr replay --interpreter=mi [RR-arguments] [trace-directory] [--tty /dev/pts] [-- gdb-arguments] &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;&lt;br /&gt;&lt;/span&gt;Note, Seer relies on the &amp;quot;mi&amp;quot; interpreter that is built into gdb. So, the &amp;quot;--interpreter=mi&amp;quot; argument is a must. This is specified in the &amp;quot;RR arguments&amp;quot; field.&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;&lt;br /&gt;The &amp;quot;trace-directory&amp;quot; argument is given when you run Seer in the RR mode.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;The &amp;quot;--tty&amp;quot; device is handled automatically by Seer.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;&lt;br /&gt;Here's the RR Wiki page for more info on arguments.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Sans Serif';&quot;&gt;https://github.com/rr-debugger/rr/wiki/Usage&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
<zorder>rrGroupBox</zorder>
<zorder>textBrowser</zorder>
</widget>
<resources>
<include location="resource.qrc"/>