mirror of
https://github.com/epasveer/seer.git
synced 2026-08-30 00:50:42 +08:00
1043 lines
46 KiB
C++
1043 lines
46 KiB
C++
#include "SeerGdbWidget.h"
|
|
#include "SeerLogWidget.h"
|
|
#include "SeerTildeEqualAmpersandLogWidget.h"
|
|
#include "SeerCaretAsteriskLogWidget.h"
|
|
#include "SeerConsoleWidget.h"
|
|
#include "SeerBreakpointsBrowserWidget.h"
|
|
#include "SeerWatchpointsBrowserWidget.h"
|
|
#include "SeerMemoryVisualizerWidget.h"
|
|
#include "SeerUtl.h"
|
|
#include <QtGui/QFont>
|
|
#include <QtWidgets/QMessageBox>
|
|
#include <QtCore/QDebug>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <termios.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
SeerGdbWidget::SeerGdbWidget (QWidget* parent) : QWidget(parent) {
|
|
|
|
_executableName = "";
|
|
_executableArguments = "";
|
|
_executableWorkingDirectory = "";
|
|
_executablePid = -1;
|
|
_gdbMonitor = 0;
|
|
_gdbProcess = 0;
|
|
_consoleWidget = 0;
|
|
|
|
setupUi(this);
|
|
|
|
// Setup the widgets
|
|
QFont font;
|
|
font.setFamily("monospace [Consolas]");
|
|
font.setFixedPitch(true);
|
|
font.setStyleHint(QFont::TypeWriter);
|
|
|
|
SeerBreakpointsBrowserWidget* breakpointsBrowserWidget = new SeerBreakpointsBrowserWidget(this);
|
|
SeerWatchpointsBrowserWidget* watchpointsBrowserWidget = new SeerWatchpointsBrowserWidget(this);
|
|
SeerTildeEqualAmpersandLogWidget* gdbOutputLog = new SeerTildeEqualAmpersandLogWidget(this);
|
|
SeerCaretAsteriskLogWidget* seerOutputLog = new SeerCaretAsteriskLogWidget(this);
|
|
|
|
logsTabWidget->addTab(breakpointsBrowserWidget, "Breakpoints");
|
|
logsTabWidget->addTab(watchpointsBrowserWidget, "Watchpoints");
|
|
logsTabWidget->addTab(gdbOutputLog, "GDB output");
|
|
logsTabWidget->addTab(seerOutputLog, "Seer output");
|
|
logsTabWidget->setCurrentIndex(0);
|
|
|
|
manualCommandComboBox->setFont(font);
|
|
manualCommandComboBox->setEditable(true);
|
|
manualCommandComboBox->lineEdit()->setPlaceholderText("Manually enter a gdb/mi command...");
|
|
manualCommandComboBox->lineEdit()->setToolTip("Manually enter a gdb/mi command.");
|
|
manualCommandComboBox->lineEdit()->setClearButtonEnabled(true);
|
|
|
|
// Create the gdb process.
|
|
_gdbProcess = new QProcess(this);
|
|
|
|
// Create the gdb monitor.
|
|
_gdbMonitor = new GdbMonitor(this);
|
|
_gdbMonitor->setProcess(_gdbProcess);
|
|
|
|
// Connect things.
|
|
QObject::connect(manualCommandComboBox->lineEdit(), &QLineEdit::returnPressed, this, &SeerGdbWidget::handleExecute);
|
|
|
|
QObject::connect(_gdbProcess, &QProcess::readyReadStandardOutput, _gdbMonitor, &GdbMonitor::handleReadyReadStandardOutput);
|
|
QObject::connect(_gdbProcess, &QProcess::readyReadStandardError, _gdbMonitor, &GdbMonitor::handleReadyReadStandardError);
|
|
//QObject::connect(_gdbProcess, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), _gdbMonitor, &GdbMonitor::handleFinished); // ??? Do we care about the gdb process ending? For now, terminate Seer.
|
|
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::tildeTextOutput, gdbOutputLog, &SeerTildeEqualAmpersandLogWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::equalTextOutput, gdbOutputLog, &SeerTildeEqualAmpersandLogWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::ampersandTextOutput, gdbOutputLog, &SeerTildeEqualAmpersandLogWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, seerOutputLog, &SeerCaretAsteriskLogWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, seerOutputLog, &SeerCaretAsteriskLogWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, editorManagerWidget, &SeerEditorManagerWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, editorManagerWidget, &SeerEditorManagerWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->sourceBrowserWidget(), &SeerSourceBrowserWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, sourceLibraryManagerWidget->sharedLibraryBrowserWidget(), &SeerSharedLibraryBrowserWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, breakpointsBrowserWidget, &SeerBreakpointsBrowserWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, watchpointsBrowserWidget, &SeerWatchpointsBrowserWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, watchpointsBrowserWidget, &SeerWatchpointsBrowserWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, this, &SeerGdbWidget::handleText);
|
|
|
|
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshBreakpointsList, this, &SeerGdbWidget::handleGdbBreakpointWatchpointList);
|
|
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshStackFrames, this, &SeerGdbWidget::handleGdbStackListFrames);
|
|
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::insertBreakpoint, this, &SeerGdbWidget::handleGdbBreakpointInsert);
|
|
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::deleteBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointDelete);
|
|
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::enableBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointEnable);
|
|
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::disableBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointDisable);
|
|
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::runToLine, this, &SeerGdbWidget::handleGdbRunToLine);
|
|
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::addVariableExpression, this, &SeerGdbWidget::handleGdbDataAddExpression);
|
|
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::refreshVariableValues, this, &SeerGdbWidget::handleGdbDataListValues);
|
|
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::addMemoryVisualize, this, &SeerGdbWidget::handleGdbMemoryAddExpression);
|
|
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression);
|
|
QObject::connect(editorManagerWidget, &SeerEditorManagerWidget::evaluateVariableExpression, variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::handleEvaluateVariableExpression);
|
|
|
|
QObject::connect(sourceLibraryManagerWidget->sourceBrowserWidget(), &SeerSourceBrowserWidget::refreshSourceList, this, &SeerGdbWidget::handleGdbExecutableSources);
|
|
QObject::connect(sourceLibraryManagerWidget->sourceBrowserWidget(), &SeerSourceBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile);
|
|
QObject::connect(sourceLibraryManagerWidget->sharedLibraryBrowserWidget(), &SeerSharedLibraryBrowserWidget::refreshSharedLibraryList, this, &SeerGdbWidget::handleGdbExecutableSharedLibraries);
|
|
|
|
QObject::connect(stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::refreshStackFrames, this, &SeerGdbWidget::handleGdbStackListFrames);
|
|
QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::refreshStackLocals, this, &SeerGdbWidget::handleGdbStackListLocals);
|
|
QObject::connect(stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::selectedFrame, this, &SeerGdbWidget::handleGdbStackSelectFrame);
|
|
QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::refreshStackArguments, this, &SeerGdbWidget::handleGdbStackListArguments);
|
|
QObject::connect(stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile);
|
|
|
|
QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::refreshVariableValues, this, &SeerGdbWidget::handleGdbDataListExpressions);
|
|
QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::refreshVariableNames, this, &SeerGdbWidget::handleGdbDataListValues);
|
|
QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::addVariableExpression, this, &SeerGdbWidget::handleGdbDataAddExpression);
|
|
QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::deleteVariableExpressions, this, &SeerGdbWidget::handleGdbDataDeleteExpressions);
|
|
QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(), &SeerVariableLoggerBrowserWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression);
|
|
|
|
QObject::connect(variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::refreshRegisterNames, this, &SeerGdbWidget::handleGdbRegisterListNames);
|
|
QObject::connect(variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::refreshRegisterValues, this, &SeerGdbWidget::handleGdbRegisterListValues);
|
|
|
|
QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::refreshThreadIds, this, &SeerGdbWidget::handleGdbThreadListIds);
|
|
QObject::connect(threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::selectedThread, this, &SeerGdbWidget::handleGdbThreadSelectId);
|
|
QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::refreshThreadFrames, this, &SeerGdbWidget::handleGdbThreadListFrames);
|
|
QObject::connect(threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile);
|
|
|
|
QObject::connect(breakpointsBrowserWidget, &SeerBreakpointsBrowserWidget::refreshBreakpointsList, this, &SeerGdbWidget::handleGdbBreakpointWatchpointList);
|
|
QObject::connect(breakpointsBrowserWidget, &SeerBreakpointsBrowserWidget::deleteBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointDelete);
|
|
QObject::connect(breakpointsBrowserWidget, &SeerBreakpointsBrowserWidget::enableBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointEnable);
|
|
QObject::connect(breakpointsBrowserWidget, &SeerBreakpointsBrowserWidget::disableBreakpoints, this, &SeerGdbWidget::handleGdbBreakpointDisable);
|
|
QObject::connect(breakpointsBrowserWidget, &SeerBreakpointsBrowserWidget::insertBreakpoint, this, &SeerGdbWidget::handleGdbBreakpointInsert);
|
|
QObject::connect(breakpointsBrowserWidget, &SeerBreakpointsBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile);
|
|
|
|
QObject::connect(watchpointsBrowserWidget, &SeerWatchpointsBrowserWidget::refreshWatchpointsList, this, &SeerGdbWidget::handleGdbBreakpointWatchpointList);
|
|
QObject::connect(watchpointsBrowserWidget, &SeerWatchpointsBrowserWidget::deleteWatchpoints, this, &SeerGdbWidget::handleGdbWatchpointDelete);
|
|
QObject::connect(watchpointsBrowserWidget, &SeerWatchpointsBrowserWidget::enableWatchpoints, this, &SeerGdbWidget::handleGdbWatchpointEnable);
|
|
QObject::connect(watchpointsBrowserWidget, &SeerWatchpointsBrowserWidget::disableWatchpoints, this, &SeerGdbWidget::handleGdbWatchpointDisable);
|
|
QObject::connect(watchpointsBrowserWidget, &SeerWatchpointsBrowserWidget::insertWatchpoint, this, &SeerGdbWidget::handleGdbWatchpointInsert);
|
|
QObject::connect(watchpointsBrowserWidget, &SeerWatchpointsBrowserWidget::selectedFile, editorManagerWidget, &SeerEditorManagerWidget::handleOpenFile);
|
|
|
|
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget->stackFramesBrowserWidget(), &SeerStackFramesBrowserWidget::handleStoppingPointReached);
|
|
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget->stackLocalsBrowserWidget(), &SeerStackLocalsBrowserWidget::handleStoppingPointReached);
|
|
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, stackManagerWidget->stackArgumentsBrowserWidget(), &SeerStackArgumentsBrowserWidget::handleStoppingPointReached);
|
|
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, threadManagerWidget->threadIdsBrowserWidget(), &SeerThreadIdsBrowserWidget::handleStoppingPointReached);
|
|
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, threadManagerWidget->threadFramesBrowserWidget(), &SeerThreadFramesBrowserWidget::handleStoppingPointReached);
|
|
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, variableManagerWidget->registerValuesBrowserWidget(), &SeerRegisterValuesBrowserWidget::handleStoppingPointReached);
|
|
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, variableManagerWidget->variableTrackerBrowserWidget(), &SeerVariableTrackerBrowserWidget::handleStoppingPointReached);
|
|
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, breakpointsBrowserWidget, &SeerBreakpointsBrowserWidget::handleStoppingPointReached);
|
|
QObject::connect(this, &SeerGdbWidget::stoppingPointReached, watchpointsBrowserWidget, &SeerWatchpointsBrowserWidget::handleStoppingPointReached);
|
|
}
|
|
|
|
SeerGdbWidget::~SeerGdbWidget () {
|
|
|
|
deleteConsole();
|
|
|
|
if (_gdbMonitor) {
|
|
delete _gdbMonitor;
|
|
}
|
|
|
|
if (_gdbProcess) {
|
|
_gdbProcess->kill();
|
|
_gdbProcess->waitForFinished();
|
|
delete _gdbProcess;
|
|
}
|
|
}
|
|
|
|
GdbMonitor* SeerGdbWidget::gdbMonitor () {
|
|
return _gdbMonitor;
|
|
}
|
|
|
|
QProcess* SeerGdbWidget::gdbProcess () {
|
|
return _gdbProcess;
|
|
}
|
|
|
|
void SeerGdbWidget::setExecutableName (const QString& executableName) {
|
|
|
|
_executableName = executableName;
|
|
}
|
|
|
|
const QString& SeerGdbWidget::executableName () const {
|
|
return _executableName;
|
|
}
|
|
|
|
void SeerGdbWidget::setExecutableArguments (const QString& executableArguments) {
|
|
|
|
_executableArguments = executableArguments;
|
|
}
|
|
|
|
const QString& SeerGdbWidget::executableArguments () const {
|
|
return _executableArguments;
|
|
}
|
|
|
|
void SeerGdbWidget::setExecutableWorkingDirectory (const QString& executableWorkingDirectory) {
|
|
|
|
_executableWorkingDirectory = executableWorkingDirectory;
|
|
}
|
|
|
|
const QString& SeerGdbWidget::executableWorkingDirectory () const {
|
|
return _executableWorkingDirectory;
|
|
}
|
|
|
|
void SeerGdbWidget::setExecutablePid (int pid) {
|
|
_executablePid = pid;
|
|
}
|
|
|
|
int SeerGdbWidget::executablePid () const {
|
|
return _executablePid;
|
|
}
|
|
|
|
void SeerGdbWidget::setExecutableHostPort (const QString& hostPort) {
|
|
_executableHostPort = hostPort;
|
|
}
|
|
|
|
const QString& SeerGdbWidget::executableHostPort () const {
|
|
return _executableHostPort;
|
|
}
|
|
|
|
void SeerGdbWidget::setExecutableCoreFilename (const QString& coreFilename) {
|
|
_executableCoreFilename = coreFilename;
|
|
}
|
|
|
|
const QString& SeerGdbWidget::executableCoreFilename () const {
|
|
return _executableCoreFilename;
|
|
}
|
|
|
|
void SeerGdbWidget::setExecutableLaunchMode (const QString& launchMode) {
|
|
_executableLaunchMode = launchMode;
|
|
}
|
|
|
|
const QString& SeerGdbWidget::executableLaunchMode () const {
|
|
return _executableLaunchMode;
|
|
}
|
|
|
|
void SeerGdbWidget::handleText (const QString& text) {
|
|
|
|
if (text.startsWith("*running,thread-id=\"all\"")) {
|
|
|
|
}else if (text.startsWith("*stopped,reason=\"breakpoint-hit\"")) {
|
|
emit stoppingPointReached();
|
|
|
|
}else if (text.startsWith("*stopped,reason=\"watchpoint-trigger\"")) {
|
|
emit stoppingPointReached();
|
|
|
|
}else if (text.startsWith("*stopped,reason=\"read-watchpoint-trigger\"")) {
|
|
emit stoppingPointReached();
|
|
|
|
}else if (text.startsWith("*stopped,reason=\"access-watchpoint-trigger\"")) {
|
|
emit stoppingPointReached();
|
|
|
|
}else if (text.startsWith("*stopped,reason=\"watchpoint-scope\"")) {
|
|
emit stoppingPointReached();
|
|
|
|
}else if (text.startsWith("*stopped,hw-awpt={")) {
|
|
emit stoppingPointReached();
|
|
|
|
}else if (text.startsWith("*stopped,reason=\"end-stepping-range\"")) {
|
|
emit stoppingPointReached();
|
|
|
|
}else if (text.startsWith("*stopped,reason=\"function-finished\"")) {
|
|
emit stoppingPointReached();
|
|
|
|
}else if (text.startsWith("*stopped,reason=\"location-reached\"")) {
|
|
emit stoppingPointReached();
|
|
|
|
}else if (text.startsWith("*stopped,reason=\"signal-received\"")) {
|
|
emit stoppingPointReached();
|
|
|
|
}else if (text.startsWith("*stopped,reason=\"exited-normally\"")) {
|
|
emit stoppingPointReached();
|
|
|
|
}else if (text.startsWith("*stopped,reason=\"exited-signalled\"")) {
|
|
emit stoppingPointReached();
|
|
|
|
}else if (text.startsWith("*stopped,reason=\"exited\"")) {
|
|
emit stoppingPointReached();
|
|
|
|
}else{
|
|
// All other text is ignored by this widget.
|
|
}
|
|
}
|
|
|
|
void SeerGdbWidget::handleExecute () {
|
|
|
|
//qDebug() << __PRETTY_FUNCTION__ << ":" << "QComboBox: " << manualCommandComboBox->currentText();
|
|
|
|
QString command = manualCommandComboBox->currentText();
|
|
manualCommandComboBox->clearEditText();
|
|
|
|
handleGdbCommand(command);
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbCommand (const QString& 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);
|
|
return;
|
|
}
|
|
|
|
QString str = command + "\n"; // Ensure there's a trailing RETURN.
|
|
|
|
QByteArray bytes = str.toUtf8(); // 8-bit Unicode Transformation Format
|
|
|
|
_gdbProcess->write(bytes); // Send the data into the stdin stream of the bash child process
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbExit () {
|
|
handleGdbCommand("-gdb-exit");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbRunExecutable () {
|
|
|
|
// Has a executable name been provided?
|
|
if (executableName() == "") {
|
|
QMessageBox::warning(this, "Seer",
|
|
QString("The executable name has not been provided.\n\nUse File->Debug..."),
|
|
QMessageBox::Ok);
|
|
return;
|
|
}
|
|
|
|
// Delete old console.
|
|
deleteConsole();
|
|
|
|
// Kill previous gdb, if any.
|
|
if (isGdbRuning() == true) {
|
|
killGdb();
|
|
}
|
|
|
|
// If gdb isn't running, start it.
|
|
if (isGdbRuning() == false) {
|
|
startGdb();
|
|
handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen.
|
|
}
|
|
|
|
// Create a new console.
|
|
createConsole();
|
|
|
|
setExecutableLaunchMode("run");
|
|
|
|
handleGdbExecutableName(); // Load the program into the gdb process.
|
|
handleGdbExecutableSources(); // Load the program source files.
|
|
handleGdbExecutableSharedLibraries(); // Load the program shared libraries.
|
|
handleGdbExecutableArguments(); // Set the program's arguments before running.
|
|
handleGdbExecutableWorkingDirectory(); // Set the program's working directory before running.
|
|
handleGdbTtyDeviceName(); // Set the program's tty device for stdin and stdout.
|
|
handleGdbCommand("-exec-run");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbStartExecutable () {
|
|
|
|
// Has a executable name been provided?
|
|
if (executableName() == "") {
|
|
QMessageBox::warning(this, "Seer",
|
|
QString("The executable name has not been provided.\n\nUse File->Debug..."),
|
|
QMessageBox::Ok);
|
|
return;
|
|
}
|
|
|
|
// Delete old console.
|
|
deleteConsole();
|
|
|
|
// Kill previous gdb, if any.
|
|
if (isGdbRuning() == true) {
|
|
killGdb();
|
|
}
|
|
|
|
// If gdb isn't running, start it.
|
|
if (isGdbRuning() == false) {
|
|
startGdb();
|
|
handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen.
|
|
}
|
|
|
|
// Create a new console.
|
|
createConsole();
|
|
|
|
setExecutableLaunchMode("start");
|
|
|
|
handleGdbExecutableName(); // Load the program into the gdb process.
|
|
handleGdbExecutableSources(); // Load the program source files.
|
|
handleGdbExecutableSharedLibraries(); // Load the program shared libraries.
|
|
handleGdbExecutableArguments(); // Set the program's arguments before running.
|
|
handleGdbExecutableWorkingDirectory(); // Set the program's working directory before running.
|
|
handleGdbTtyDeviceName(); // Set the program's tty device for stdin and stdout.
|
|
handleGdbCommand("-exec-run --start");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbAttachExecutable () {
|
|
|
|
// Has a executable name been provided?
|
|
if (executableName() == "") {
|
|
QMessageBox::warning(this, "Seer",
|
|
QString("The executable name has not been provided.\n\nUse File->Debug..."),
|
|
QMessageBox::Ok);
|
|
return;
|
|
}
|
|
|
|
// Delete old console.
|
|
deleteConsole();
|
|
|
|
// Kill previous gdb, if any.
|
|
if (isGdbRuning() == true) {
|
|
killGdb();
|
|
}
|
|
|
|
// If gdb isn't running, start it.
|
|
if (isGdbRuning() == false) {
|
|
startGdb();
|
|
handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen.
|
|
}
|
|
|
|
// Create a new console.
|
|
createConsole();
|
|
|
|
setExecutableLaunchMode("attach");
|
|
|
|
handleGdbExecutableName(); // Load the program into the gdb process.
|
|
handleGdbExecutableSources(); // Load the program source files.
|
|
handleGdbExecutableSharedLibraries(); // Load the program shared libraries.
|
|
handleGdbTtyDeviceName(); // Set the program's tty device for stdin and stdout.
|
|
|
|
handleGdbCommand(QString("-target-attach %1").arg(executablePid()));
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbConnectExecutable () {
|
|
|
|
// Has a executable name been provided?
|
|
if (executableName() == "") {
|
|
QMessageBox::warning(this, "Seer",
|
|
QString("The executable name has not been provided.\n\nUse File->Debug..."),
|
|
QMessageBox::Ok);
|
|
return;
|
|
}
|
|
|
|
// Delete old console.
|
|
deleteConsole();
|
|
|
|
// Kill previous gdb, if any.
|
|
if (isGdbRuning() == true) {
|
|
killGdb();
|
|
}
|
|
|
|
// If gdb isn't running, start it.
|
|
if (isGdbRuning() == false) {
|
|
startGdb();
|
|
handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen.
|
|
}
|
|
|
|
// Create a new console.
|
|
createConsole();
|
|
|
|
setExecutableLaunchMode("connect");
|
|
|
|
handleGdbTtyDeviceName(); // Set the program's tty device for stdin and stdout.
|
|
|
|
handleGdbCommand(QString("-target-select extended-remote %1").arg(executableHostPort()));
|
|
|
|
handleGdbExecutableName(); // Load the program into the gdb process.
|
|
handleGdbExecutableSources(); // Load the program source files.
|
|
handleGdbExecutableSharedLibraries(); // Load the program shared libraries.
|
|
handleGdbCommand("-target-download");
|
|
|
|
// "-file-symbol-file %s"
|
|
// "-file-exec-file %s"
|
|
// "-target-download"
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbCoreFileExecutable () {
|
|
|
|
// Has a executable name been provided?
|
|
if (executableName() == "") {
|
|
QMessageBox::warning(this, "Seer",
|
|
QString("The executable name has not been provided.\n\nUse File->Debug..."),
|
|
QMessageBox::Ok);
|
|
return;
|
|
}
|
|
|
|
// Delete old console.
|
|
deleteConsole();
|
|
|
|
// Kill previous gdb, if any.
|
|
if (isGdbRuning() == true) {
|
|
killGdb();
|
|
}
|
|
|
|
// If gdb isn't running, start it.
|
|
if (isGdbRuning() == false) {
|
|
startGdb();
|
|
handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen.
|
|
}
|
|
|
|
// Create a new console.
|
|
createConsole();
|
|
|
|
setExecutableLaunchMode("corefile");
|
|
|
|
handleGdbExecutableName(); // Load the program into the gdb process.
|
|
handleGdbExecutableSources(); // Load the program source files.
|
|
handleGdbExecutableSharedLibraries(); // Load the program shared libraries.
|
|
handleGdbTtyDeviceName(); // Set the program's tty device for stdin and stdout.
|
|
|
|
handleGdbCommand(QString("-target-select core %1").arg(executableCoreFilename()));
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbRunToLine (QString fullname, int lineno) {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
QString command = "-exec-until " + fullname + ":" + QString::number(lineno);
|
|
|
|
handleGdbCommand(command);
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbNext () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-exec-next");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbStep () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-exec-step");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbFinish () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-exec-finish");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbContinue () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-exec-continue");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbInterrupt () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-exec-interrupt");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbExecutableSources () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-file-list-exec-source-files");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbExecutableSharedLibraries () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-file-list-shared-libraries");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbExecutableName () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand(QString("-file-exec-and-symbols ") + executableName());
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbExecutableArguments () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand(QString("-exec-arguments ") + executableArguments());
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbExecutableWorkingDirectory () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
if (executableWorkingDirectory() != "") {
|
|
handleGdbCommand(QString("-environment-cd ") + executableWorkingDirectory());
|
|
}
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbTtyDeviceName () {
|
|
|
|
if (_consoleWidget->ttyDeviceName() != "") {
|
|
|
|
//qDebug() << __PRETTY_FUNCTION__ << "Setting TTY name to" << _consoleWidget->ttyDeviceName();
|
|
|
|
handleGdbCommand(QString("-inferior-tty-set ") + _consoleWidget->ttyDeviceName());
|
|
}
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbStackListFrames () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-stack-list-frames");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbStackSelectFrame (int frameno) {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand(QString("-stack-select-frame %1").arg(frameno));
|
|
|
|
emit stoppingPointReached();
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbStackListLocals () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-stack-list-variables --all-values");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbStackListArguments () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-stack-list-arguments --all-values");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbBreakpointWatchpointList () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-break-list");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbBreakpointDelete (QString breakpoints) {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-break-delete " + breakpoints);
|
|
handleGdbBreakpointWatchpointList();
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbBreakpointEnable (QString breakpoints) {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-break-enable " + breakpoints);
|
|
handleGdbBreakpointWatchpointList();
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbBreakpointDisable (QString breakpoints) {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-break-disable " + breakpoints);
|
|
handleGdbBreakpointWatchpointList();
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbBreakpointInsert (QString breakpoint) {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-break-insert " + breakpoint);
|
|
handleGdbBreakpointWatchpointList();
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbWatchpointDelete (QString watchpoints) {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-break-delete " + watchpoints);
|
|
handleGdbBreakpointWatchpointList();
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbWatchpointEnable (QString watchpoints) {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-break-enable " + watchpoints);
|
|
handleGdbBreakpointWatchpointList();
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbWatchpointDisable (QString watchpoints) {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-break-disable " + watchpoints);
|
|
handleGdbBreakpointWatchpointList();
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbWatchpointInsert (QString watchpoint) {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-break-watch " + watchpoint);
|
|
handleGdbBreakpointWatchpointList();
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbThreadListIds () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-thread-list-ids");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbThreadListFrames () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-thread-info");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbThreadSelectId (int threadid) {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand(QString("-thread-select %1").arg(threadid));
|
|
|
|
emit stoppingPointReached();
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbRegisterListNames () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-data-list-register-names");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbRegisterListValues () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand("-data-list-register-values N");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbDataEvaluateExpression (int expressionid, QString expression) {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand(QString::number(expressionid) + "-data-evaluate-expression \"" + expression + "\"");
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbDataListValues () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
for (int i=0; i<_dataExpressionId.size(); i++) {
|
|
handleGdbCommand(QString::number(_dataExpressionId[i]) + "-data-evaluate-expression \"" + _dataExpressionName[i] + "\"");
|
|
}
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbDataListExpressions () {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
// ^done,DataExpressionTable={
|
|
// entry={id="2",expression="a"},
|
|
// entry={id="3",expression="i"}
|
|
// }
|
|
|
|
QString text;
|
|
text += "^done,DataExpressionTable={";
|
|
|
|
for (int i=0; i<_dataExpressionId.size(); i++) {
|
|
if (i != 0) {
|
|
text += ",";
|
|
}
|
|
text += "entry={id=\"" + QString::number(_dataExpressionId[i]) + "\",expression=\"" + _dataExpressionName[i] + "\"}";
|
|
}
|
|
|
|
text += "}";
|
|
|
|
gdbMonitor()->handleTextOutput(text);
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbDataAddExpression (QString expression) {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
// Is this one already present?
|
|
// ??? Emit an error?
|
|
if (_dataExpressionName.indexOf(expression) >= 0) {
|
|
return;
|
|
}
|
|
|
|
// Add it to our list of variables.
|
|
_dataExpressionName.push_back(expression);
|
|
_dataExpressionId.push_back(Seer::createID());
|
|
|
|
// ^done,DataExpressionAdded={
|
|
// id="2",
|
|
// expression="a"
|
|
// }
|
|
|
|
QString text = QString("^done,DataExpressionAdded={id=\"%1\",expression=\"%2\"}").arg(_dataExpressionId.back()).arg(_dataExpressionName.back());
|
|
|
|
//qDebug() << __PRETTY_FUNCTION__ << ":" << text;
|
|
|
|
gdbMonitor()->handleTextOutput(text);
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbDataDeleteExpressions (QString expressionids) {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
// ^done,DataExpressionDeleted={
|
|
// entry={id="2", expression="a"},
|
|
// entry={id="3", expression="a"}
|
|
// }
|
|
|
|
QString text;
|
|
text += "^done,DataExpressionDeleted={";
|
|
|
|
if (expressionids == "*") {
|
|
|
|
bool first = true;
|
|
for (int i=0; i<_dataExpressionId.size(); i++) {
|
|
|
|
if (first == false) {
|
|
text += ",";
|
|
}
|
|
|
|
text += "entry={id=\"" + QString::number(_dataExpressionId[i]) + "\",expression=\"" + _dataExpressionName[i] + "\"}";
|
|
first = false;
|
|
}
|
|
|
|
_dataExpressionId.clear();
|
|
_dataExpressionName.clear();
|
|
|
|
}else{
|
|
|
|
QStringList ids = expressionids.split(' ', QString::SkipEmptyParts);
|
|
|
|
bool first = true;
|
|
for (int i=0; i<ids.size(); i++) {
|
|
|
|
if (ids[i] == "") {
|
|
continue;
|
|
}
|
|
|
|
int index = _dataExpressionId.indexOf(ids[i].toInt());
|
|
|
|
if (index < 0) {
|
|
continue;
|
|
}
|
|
|
|
if (first == false) {
|
|
text += ",";
|
|
}
|
|
|
|
text += "entry={id=\"" + QString::number(_dataExpressionId[index]) + "\",expression=\"" + _dataExpressionName[index] + "\"}";
|
|
first = false;
|
|
|
|
_dataExpressionId.remove(index);
|
|
_dataExpressionName.remove(index);
|
|
}
|
|
}
|
|
|
|
text += "}";
|
|
|
|
gdbMonitor()->handleTextOutput(text);
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbMemoryAddExpression (QString expression) {
|
|
|
|
Q_UNUSED(expression);
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
SeerMemoryVisualizerWidget* w = new SeerMemoryVisualizerWidget(0);
|
|
w->show();
|
|
|
|
// Connect things.
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::astrixTextOutput, w, &SeerMemoryVisualizerWidget::handleText);
|
|
QObject::connect(_gdbMonitor, &GdbMonitor::caretTextOutput, w, &SeerMemoryVisualizerWidget::handleText);
|
|
QObject::connect(w, &SeerMemoryVisualizerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression);
|
|
QObject::connect(w, &SeerMemoryVisualizerWidget::evaluateMemoryExpression, this, &SeerGdbWidget::handleGdbMemoryEvaluateExpression);
|
|
|
|
// Tell the visualizer what variable to use.
|
|
w->setVariableName(expression);
|
|
}
|
|
|
|
void SeerGdbWidget::handleGdbMemoryEvaluateExpression (int expressionid, QString address, int count) {
|
|
|
|
if (executableLaunchMode() == "") {
|
|
return;
|
|
}
|
|
|
|
handleGdbCommand(QString::number(expressionid) + "-data-read-memory-bytes " + address + " " + QString::number(count));
|
|
}
|
|
|
|
void SeerGdbWidget::handleFinished (int exitCode, QProcess::ExitStatus exitStatus) {
|
|
|
|
Q_UNUSED(exitCode);
|
|
Q_UNUSED(exitStatus);
|
|
|
|
// For now, terminate Seer.
|
|
qApp->exit();
|
|
}
|
|
|
|
bool SeerGdbWidget::isGdbRuning () const {
|
|
|
|
if (_gdbProcess->state() == QProcess::NotRunning) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void SeerGdbWidget::startGdb () {
|
|
|
|
// Don't do anything, if already running.
|
|
if (isGdbRuning()) {
|
|
qDebug() << __PRETTY_FUNCTION__ << ":" << "Already running";
|
|
|
|
return;
|
|
}
|
|
|
|
// Build the gdb argument list.
|
|
QStringList args;
|
|
args << "-nh" << "--interpreter=mi";
|
|
|
|
// Give the gdb process the argument list.
|
|
_gdbProcess->setArguments(args);
|
|
|
|
// Set the gdb program name to use.
|
|
_gdbProcess->setProgram("/usr/bin/gdb");
|
|
|
|
// Start the gdb process.
|
|
_gdbProcess->start();
|
|
}
|
|
|
|
void SeerGdbWidget::killGdb () {
|
|
|
|
// Don't do anything, if already running.
|
|
if (isGdbRuning() == false) {
|
|
return;
|
|
}
|
|
|
|
// Kill the process.
|
|
_gdbProcess->kill();
|
|
|
|
// Wait for it to end.
|
|
_gdbProcess->waitForFinished();
|
|
|
|
// Sanity check.
|
|
if (isGdbRuning()) {
|
|
qDebug() << __PRETTY_FUNCTION__ << ":" << "Is running but shouldn't be.";
|
|
}
|
|
|
|
// Clear the launch mode.
|
|
setExecutableLaunchMode("");
|
|
}
|
|
|
|
void SeerGdbWidget::createConsole () {
|
|
|
|
deleteConsole(); // Delete old console, if any.
|
|
|
|
if (_consoleWidget == 0) {
|
|
_consoleWidget = new SeerConsoleWidget(0);
|
|
_consoleWidget->setWindowFlags(Qt::Window | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint);
|
|
_consoleWidget->show();
|
|
}
|
|
}
|
|
|
|
void SeerGdbWidget::deleteConsole () {
|
|
|
|
if (_consoleWidget) {
|
|
delete _consoleWidget;
|
|
_consoleWidget = 0;
|
|
}
|
|
}
|
|
|