diff --git a/CHANGELOG.md b/CHANGELOG.md index d8ef21c1..6bd009a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Seer Change Log +## [2.4beta] - 2023-XX-XX +* Prepare for the 2.4 release cycle. +* Fixed string compares for breakpoint conditions (#184) + ## [2.3] - 2023-11-19 * In the margins of the source windows, allow CTRL+DoubleClick to do a quick RunToLine or RunToAddress. * Add --gdb-program and --gdb-arguments to command line to override settings from Seer's config. diff --git a/debian/changelog b/debian/changelog index 83ef178b..2c9924db 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,6 @@ -seergdb (2.3) UNRELEASED; urgency=medium +seergdb (2.4beta) UNRELEASED; urgency=medium - * Release Seer version 2.3 + * Release Seer version 2.4beta -- Ernie Pasveer Sun, 11 Nov 2023 22:18:38 +0200 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6459e611..4b6fe293 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.1.0) -project(seergdb VERSION 2.3 LANGUAGES CXX) +project(seergdb VERSION 2.4.0 LANGUAGES CXX) set(PROJECT_NAME seergdb) diff --git a/src/SeerDebugDialog.cpp b/src/SeerDebugDialog.cpp index 2b934961..f98c934a 100644 --- a/src/SeerDebugDialog.cpp +++ b/src/SeerDebugDialog.cpp @@ -21,6 +21,8 @@ SeerDebugDialog::SeerDebugDialog (QWidget* parent) : QDialog(parent) { // Set up the UI. setupUi(this); + buttonBox->button(QDialogButtonBox::Ok)->setText("Launch"); + // Setup the widgets setExecutableName(""); setExecutableSymbolName(""); @@ -158,9 +160,13 @@ void SeerDebugDialog::setBreakpointMode (const QString& mode) { }else if (mode == "infunction") { breakpointInFunctionRadioButton->setChecked(true); return; + }else if (mode == "insource") { + breakpointAtSourceRadioButton->setChecked(true); + return; } - noBreakpointRadioButton->setChecked(true); + // Default of "inmain". + breakpointInMainRadioButton->setChecked(true); } QString SeerDebugDialog::breakpointMode () const { @@ -171,19 +177,39 @@ QString SeerDebugDialog::breakpointMode () const { return "inmain"; }else if (breakpointInFunctionRadioButton->isChecked()) { return "infunction"; + }else if (breakpointAtSourceRadioButton->isChecked()) { + return "insource"; } - return "none"; + return "inmain"; } void SeerDebugDialog::setBreakpointFunctionName (const QString& nameoraddress) { + breakpointInFunctionLineEdit->setText(nameoraddress); + + if (nameoraddress != "") { + breakpointInFunctionRadioButton->setChecked(true); + } } QString SeerDebugDialog::breakpointFunctionName () const { return breakpointInFunctionLineEdit->text(); } +void SeerDebugDialog::setBreakpointSourceName (const QString& sourceFilenameAndLineno) { + + breakpointAtSourceLineEdit->setText(sourceFilenameAndLineno); + + if (sourceFilenameAndLineno != "") { + breakpointAtSourceRadioButton->setChecked(true); + } +} + +QString SeerDebugDialog::breakpointSourceName () const { + return breakpointAtSourceLineEdit->text(); +} + void SeerDebugDialog::setShowAssemblyTab (bool flag) { showAsseblyTabCheckBox->setChecked(flag); } diff --git a/src/SeerDebugDialog.h b/src/SeerDebugDialog.h index f7eb9344..6c1fe59d 100644 --- a/src/SeerDebugDialog.h +++ b/src/SeerDebugDialog.h @@ -34,6 +34,8 @@ class SeerDebugDialog : public QDialog, protected Ui::SeerDebugDialogForm { QString breakpointMode () const; void setBreakpointFunctionName (const QString& nameoraddress); QString breakpointFunctionName () const; + void setBreakpointSourceName (const QString& sourceFilenameAndLineno); + QString breakpointSourceName () const; void setShowAssemblyTab (bool flag); bool showAssemblyTab () const; void setRandomizeStartAddress (bool flag); diff --git a/src/SeerDebugDialog.ui b/src/SeerDebugDialog.ui index eef9b286..1819d5c7 100644 --- a/src/SeerDebugDialog.ui +++ b/src/SeerDebugDialog.ui @@ -14,52 +14,6 @@ Select Executable to Debug - - - - - - - Working Directory - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - The working directory path to tell GDB. Default current directory. - - - The working directory path to tell GDB. Default current directory. - - - true - - - - - - - Open a dialog to select a path. - - - - - - - :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg - - - - - - - - @@ -118,16 +72,6 @@ - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - @@ -186,6 +130,52 @@ + + + + + + + Working Directory + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + The working directory path to tell GDB. Default current directory. + + + The working directory path to tell GDB. Default current directory. + + + true + + + + + + + Open a dialog to select a path. + + + + + + + :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg + + + + + + + + @@ -197,8 +187,38 @@ Launch Method - - + + + + + + + + 0 + 40 + + + + + + + + + + + + 0 + 40 + + + + + + + + + + @@ -207,7 +227,7 @@ - 3 + 0 @@ -219,7 +239,45 @@ Run - + + + + + + + Run and debug an executable. + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Help for Run launch method. + + + ... + + + + :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg + + + + + @@ -290,138 +348,142 @@ - - + + - + - Show Assembly tab at startup. + Set a breakpoint in "main". - Show Assembly tab + Break in "main" + + breakpointButtonGroup + - - + + - Allow other threads to continue if any thread reaches a breakpoint. + Set a breakpoint in a function or at an address. - Non-stop mode + Break in + + breakpointButtonGroup + - - + + - Randomize the process start address. + The breakpoint function or address. - Randomize start address + + + + _function or 0xaddress + + + true - - - - - - + + - No initial breakpoint. + Set a breakpoint at a line number in a source file. - No breakpoint - - - true + Break at breakpointButtonGroup - - + + - Set a breakpoint in "main". + The breakpoint using filename and lineno. - Break in "main" + + + + sourcefile.cpp:line + + + true - - breakpointButtonGroup - - - + + - Set a breakpoint in a function or at an address. + No initial breakpoint. - Break in + No breakpoint + + + true breakpointButtonGroup + + + + - + - The breakpoint function or address. + Show Assembly tab at startup. - + Show Assembly tab - - _function or 0xaddress + + + + + + Allow other threads to continue if any thread reaches a breakpoint. - - true + + Non-stop mode - - - - - + + + Randomize the process start address. + - Run and debug an executable. + Randomize start address - + Qt::Horizontal - 40 + 258 20 - - - - Help for Run launch method. - - - ... - - - - :/seer/resources/RelaxLightIcons/help-about.svg:/seer/resources/RelaxLightIcons/help-about.svg - - - @@ -471,21 +533,12 @@ - - - - Qt::Horizontal - - - QSizePolicy::Preferred - - - - 248 - 24 - + + + + Process PID - + @@ -495,6 +548,12 @@ 0 + + + 200 + 16777215 + + The process pid. @@ -509,14 +568,33 @@ - - + + + + Open a dialog to select a pid on the local system. + - Process PID + ... - + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 468 + 24 + + + + + Qt::Vertical @@ -529,16 +607,6 @@ - - - - Open a dialog to select a pid on the local system. - - - ... - - - @@ -884,35 +952,19 @@ - - - - - 0 - 40 - - - - - - - - - - - - 0 - 40 - - - - - - - + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + executableNameGroupBox buttonBox @@ -920,6 +972,43 @@ executableWorkingDirectoryGroupBox launchMethodGroupBox + + executableNameLineEdit + executableNameToolButton + executableSymbolNameLineEdit + executableSymbolNameToolButton + executableWorkingDirectoryLineEdit + executableWorkingDirectoryToolButton + runModeTabWidget + helpRunToolButton + runProgramArgumentsLineEdit + loadBreakpointsFilenameLineEdit + loadBreakpointsFilenameToolButton + breakpointInMainRadioButton + breakpointInFunctionRadioButton + breakpointInFunctionLineEdit + breakpointAtSourceRadioButton + breakpointAtSourceLineEdit + noBreakpointRadioButton + showAsseblyTabCheckBox + nonStopModeCheckBox + randomizeStartAddressCheckBox + preCommandsPlainTextEdit + postCommandsPlainTextEdit + helpAttachToolButton + attachProgramPidLineEdit + attachProgramPidToolButton + helpConnectToolButton + connectProgramHostPortLineEdit + helpRRToolButton + rrTraceDirectoryLineEdit + rrLoadTraceDirectoryToolButton + rrLoadBreakpointsFilenameLineEdit + rrLoadBreakpointsFilenameToolButton + helpCorefileToolButton + loadCoreFilenameLineEdit + loadCoreFilenameToolButton + diff --git a/src/SeerGdbWidget.cpp b/src/SeerGdbWidget.cpp index 62468c0c..f0c45368 100644 --- a/src/SeerGdbWidget.cpp +++ b/src/SeerGdbWidget.cpp @@ -435,6 +435,14 @@ const QString& SeerGdbWidget::executableBreakpointFunctionName () const { return _executableBreakpointFunctionName; } +void SeerGdbWidget::setExecutableBreakpointSourceName (const QString& sourceFilenameAndLineno) { + _executableBreakpointSourceName = sourceFilenameAndLineno; +} + +const QString& SeerGdbWidget::executableBreakpointSourceName () const { + return _executableBreakpointSourceName; +} + void SeerGdbWidget::setExecutablePid (int pid) { _executablePid = pid; } @@ -895,7 +903,7 @@ void SeerGdbWidget::handleGdbExit () { void SeerGdbWidget::handleGdbRunExecutable (const QString& breakMode) { - qCDebug(LC) << "Starting 'gdb run/start'."; + qCDebug(LC) << "Starting 'gdb run/start':" << breakMode; QApplication::setOverrideCursor(Qt::BusyCursor); @@ -999,16 +1007,20 @@ void SeerGdbWidget::handleGdbRunExecutable (const QString& breakMode) { // Set the program's arguments before running. handleGdbExecutableArguments(); - // Set a temporary breakpoint for start up. + // Set a breakpoint for start up if "infunction" or "insource". if (_executableBreakMode == "infunction" && executableBreakpointFunctionName() != "") { if (executableBreakpointFunctionName().contains("^0[xX][0-9a-fA-F]+")) { - handleGdbBreakpointInsert("-t *" + executableBreakpointFunctionName()); + handleGdbBreakpointInsert("*" + executableBreakpointFunctionName()); }else{ - handleGdbBreakpointInsert("-t -f --function " + executableBreakpointFunctionName()); + handleGdbBreakpointInsert("-f --function " + executableBreakpointFunctionName()); } } + if (_executableBreakMode == "insource" && executableBreakpointSourceName() != "") { + handleGdbBreakpointInsert(executableBreakpointSourceName()); + } + // Run any 'post' commands after program is loaded. handleGdbExecutablePostCommands(); @@ -3060,8 +3072,8 @@ bool SeerGdbWidget::startGdb () { QString expandedcommand = Seer::expandEnv(rawcommand, &ok); - qDebug() << "Raw command : " << rawcommand; - qDebug() << "Expanded command: " << expandedcommand; + //qDebug() << "Raw command : " << rawcommand; + //qDebug() << "Expanded command: " << expandedcommand; if (ok == false) { @@ -3079,8 +3091,8 @@ bool SeerGdbWidget::startGdb () { QString expandedarguments = Seer::expandEnv(rawarguments, &ok); - qDebug() << "Raw arguments : " << rawarguments; - qDebug() << "Expanded arguments: " << expandedarguments; + //qDebug() << "Raw arguments : " << rawarguments; + //qDebug() << "Expanded arguments: " << expandedarguments; if (ok == false) { @@ -3104,7 +3116,7 @@ bool SeerGdbWidget::startGdb () { // Start the gdb process. _gdbProcess->start(); - qDebug() << _gdbProcess->state(); + //qDebug() << _gdbProcess->state(); return true; } @@ -3135,8 +3147,8 @@ bool SeerGdbWidget::startGdbRR () { QStringList args = arguments.split(' ', Qt::SkipEmptyParts); - qDebug() << "Expanded command: " << command; - qDebug() << "Expanded arguments: " << arguments; + //qDebug() << "Expanded command: " << command; + //qDebug() << "Expanded arguments: " << arguments; // Give the gdb process the program and the argument list. _gdbProcess->setProgram(command); @@ -3151,7 +3163,7 @@ bool SeerGdbWidget::startGdbRR () { // Start the gdb process. _gdbProcess->start(); - qDebug() << _gdbProcess->state(); + //qDebug() << _gdbProcess->state(); return true; } diff --git a/src/SeerGdbWidget.h b/src/SeerGdbWidget.h index 315facc9..1b2b15f0 100644 --- a/src/SeerGdbWidget.h +++ b/src/SeerGdbWidget.h @@ -48,6 +48,9 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm { void setExecutableBreakpointFunctionName (const QString& nameoraddress); const QString& executableBreakpointFunctionName () const; + void setExecutableBreakpointSourceName (const QString& sourceFilenameAndLineno); + const QString& executableBreakpointSourceName () const; + void setExecutablePid (int pid); int executablePid () const; @@ -393,6 +396,7 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm { QString _executableWorkingDirectory; QString _executableBreakpointsFilename; QString _executableBreakpointFunctionName; + QString _executableBreakpointSourceName; int _executablePid; QString _executableConnectHostPort; QString _executableRRTraceDirectory; diff --git a/src/SeerMainWindow.cpp b/src/SeerMainWindow.cpp index 75b63e75..c021d8a0 100644 --- a/src/SeerMainWindow.cpp +++ b/src/SeerMainWindow.cpp @@ -284,6 +284,14 @@ const QString& SeerMainWindow::executableBreakpointFunctionName () const { return gdbWidget->executableBreakpointFunctionName(); } +void SeerMainWindow::setExecutableBreakpointSourceName (const QString& sourceFilenameAndLineno) { + gdbWidget->setExecutableBreakpointSourceName(sourceFilenameAndLineno); +} + +const QString& SeerMainWindow::executableBreakpointSourceName () const { + return gdbWidget->executableBreakpointSourceName(); +} + void SeerMainWindow::setExecutableShowAssemblyTab (bool flag) { gdbWidget->setAssemblyShowAssemblyTabOnStartup(flag); } @@ -467,8 +475,11 @@ void SeerMainWindow::handleFileDebug () { dlg.setExecutableSymbolName(executableSymbolName()); dlg.setExecutableWorkingDirectory(executableWorkingDirectory()); dlg.setExecutableArguments(executableArguments()); + dlg.setLaunchMode(executableLaunchMode()); + dlg.setBreakpointMode(executableBreakMode()); dlg.setBreakpointsFilename(executableBreakpointsFilename()); dlg.setBreakpointFunctionName(executableBreakpointFunctionName()); + dlg.setBreakpointSourceName(executableBreakpointSourceName()); dlg.setShowAssemblyTab(executableShowAssemblyTab()); dlg.setRandomizeStartAddress(executableRandomizeStartAddress()); dlg.setNonStopMode(executableNonStopMode()); @@ -476,8 +487,6 @@ void SeerMainWindow::handleFileDebug () { dlg.setConnectHostPort(executableConnectHostPort()); dlg.setRRTraceDirectory(executableRRTraceDirectory()); dlg.setCoreFilename(executableCoreFilename()); - dlg.setLaunchMode(executableLaunchMode()); - dlg.setBreakpointMode(executableBreakMode()); dlg.setPreGdbCommands(executablePreGdbCommands()); dlg.setPostGdbCommands(executablePostGdbCommands()); dlg.setProjectFilename(projectFilename()); @@ -503,6 +512,7 @@ void SeerMainWindow::handleFileDebug () { setExecutableArguments(dlg.executableArguments()); setExecutableBreakpointsFilename(dlg.breakpointsFilename()); setExecutableBreakpointFunctionName(dlg.breakpointFunctionName()); + setExecutableBreakpointSourceName(dlg.breakpointSourceName()); setExecutableShowAssemblyTab(dlg.showAssemblyTab()); setExecutableRandomizeStartAddress(dlg.randomizeStartAddress()); setExecutableNonStopMode(dlg.nonStopMode()); @@ -742,14 +752,21 @@ void SeerMainWindow::handleStartExecutable () { }else{ QString breakfunction = gdbWidget->executableBreakpointFunctionName(); + QString breaksource = gdbWidget->executableBreakpointSourceName(); - // No break function, attempt to stop in "main". - if (breakfunction == "") { - gdbWidget->handleGdbRunExecutable("inmain"); + // Stop in function? + if (breakfunction != "") { - // Otherwise, attempt to stop in the function. - }else{ gdbWidget->handleGdbRunExecutable("infunction"); + + // Stop at source:line? + }else if (breaksource != "") { + + gdbWidget->handleGdbRunExecutable("insource"); + + // Otherwise, attempt to stop in "main". + }else{ + gdbWidget->handleGdbRunExecutable("inmain"); } } } diff --git a/src/SeerMainWindow.h b/src/SeerMainWindow.h index 2c67c747..dec27e06 100644 --- a/src/SeerMainWindow.h +++ b/src/SeerMainWindow.h @@ -33,6 +33,8 @@ class SeerMainWindow : public QMainWindow, protected Ui::SeerMainWindowForm { const QString& executableBreakpointsFilename () const; void setExecutableBreakpointFunctionName (const QString& nameoraddress); const QString& executableBreakpointFunctionName () const; + void setExecutableBreakpointSourceName (const QString& sourceFilenameAndLineno); + const QString& executableBreakpointSourceName () const; void setExecutableShowAssemblyTab (bool flag); bool executableShowAssemblyTab () const; void setExecutableRandomizeStartAddress (bool flag); diff --git a/src/SeerUtl.cpp b/src/SeerUtl.cpp index 046d148e..04993e89 100644 --- a/src/SeerUtl.cpp +++ b/src/SeerUtl.cpp @@ -9,7 +9,7 @@ // Increment this with every release on GitHub. // See scripts/change_versionnumber // -#define SEER_VERSION "2.3" +#define SEER_VERSION "2.4beta" namespace Seer { diff --git a/src/resources/help/RunDebugMode.md b/src/resources/help/RunDebugMode.md index 27cd5b1c..1b2ad63f 100644 --- a/src/resources/help/RunDebugMode.md +++ b/src/resources/help/RunDebugMode.md @@ -15,11 +15,18 @@ In this mode, Seer needs: ### What can you do? There are a couple gdb settings that you can choose from when running the executable. -The main one, though, is the initial breakpoint, which there are three ways: +The main one, though, is the initial breakpoint, which there are four ways: -* No initial breakpoint. The program is started and executes without any breakpoints unless they are specified in the optional breakpoint file. * Break in 'main'. The program is started and breaks in the program's main function. + The definition of 'main' is language dependant. Seer/gdb will stop in the initial + function for that language. * Break in 'function'. The program is started and breaks in a named function or at an address. +* Break at 'source'. The program is started and breaks at a line number of a source file. + eg: myprog.cpp:36 +* No initial breakpoint. The program is started and executes without any breakpoints unless + they are specified in the optional breakpoint file. The program will run til the end or when it + encounters a signal or breakpoint. No source files will be loaded until a signal or breakpoint + is encountered. From this point, you can debug the process as normal (stepping and setting breakpoints, etc...) diff --git a/src/resources/help/seergdb.hlp b/src/resources/help/seergdb.hlp index 2d7bce4d..d34a488a 100644 --- a/src/resources/help/seergdb.hlp +++ b/src/resources/help/seergdb.hlp @@ -45,6 +45,8 @@ Misc Options: --sym, --symbol-file Load symbols from a separate file than the executable. --bl, --break-load Load a previously saved breakpoints file. For 'run', 'start', or 'rr'. --bf, --break-function Set a breakpoint in a function/address. For 'run' or 'start'. + --bs, --break-source Set a breakpoint in a source file and line number. For 'run' or 'start'. + eg: --bs myprog.cpp:30 --sat, --show-assembly-tab Show the Assembly Tab on Seer startup. For 'run' or 'start'. --sar, --start-address-randomize Randomize the program's starting address. For 'run' or 'start'. --nsm, --non-stop-mode Continue to run other threads at breakpoints. For 'run' or 'start'. diff --git a/src/seergdb.cpp b/src/seergdb.cpp index aa3a2b14..bde5c00d 100644 --- a/src/seergdb.cpp +++ b/src/seergdb.cpp @@ -96,6 +96,9 @@ int main (int argc, char* argv[]) { QCommandLineOption breakfunctionOption(QStringList() << "bf" << "break-function", "", "breakpointfunction"); parser.addOption(breakfunctionOption); + QCommandLineOption breaksourceOption(QStringList() << "bs" << "break-source", "", "breakpointsource"); + parser.addOption(breaksourceOption); + QCommandLineOption showAssemblyTabOption(QStringList() << "sat" << "show-assembly-tab"); parser.addOption(showAssemblyTabOption); @@ -155,6 +158,7 @@ int main (int argc, char* argv[]) { QString executableSymbolFilename; QString executableBreakpointsFilename; QString executableBreakpointFunctionName; + QString executableBreakpointSourceFilenameAndLineno; QString executableShowAssemblyTab; QString executableStartAddressRandomize; QString executableNonStopMode; @@ -186,6 +190,11 @@ int main (int argc, char* argv[]) { breakMode = "infunction"; } + if (parser.isSet(breaksourceOption)) { + executableBreakpointSourceFilenameAndLineno = parser.value(breaksourceOption); + breakMode = "insource"; + } + if (parser.isSet(showAssemblyTabOption)) { executableShowAssemblyTab = parser.value(showAssemblyTabOption); } @@ -268,6 +277,10 @@ int main (int argc, char* argv[]) { seer.setExecutableBreakpointFunctionName(executableBreakpointFunctionName); } + if (executableBreakpointSourceFilenameAndLineno != "") { + seer.setExecutableBreakpointSourceName(executableBreakpointSourceFilenameAndLineno); + } + if (executableShowAssemblyTab != "") { if (executableShowAssemblyTab == "yes") { seer.setExecutableShowAssemblyTab(true);