Merge pull request #359 from epasveer/343-default-rr-trace-to-latest-trace-location

343 default rr trace to latest trace location
This commit is contained in:
Ernie Pasveer
2025-09-20 19:27:26 -05:00
committed by GitHub
8 changed files with 331 additions and 134 deletions
+4
View File
@@ -24,6 +24,10 @@
* Add support for remaining Catchpoint types.
* Add a Matrix Visualizer for viewing 2D arrays.
* Add breakpoints from the Function tab.
* When using the Debug dialog, save the debug settings so they can be fast loaded
the next time the Debug dialog is used. Kind of a default project.
* RR: When using the Debug dialog, check a couple standard locations for
the RR trace directory.
## [2.5] - 2024-12-24
* Console now supports a subset of ANSI color codes.
+259 -130
View File
@@ -7,6 +7,7 @@
#include "SeerDirectoryFilterProxyModel.h"
#include "SeerSlashProcDialog.h"
#include "SeerHelpPageDialog.h"
#include "SeerUtl.h"
#include "QHContainerWidget.h"
#include <QtWidgets/QFileDialog>
#include <QtWidgets/QMessageBox>
@@ -26,23 +27,10 @@ SeerDebugDialog::SeerDebugDialog (QWidget* parent) : QDialog(parent) {
setupUi(this);
buttonBox->button(QDialogButtonBox::Ok)->setText("Launch");
buttonBox->button(QDialogButtonBox::Reset)->setText("Clear");
// Setup the widgets
setExecutableName("");
setExecutableSymbolName("");
setExecutableArguments("");
setBreakpointsFilename("");
setExecutableWorkingDirectory(QDir::currentPath());
setBreakpointMode("none");
setBreakpointFunctionName("");
setShowAssemblyTab(false);
setRandomizeStartAddress(false);
setNonStopMode(false);
setAttachPid(0);
setConnectHostPort("");
setRRTraceDirectory("");
setCoreFilename("");
setProjectFilename("");
reset();
// Create editor options bar.
QToolButton* loadProjectToolButton = new QToolButton(runModeTabWidget);
@@ -84,17 +72,52 @@ SeerDebugDialog::SeerDebugDialog (QWidget* parent) : QDialog(parent) {
QObject::connect(helpRRToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleHelpRRToolButtonClicked);
QObject::connect(helpCorefileToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleHelpCorefileToolButtonClicked);
QObject::connect(runModeTabWidget, &QTabWidget::currentChanged, this, &SeerDebugDialog::handleRunModeChanged);
QObject::connect(buttonBox, &QDialogButtonBox::accepted, this, &SeerDebugDialog::handleLaunchButtonClicked);
QObject::connect(buttonBox, &QDialogButtonBox::clicked, this, &SeerDebugDialog::handleResetButtonClicked);
// Set initial run mode.
handleRunModeChanged(0);
// Restore window settings.
readSettings();
// Read default project settings, if any.
loadDefaultProjectSettings();
}
SeerDebugDialog::~SeerDebugDialog () {
}
void SeerDebugDialog::reset () {
// At least retain the launch mode.
QString launchmode = launchMode();
// Reset everything else.
setExecutableName("");
setExecutableSymbolName("");
setExecutableWorkingDirectory("");
setExecutableArguments("");
setBreakpointsFilename("");
setBreakpointFunctionName("");
setBreakpointSourceName("");
setBreakpointMode("inmain");
setShowAssemblyTab(false);
setRandomizeStartAddress(false);
setNonStopMode(false);
setPreGdbCommands(QStringList());
setPostGdbCommands(QStringList());
setAttachPid(0);
setConnectHostPort("");
setConnectRemoteTargetType("remote");
setConnectGdbserverDebug(false);
setRRTraceDirectory("");
setCoreFilename("");
setLaunchMode(launchmode);
setProjectFilename("");
}
void SeerDebugDialog::setExecutableName (const QString& executableName) {
executableNameLineEdit->setText(executableName);
}
@@ -265,7 +288,7 @@ QString SeerDebugDialog::coreFilename () const {
void SeerDebugDialog::setAttachPid (int pid) {
if (pid < 1) {
attachProgramPidLineEdit->clear();
attachProgramPidLineEdit->setText("");
}else{
attachProgramPidLineEdit->setText(QString::number(pid));
}
@@ -341,11 +364,15 @@ void SeerDebugDialog::setLaunchMode (const QString& mode) {
runModeTabWidget->setCurrentIndex(0);
setBreakpointMode("none");
setBreakpointMode("inmain");
}else{
qWarning() << "Unknown launch mode of:" << mode;
runModeTabWidget->setCurrentIndex(0);
setBreakpointMode("inmain");
}
}
@@ -485,6 +512,7 @@ void SeerDebugDialog::handleLoadProjectToolButton () {
void SeerDebugDialog::loadProject (const QString& filename, bool notify) {
// Look for the mainwindow to place possible QMessageBox on.
QWidget* p = this;
if (isHidden() == true) {
@@ -508,6 +536,145 @@ 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);
if (f == false) {
return;
}
if (notify) {
QMessageBox::information(p, "Success", QString("Loaded the Seer project file '%1'.").arg(filename));
}
}
QJsonDocument SeerDebugDialog::makeJsonDoc() const {
// Build the JSON document.
QJsonDocument jsonDoc;
QJsonObject rootJson;
QJsonObject seerProjectJson;
QJsonArray preConnectCommands;
QJsonArray postConnectCommands;
// Save pre/post gdb commands.
QStringList preCommands = preGdbCommands();
QStringList postCommands = postGdbCommands();
for (const auto& i : preCommands) {
preConnectCommands.push_back(QJsonValue(i));
}
for (const auto& i : postCommands) {
postConnectCommands.push_back(QJsonValue(i));
}
seerProjectJson["executable"] = QJsonValue(executableNameLineEdit->text());
seerProjectJson["symbolfile"] = QJsonValue(executableSymbolNameLineEdit->text());
seerProjectJson["workingdirectory"] = QJsonValue(executableWorkingDirectoryLineEdit->text());
seerProjectJson["pregdbcommands"] = preConnectCommands;
seerProjectJson["postgdbcommands"] = postConnectCommands;
// Save RUN project.
if (launchMode() == "run") {
QJsonObject modeJson;
modeJson["arguments"] = runProgramArgumentsLineEdit->text();
modeJson["breakpointsfile"] = loadBreakpointsFilenameLineEdit->text();
modeJson["nobreak"] = noBreakpointRadioButton->isChecked();
modeJson["breakinmain"] = breakpointInMainRadioButton->isChecked();
modeJson["breakinfunction"] = breakpointInFunctionRadioButton->isChecked();
modeJson["breakinfunctionname"] = breakpointInFunctionLineEdit->text();
modeJson["showassemblytab"] = showAsseblyTabCheckBox->isChecked();
modeJson["nonstopmode"] = nonStopModeCheckBox->isChecked();
modeJson["randomizestartaddress"] = randomizeStartAddressCheckBox->isChecked();
seerProjectJson["runmode"] = modeJson;
}
// Save START project.
if (launchMode() == "start") {
QJsonObject modeJson;
modeJson["arguments"] = runProgramArgumentsLineEdit->text();
modeJson["breakpointsfile"] = loadBreakpointsFilenameLineEdit->text();
modeJson["nobreak"] = noBreakpointRadioButton->isChecked();
modeJson["breakinmain"] = breakpointInMainRadioButton->isChecked();
modeJson["breakinfunction"] = breakpointInFunctionRadioButton->isChecked();
modeJson["breakinfunctionname"] = breakpointInFunctionLineEdit->text();
modeJson["showassemblytab"] = showAsseblyTabCheckBox->isChecked();
modeJson["nonstopmode"] = nonStopModeCheckBox->isChecked();
modeJson["randomizestartaddress"] = randomizeStartAddressCheckBox->isChecked();
seerProjectJson["startmode"] = modeJson;
}
// Save ATTACH project.
if (launchMode() == "attach") {
QJsonObject modeJson;
modeJson["pid"] = attachProgramPidLineEdit->text();
seerProjectJson["attachmode"] = modeJson;
}
// Save CONNECT project.
if (launchMode() == "connect") {
QJsonObject modeJson;
modeJson["gdbserver"] = connectProgramHostPortLineEdit->text();
modeJson["targettype"] = connectRemoteTargetTypeCombo->currentText();
modeJson["gdbserverdebug"] = connectGdbserverDebugCheckBox->isChecked();
seerProjectJson["connectmode"] = modeJson;
}
// Save RR project.
if (launchMode() == "rr") {
QJsonObject modeJson;
modeJson["tracedirectory"] = rrTraceDirectoryLineEdit->text();
modeJson["breakpointsfile"] = rrLoadBreakpointsFilenameLineEdit->text();
seerProjectJson["rrmode"] = modeJson;
}
// Save COREFILE project.
if (launchMode() == "corefile") {
QJsonObject modeJson;
modeJson["corefile"] = loadCoreFilenameLineEdit->text();
seerProjectJson["corefilemode"] = modeJson;
}
rootJson["seerproject"] = seerProjectJson;
jsonDoc.setObject(rootJson);
return jsonDoc;
}
bool SeerDebugDialog::loadJsonDoc (const QJsonDocument& jsonDoc, const QString& filename) {
// Look for the mainwindow to place possible QMessageBox on.
QWidget* p = this;
if (isHidden() == true) {
foreach (QWidget* w, qApp->topLevelWidgets()) {
if (QMainWindow* mainWin = qobject_cast<QMainWindow*>(w)) {
p = mainWin;
break;
}
}
}
QJsonObject rootJson;
QJsonObject seerProjectJson;
QJsonObject runModeJson;
@@ -521,7 +688,7 @@ void SeerDebugDialog::loadProject (const QString& filename, bool notify) {
if (jsonDoc.isObject() == false) {
QMessageBox::critical(p, "Error", QString("'%1' is not a Seer project file (bad Json format).").arg(filename));
return;
return false;
}
rootJson = jsonDoc.object();
@@ -537,7 +704,7 @@ void SeerDebugDialog::loadProject (const QString& filename, bool notify) {
if (seerProjectJson.isEmpty() == true) {
QMessageBox::critical(p, "Error", QString("'%1' is not a Seer project file (missing 'seerproject' section).").arg(filename));
return;
return false;
}
// Load executable/symbol/working directory.
@@ -660,9 +827,7 @@ void SeerDebugDialog::loadProject (const QString& filename, bool notify) {
setLaunchMode("corefile");
}
if (notify) {
QMessageBox::information(p, "Success", QString("Loaded the Seer project file '%1'.").arg(filename));
}
return true;
}
void SeerDebugDialog::handleSaveProjectToolButton () {
@@ -674,113 +839,8 @@ void SeerDebugDialog::handleSaveProjectToolButton () {
return;
}
// Build the JSON document.
QJsonDocument jsonDoc;
QJsonObject rootJson;
QJsonObject seerProjectJson;
QJsonArray preConnectCommands;
QJsonArray postConnectCommands;
// Save pre/post gdb commands.
QStringList preCommands = preGdbCommands();
QStringList postCommands = postGdbCommands();
for (const auto& i : preCommands) {
preConnectCommands.push_back(QJsonValue(i));
}
for (const auto& i : postCommands) {
postConnectCommands.push_back(QJsonValue(i));
}
seerProjectJson["executable"] = QJsonValue(executableNameLineEdit->text());
seerProjectJson["symbolfile"] = QJsonValue(executableSymbolNameLineEdit->text());
seerProjectJson["workingdirectory"] = QJsonValue(executableWorkingDirectoryLineEdit->text());
seerProjectJson["pregdbcommands"] = preConnectCommands;
seerProjectJson["postgdbcommands"] = postConnectCommands;
// Save RUN project.
if (launchMode() == "run") {
QJsonObject modeJson;
modeJson["arguments"] = runProgramArgumentsLineEdit->text();
modeJson["breakpointsfile"] = loadBreakpointsFilenameLineEdit->text();
modeJson["nobreak"] = noBreakpointRadioButton->isChecked();
modeJson["breakinmain"] = breakpointInMainRadioButton->isChecked();
modeJson["breakinfunction"] = breakpointInFunctionRadioButton->isChecked();
modeJson["breakinfunctionname"] = breakpointInFunctionLineEdit->text();
modeJson["showassemblytab"] = showAsseblyTabCheckBox->isChecked();
modeJson["nonstopmode"] = nonStopModeCheckBox->isChecked();
modeJson["randomizestartaddress"] = randomizeStartAddressCheckBox->isChecked();
seerProjectJson["runmode"] = modeJson;
}
// Save START project.
if (launchMode() == "start") {
QJsonObject modeJson;
modeJson["arguments"] = runProgramArgumentsLineEdit->text();
modeJson["breakpointsfile"] = loadBreakpointsFilenameLineEdit->text();
modeJson["nobreak"] = noBreakpointRadioButton->isChecked();
modeJson["breakinmain"] = breakpointInMainRadioButton->isChecked();
modeJson["breakinfunction"] = breakpointInFunctionRadioButton->isChecked();
modeJson["breakinfunctionname"] = breakpointInFunctionLineEdit->text();
modeJson["showassemblytab"] = showAsseblyTabCheckBox->isChecked();
modeJson["nonstopmode"] = nonStopModeCheckBox->isChecked();
modeJson["randomizestartaddress"] = randomizeStartAddressCheckBox->isChecked();
seerProjectJson["startmode"] = modeJson;
}
// Save ATTACH project.
if (launchMode() == "attach") {
QJsonObject modeJson;
modeJson["pid"] = attachProgramPidLineEdit->text();
seerProjectJson["attachmode"] = modeJson;
}
// Save CONNECT project.
if (launchMode() == "connect") {
QJsonObject modeJson;
modeJson["gdbserver"] = connectProgramHostPortLineEdit->text();
modeJson["targettype"] = connectRemoteTargetTypeCombo->currentText();
modeJson["gdbserverdebug"] = connectGdbserverDebugCheckBox->isChecked();
seerProjectJson["connectmode"] = modeJson;
}
// Save RR project.
if (launchMode() == "rr") {
QJsonObject modeJson;
modeJson["tracedirectory"] = rrTraceDirectoryLineEdit->text();
modeJson["breakpointsfile"] = rrLoadBreakpointsFilenameLineEdit->text();
seerProjectJson["rrmode"] = modeJson;
}
// Save COREFILE project.
if (launchMode() == "corefile") {
QJsonObject modeJson;
modeJson["corefile"] = loadCoreFilenameLineEdit->text();
seerProjectJson["corefilemode"] = modeJson;
}
rootJson["seerproject"] = seerProjectJson;
jsonDoc.setObject(rootJson);
// Make the json document for the debug dialog settings.
QJsonDocument jsonDoc = makeJsonDoc();
// Write the JSON document to the project file.
QFile saveFile(fname);
@@ -857,6 +917,30 @@ void SeerDebugDialog::handleRunModeChanged (int id) {
executableSymbolNameToolButton->setEnabled(true);
preCommandsPlainTextEdit->setPlaceholderText("gdb commands before \"RR trace-directory load\"");
postCommandsPlainTextEdit->setPlaceholderText("gdb commands after \"RR trace-directory load\"");
// Set default if we can. Otherwise, leave it blank.
//
if (rrTraceDirectoryLineEdit->text() == "") {
QStringList searchPaths = {
"$_RR_TRACE_DIR/latest-trace",
"$XDG_DATA_HOME/rr/latest-trace",
"$HOME/.local/share/rr/latest-trace"
};
QString defaultPath = "";
bool f;
for (const auto& path : searchPaths) {
defaultPath = Seer::expandEnv(path, &f);
if (f == false) {
continue;
}
if (QFile::exists(defaultPath)) {
setRRTraceDirectory(defaultPath);
break;
}
}
}
}
// ID == 4 COREFILE
@@ -870,6 +954,26 @@ void SeerDebugDialog::handleRunModeChanged (int id) {
}
}
void SeerDebugDialog::handleLaunchButtonClicked () {
QJsonDocument document = makeJsonDoc();
writeDefaultProjectSettings(document);
}
void SeerDebugDialog::handleResetButtonClicked (QAbstractButton* button) {
// Was the Reset button clicked?
QAbstractButton* resetButton = buttonBox->button(QDialogButtonBox::Reset);
if (button != resetButton) {
return;
}
// Reset all parameters.
reset();
}
void SeerDebugDialog::handleHelpModeToolButtonClicked () {
SeerHelpPageDialog* help = new SeerHelpPageDialog(this);
@@ -924,7 +1028,7 @@ void SeerDebugDialog::writeSettings() {
settings.beginGroup("debugdialog"); {
settings.setValue("size", size());
}settings.endGroup();
} settings.endGroup();
}
void SeerDebugDialog::readSettings() {
@@ -936,6 +1040,31 @@ void SeerDebugDialog::readSettings() {
} settings.endGroup();
}
void SeerDebugDialog::writeDefaultProjectSettings (const QJsonDocument& document) {
QSettings settings;
settings.beginGroup("debugdialog"); {
settings.setValue("defaultproject", document.toJson(QJsonDocument::Compact));
} settings.endGroup();
}
void SeerDebugDialog::loadDefaultProjectSettings () {
QSettings settings;
settings.beginGroup("debugdialog"); {
QVariant variantData = settings.value("defaultproject");
if (variantData.isValid()) {
QJsonDocument jsonDoc = QJsonDocument::fromJson(variantData.toByteArray());
loadJsonDoc(jsonDoc, "defaultproject");
}
} settings.endGroup();
}
void SeerDebugDialog::resizeEvent (QResizeEvent* event) {
// Write window settings.
+12
View File
@@ -8,6 +8,7 @@
#include <QtWidgets/QButtonGroup>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QJsonDocument>
#include "ui_SeerDebugDialog.h"
@@ -19,6 +20,9 @@ class SeerDebugDialog : public QDialog, protected Ui::SeerDebugDialogForm {
explicit SeerDebugDialog (QWidget* parent = 0);
~SeerDebugDialog ();
// Reset all
void reset ();
// For any run mode.
void setExecutableName (const QString& executableName);
QString executableName () const;
@@ -81,6 +85,11 @@ class SeerDebugDialog : public QDialog, protected Ui::SeerDebugDialogForm {
void setProjectFilename (const QString& filename);
QString projectFilename () const;
void loadProject (const QString& filename, bool notify);
void loadDefaultProjectSettings ();
// Make a json document of the current debug dialog settings.
QJsonDocument makeJsonDoc () const;
bool loadJsonDoc (const QJsonDocument& jsonDoc, const QString& filename);
protected slots:
void handleExecutableNameToolButton ();
@@ -94,6 +103,8 @@ class SeerDebugDialog : public QDialog, protected Ui::SeerDebugDialogForm {
void handleLoadProjectToolButton ();
void handleSaveProjectToolButton ();
void handleRunModeChanged (int id);
void handleLaunchButtonClicked ();
void handleResetButtonClicked (QAbstractButton* button);
private slots:
void handleHelpModeToolButtonClicked ();
@@ -106,6 +117,7 @@ class SeerDebugDialog : public QDialog, protected Ui::SeerDebugDialogForm {
protected:
void writeSettings ();
void readSettings ();
void writeDefaultProjectSettings (const QJsonDocument& document);
void resizeEvent (QResizeEvent* event);
private:
+5 -2
View File
@@ -227,7 +227,7 @@
</sizepolicy>
</property>
<property name="currentIndex">
<number>2</number>
<number>4</number>
</property>
<widget class="QWidget" name="runTab">
<property name="sizePolicy">
@@ -960,6 +960,9 @@
<property name="toolTip">
<string>The path and name of a core file.</string>
</property>
<property name="placeholderText">
<string>The path and name of the core file.</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
@@ -1007,7 +1010,7 @@
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset</set>
</property>
</widget>
</item>
+8 -1
View File
@@ -568,7 +568,14 @@ void SeerMainWindow::handleFileDebug () {
dlg.setCoreFilename(executableCoreFilename());
dlg.setPreGdbCommands(executablePreGdbCommands());
dlg.setPostGdbCommands(executablePostGdbCommands());
dlg.setProjectFilename(projectFilename());
// If there's a project, use it.
if (projectFilename() != "") {
dlg.setProjectFilename(projectFilename());
// Otherwise use the default project, if there is one.
}else{
dlg.loadDefaultProjectSettings();
}
setProjectFilename(""); // Clear project name here. No need to have it anymore.
+1 -1
View File
@@ -57,7 +57,7 @@ int main (int argc, char* argv[]) {
QCoreApplication::setApplicationName("seergdb");
QCoreApplication::setOrganizationName("seergdb");
QCoreApplication::setApplicationVersion(Seer::version() + " - Ernie Pasveer (c)2021 - 2024");
QCoreApplication::setApplicationVersion(Seer::version() + " - Ernie Pasveer (c)2021 - 2025");
//
// Parse arguments.
+24
View File
@@ -0,0 +1,24 @@
{
"seerproject": {
"executable": "/nas/erniep/Development/seer/tests/helloworld/helloworld",
"postgdbcommands": [
""
],
"pregdbcommands": [
""
],
"startmode": {
"arguments": "one two three",
"breakinfunction": false,
"breakinfunctionname": "",
"breakinmain": true,
"breakpointsfile": "",
"nobreak": false,
"nonstopmode": false,
"randomizestartaddress": false,
"showassemblytab": false
},
"symbolfile": "",
"workingdirectory": "/nas/erniep/Development/seer/tests/helloworld"
}
}
+18
View File
@@ -0,0 +1,18 @@
{
"seerproject": {
"connectmode": {
"gdbserver": ":1234",
"gdbserverdebug": false,
"targettype": "extended-remote"
},
"executable": "/nas/erniep/Development/seer/tests/helloworld/helloworld",
"postgdbcommands": [
""
],
"pregdbcommands": [
""
],
"symbolfile": "",
"workingdirectory": "/nas/erniep/Development/seer/tests/helloworld"
}
}