diff --git a/CHANGELOG.md b/CHANGELOG.md index 55fa335..6e60a7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * Re-added the original struct visualizers as "Basic Struct Visualizer". The advanced version is called "Struct Visualizer". * Moved selection of visualizers into a sub menu called "Visualizers" on the menu bar. +* Added alternate file to load symbols from (instead of the debugee executable. ## [1.13] - 2022-12-02 diff --git a/README.md b/README.md index 546fae3..a4a4bbc 100644 --- a/README.md +++ b/README.md @@ -224,6 +224,11 @@ with no start address randomization. % seergdb --start --sar yes myprog arg1 arg2 # Debug myprog with its arguments. # The program's start address is randomized. +The program's symbols can be taken from a separated file instead of the executable. + + % seergdb --sym myprog.db myprog arg1 arg2 # Debug myprog with its arguments. + # Take the symbols from myprog.dbg. + See "-h" for the full Seer help. % seergdb -h diff --git a/images/opendialog.png b/images/opendialog.png index 4942e26..29489b4 100644 Binary files a/images/opendialog.png and b/images/opendialog.png differ diff --git a/src/SeerDebugDialog.cpp b/src/SeerDebugDialog.cpp index a9830b8..14197c3 100644 --- a/src/SeerDebugDialog.cpp +++ b/src/SeerDebugDialog.cpp @@ -20,6 +20,7 @@ SeerDebugDialog::SeerDebugDialog (QWidget* parent) : QDialog(parent) { // Setup the widgets setExecutableName(""); + setExecutableSymbolName(""); setExecutableArguments(""); setBreakpointsFilename(""); setExecutableWorkingDirectory(QDir::currentPath()); @@ -34,6 +35,7 @@ SeerDebugDialog::SeerDebugDialog (QWidget* parent) : QDialog(parent) { // Connect things. QObject::connect(executableNameToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleExecutableNameToolButton); + QObject::connect(executableSymbolNameToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleExecutableSymbolNameToolButton); QObject::connect(executableWorkingDirectoryToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleExecutableWorkingDirectoryToolButton); QObject::connect(loadBreakpointsFilenameToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleLoadBreakpointsFilenameToolButton); QObject::connect(loadCoreFilenameToolButton, &QToolButton::clicked, this, &SeerDebugDialog::handleLoadCoreFilenameToolButton); @@ -61,6 +63,14 @@ QString SeerDebugDialog::executableName () const { return executableNameLineEdit->text(); } +void SeerDebugDialog::setExecutableSymbolName (const QString& executableSymbolName) { + executableSymbolNameLineEdit->setText(executableSymbolName); +} + +QString SeerDebugDialog::executableSymbolName () const { + return executableSymbolNameLineEdit->text(); +} + void SeerDebugDialog::setExecutableWorkingDirectory (const QString& executableWorkingDirectory) { executableWorkingDirectoryLineEdit->setText(executableWorkingDirectory); } @@ -271,6 +281,15 @@ void SeerDebugDialog::handleExecutableNameToolButton () { } } +void SeerDebugDialog::handleExecutableSymbolNameToolButton () { + + QString name = QFileDialog::getOpenFileName(this, "Select a Symbol File for the executable.", executableSymbolName(), "", nullptr, QFileDialog::DontUseNativeDialog); + + if (name != "") { + setExecutableSymbolName(name); + } +} + void SeerDebugDialog::handleExecutableWorkingDirectoryToolButton () { QString name = QFileDialog::getExistingDirectory(this, "Select a Working Directory to run in.", executableWorkingDirectory(), QFileDialog::ShowDirsOnly|QFileDialog::DontUseNativeDialog); diff --git a/src/SeerDebugDialog.h b/src/SeerDebugDialog.h index f8d6e4a..f3496e0 100644 --- a/src/SeerDebugDialog.h +++ b/src/SeerDebugDialog.h @@ -18,6 +18,9 @@ class SeerDebugDialog : public QDialog, protected Ui::SeerDebugDialogForm { void setExecutableName (const QString& executableName); QString executableName () const; + void setExecutableSymbolName (const QString& executableSymbolName); + QString executableSymbolName () const; + void setExecutableWorkingDirectory (const QString& executableWorkingDirectory); QString executableWorkingDirectory () const; @@ -59,6 +62,7 @@ class SeerDebugDialog : public QDialog, protected Ui::SeerDebugDialogForm { protected slots: void handleExecutableNameToolButton (); + void handleExecutableSymbolNameToolButton (); void handleExecutableWorkingDirectoryToolButton (); void handleLoadBreakpointsFilenameToolButton (); void handleBreakpointInFunctionLineEdit (); diff --git a/src/SeerDebugDialog.ui b/src/SeerDebugDialog.ui index 0118c9f..8de2d2c 100644 --- a/src/SeerDebugDialog.ui +++ b/src/SeerDebugDialog.ui @@ -7,24 +7,17 @@ 0 0 550 - 777 + 857 Select Executable to Debug - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - + + + 9 + + Executable Name @@ -36,6 +29,9 @@ false + + 9 + @@ -47,6 +43,9 @@ The path and name of an executable to debug. + + The path and name of an executable to debug. + true @@ -75,7 +74,61 @@ - + + + + Symbol File Name + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + false + + + + + + + 0 + 0 + + + + Optional path and name of a symbol file for the executable. + + + Optional path and name of a symbol file for the executable. + + + true + + + + + + + + 0 + 0 + + + + Open a dialog to select the symbol file for the executable. + + + + + + + :/seer/resources/RelaxLightIcons/document-open.svg:/seer/resources/RelaxLightIcons/document-open.svg + + + + + + + @@ -104,7 +157,10 @@ - The working directory path to tell GDB. + The working directory path to tell GDB. Default current directory. + + + The working directory path to tell GDB. Default current directory. true @@ -114,7 +170,7 @@ - + @@ -563,11 +619,22 @@ + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + launchMethodGroupBox executableNameGroupBox executableWorkingDirectoryGroupBox buttonBox + executableSymbolNameGroupBox diff --git a/src/SeerGdbWidget.cpp b/src/SeerGdbWidget.cpp index f91844e..a9f1fdb 100644 --- a/src/SeerGdbWidget.cpp +++ b/src/SeerGdbWidget.cpp @@ -346,6 +346,17 @@ const QString& SeerGdbWidget::executableName () const { return _executableName; } +void SeerGdbWidget::setExecutableSymbolName (const QString& executableSymbolName) { + + _executableSymbolName = executableSymbolName; + + setNewExecutableFlag(true); +} + +const QString& SeerGdbWidget::executableSymbolName () const { + return _executableSymbolName; +} + void SeerGdbWidget::setNewExecutableFlag (bool flag) { _newExecutableFlag = flag; @@ -1414,7 +1425,22 @@ void SeerGdbWidget::handleGdbExecutableName () { return; } - handleGdbCommand(QString("-file-exec-and-symbols \"") + executableName() + "\""); + //qDebug() << executableName(); + //qDebug() << executableSymbolName(); + + // executableName() is expected to be non-blank. + + // No symbol file? Symbols are expected in the executable. + if (executableSymbolName() == "") { + + handleGdbCommand(QString("-file-exec-and-symbols \"") + executableName() + "\""); + + // A symbol file? Open the executable and symbol files separately. + }else{ + + handleGdbCommand(QString("-file-exec-file \"") + executableName() + "\""); + handleGdbCommand(QString("-file-symbol-file \"") + executableSymbolName() + "\""); + } } void SeerGdbWidget::handleGdbExecutableArguments () { diff --git a/src/SeerGdbWidget.h b/src/SeerGdbWidget.h index 4372e71..5f4a420 100644 --- a/src/SeerGdbWidget.h +++ b/src/SeerGdbWidget.h @@ -29,6 +29,9 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm { void setExecutableName (const QString& executableName); const QString& executableName () const; + void setExecutableSymbolName (const QString& executableSymbolName); + const QString& executableSymbolName () const; + void setNewExecutableFlag (bool flag); bool newExecutableFlag () const; @@ -332,6 +335,7 @@ class SeerGdbWidget : public QWidget, protected Ui::SeerGdbWidgetForm { QString _assemblyRegisterFormat; QString _executableName; + QString _executableSymbolName; QString _executableArguments; QString _executableWorkingDirectory; QString _executableBreakpointsFilename; diff --git a/src/SeerMainWindow.cpp b/src/SeerMainWindow.cpp index a3b4d5e..46ff61a 100644 --- a/src/SeerMainWindow.cpp +++ b/src/SeerMainWindow.cpp @@ -209,6 +209,14 @@ const QString& SeerMainWindow::executableName () const { return gdbWidget->executableName(); } +void SeerMainWindow::setExecutableSymbolName (const QString& executableSymbolName) { + gdbWidget->setExecutableSymbolName(executableSymbolName); +} + +const QString& SeerMainWindow::executableSymbolName () const { + return gdbWidget->executableSymbolName(); +} + void SeerMainWindow::setExecutableArguments (const QString& executableArguments) { gdbWidget->setExecutableArguments(executableArguments); @@ -380,6 +388,7 @@ void SeerMainWindow::handleFileDebug () { SeerDebugDialog dlg(this); dlg.setExecutableName(executableName()); + dlg.setExecutableSymbolName(executableSymbolName()); dlg.setExecutableWorkingDirectory(executableWorkingDirectory()); dlg.setExecutableArguments(executableArguments()); dlg.setBreakpointsFilename(executableBreakpointsFilename()); @@ -409,6 +418,7 @@ void SeerMainWindow::handleFileDebug () { } setExecutableName(dlg.executableName()); + setExecutableSymbolName(dlg.executableSymbolName()); setExecutableWorkingDirectory(dlg.executableWorkingDirectory()); setExecutableArguments(dlg.executableArguments()); setExecutableBreakpointsFilename(dlg.breakpointsFilename()); diff --git a/src/SeerMainWindow.h b/src/SeerMainWindow.h index 62160c5..e4b01ff 100644 --- a/src/SeerMainWindow.h +++ b/src/SeerMainWindow.h @@ -22,6 +22,8 @@ class SeerMainWindow : public QMainWindow, protected Ui::SeerMainWindowForm { void setExecutableName (const QString& executableName); const QString& executableName () const; + void setExecutableSymbolName (const QString& executableSymbolName); + const QString& executableSymbolName () const; void setExecutableArguments (const QString& executableArguments); void setExecutableArguments (const QStringList& executableArguments); const QString& executableArguments () const; diff --git a/src/seergdb.cpp b/src/seergdb.cpp index a2c0942..2ba5f75 100644 --- a/src/seergdb.cpp +++ b/src/seergdb.cpp @@ -46,6 +46,9 @@ int main (int argc, char* argv[]) { QCommandLineOption startOption(QStringList()<<"s"<<"start", QCoreApplication::translate("main", "Load the executable, break in \"main\", and run it.")); parser.addOption(startOption); + QCommandLineOption symbolfileOption(QStringList()<<"sym"<<"symbol-file", QCoreApplication::translate("main", "Load symbols from a separate file than the executable."), "symbolfilename"); + parser.addOption(symbolfileOption); + QCommandLineOption breakfileOption(QStringList()<<"bl"<<"break-load", QCoreApplication::translate("main", "Load a previously saved breakpoints file. For --run or --start"), "filename"); parser.addOption(breakfileOption); @@ -108,6 +111,7 @@ int main (int argc, char* argv[]) { QString breakMode = "none"; int executablePid = -1; QString executableHostPort; + QString executableSymbolFilename; QString executableBreakpointsFilename; QString executableBreakpointFunctionName; QString executableShowAssemblyTab; @@ -125,6 +129,10 @@ int main (int argc, char* argv[]) { breakMode = "inmain"; } + if (parser.isSet(symbolfileOption)) { + executableSymbolFilename = parser.value(symbolfileOption); + } + if (parser.isSet(breakfileOption)) { executableBreakpointsFilename = parser.value(breakfileOption); } @@ -178,6 +186,7 @@ int main (int argc, char* argv[]) { seer.setWindowIcon(QIcon(":/seer/resources/seergdb_64x64.png")); seer.setExecutableName(executableName); + seer.setExecutableSymbolName(executableSymbolFilename); seer.setExecutableArguments(positionalArguments); if (executableBreakpointsFilename != "") { diff --git a/tests/hellosymbolfile/.gitignore b/tests/hellosymbolfile/.gitignore new file mode 100644 index 0000000..ce95dd3 --- /dev/null +++ b/tests/hellosymbolfile/.gitignore @@ -0,0 +1,2 @@ +hellosymbolfile +hellosymbolfile.dbg diff --git a/tests/hellosymbolfile/Makefile b/tests/hellosymbolfile/Makefile new file mode 100644 index 0000000..4355646 --- /dev/null +++ b/tests/hellosymbolfile/Makefile @@ -0,0 +1,12 @@ +.PHONY: all +all: hellosymbolfile + +hellosymbolfile: hellosymbolfile.cpp function1.cpp + g++ -g -o hellosymbolfile hellosymbolfile.cpp function1.cpp + objcopy --only-keep-debug hellosymbolfile hellosymbolfile.dbg + strip --strip-debug --strip-unneeded hellosymbolfile + +.PHONY: clean +clean: + rm -f hellosymbolfile hellosymbolfile.dbg hellosymbolfile.o function1.o + diff --git a/tests/hellosymbolfile/README b/tests/hellosymbolfile/README new file mode 100644 index 0000000..05fcf96 --- /dev/null +++ b/tests/hellosymbolfile/README @@ -0,0 +1 @@ +Simple Hello,World program to test a separate executable and symbol file. diff --git a/tests/hellosymbolfile/function1.cpp b/tests/hellosymbolfile/function1.cpp new file mode 100644 index 0000000..61db1f8 --- /dev/null +++ b/tests/hellosymbolfile/function1.cpp @@ -0,0 +1,15 @@ +#include "function1.h" +#include +#include + +void function1 (const std::string& text) { + + int i = 42; + + sleep(2); // Simulate doing work. + + std::cout << text << i << std::endl; + + sleep(3); // Simulate doing work. +} + diff --git a/tests/hellosymbolfile/function1.h b/tests/hellosymbolfile/function1.h new file mode 100644 index 0000000..8f24a9b --- /dev/null +++ b/tests/hellosymbolfile/function1.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +void function1 (const std::string& text); + diff --git a/tests/hellosymbolfile/hellosymbolfile.cpp b/tests/hellosymbolfile/hellosymbolfile.cpp new file mode 100644 index 0000000..27721f0 --- /dev/null +++ b/tests/hellosymbolfile/hellosymbolfile.cpp @@ -0,0 +1,26 @@ +#include +#include + +void function1 (const std::string& message); + +int main (int argc, char** argv) { + + int j = 0; + + for (int i=0; i