mirror of
https://github.com/epasveer/seer.git
synced 2026-08-30 00:50:42 +08:00
417 lines
16 KiB
C++
417 lines
16 KiB
C++
#include "SeerMainWindow.h"
|
|
#include "SeerRunStatusIndicator.h"
|
|
#include "SeerDebugDialog.h"
|
|
#include "SeerArgumentsDialog.h"
|
|
#include "SeerUtl.h"
|
|
#include <QtWidgets/QMessageBox>
|
|
#include <QtWidgets/QShortcut>
|
|
#include <QtGui/QKeySequence>
|
|
#include <QtCore/QCoreApplication>
|
|
#include <QtCore/QTimer>
|
|
#include <QtCore/QRegExp>
|
|
#include <QtCore/QDebug>
|
|
|
|
SeerMainWindow::SeerMainWindow(QWidget* parent) : QMainWindow(parent) {
|
|
|
|
//
|
|
// Set up UI.
|
|
//
|
|
setupUi(this);
|
|
|
|
//
|
|
// Set up other parts of the UI.
|
|
//
|
|
SeerRunStatusIndicator* runStatus = new SeerRunStatusIndicator(this);
|
|
|
|
statusBar()->addPermanentWidget(runStatus);
|
|
|
|
//
|
|
// Set up shortcut keys.
|
|
//
|
|
QShortcut* nextKeyF5 = new QShortcut(QKeySequence(Qt::Key_F5), this);
|
|
QShortcut* stepKeyF6 = new QShortcut(QKeySequence(Qt::Key_F6), this);
|
|
QShortcut* finishKeyF7 = new QShortcut(QKeySequence(Qt::Key_F7), this);
|
|
QShortcut* continueKeyF8 = new QShortcut(QKeySequence(Qt::Key_F8), this);
|
|
|
|
//
|
|
// Set up signals/slots.
|
|
//
|
|
QObject::connect(actionFileDebug, &QAction::triggered, this, &SeerMainWindow::handleFileDebug);
|
|
QObject::connect(actionFileArguments, &QAction::triggered, this, &SeerMainWindow::handleFileArguments);
|
|
QObject::connect(actionFileQuit, &QAction::triggered, this, &SeerMainWindow::handleFileQuit);
|
|
|
|
QObject::connect(actionGdbRun, &QAction::triggered, centralwidget, &SeerGdbWidget::handleGdbRunExecutable);
|
|
QObject::connect(actionGdbStart, &QAction::triggered, centralwidget, &SeerGdbWidget::handleGdbStartExecutable);
|
|
QObject::connect(actionGdbNext, &QAction::triggered, centralwidget, &SeerGdbWidget::handleGdbNext);
|
|
QObject::connect(actionGdbStep, &QAction::triggered, centralwidget, &SeerGdbWidget::handleGdbStep);
|
|
QObject::connect(actionGdbFinish, &QAction::triggered, centralwidget, &SeerGdbWidget::handleGdbFinish);
|
|
QObject::connect(actionGdbContinue, &QAction::triggered, centralwidget, &SeerGdbWidget::handleGdbContinue);
|
|
QObject::connect(actionInterruptProcess, &QAction::triggered, centralwidget, &SeerGdbWidget::handleGdbInterrupt);
|
|
|
|
QObject::connect(nextKeyF5, &QShortcut::activated, centralwidget, &SeerGdbWidget::handleGdbNext);
|
|
QObject::connect(stepKeyF6, &QShortcut::activated, centralwidget, &SeerGdbWidget::handleGdbStep);
|
|
QObject::connect(finishKeyF7, &QShortcut::activated, centralwidget, &SeerGdbWidget::handleGdbFinish);
|
|
QObject::connect(continueKeyF8, &QShortcut::activated, centralwidget, &SeerGdbWidget::handleGdbContinue);
|
|
|
|
QObject::connect(centralwidget->gdbMonitor(), &GdbMonitor::astrixTextOutput, runStatus, &SeerRunStatusIndicator::handleText);
|
|
QObject::connect(centralwidget->gdbMonitor(), &GdbMonitor::astrixTextOutput, this, &SeerMainWindow::handleText);
|
|
QObject::connect(centralwidget->gdbMonitor(), &GdbMonitor::caretTextOutput, this, &SeerMainWindow::handleText);
|
|
|
|
//
|
|
// Initialize contents.
|
|
//
|
|
statusBar()->showMessage(tr("Welcome to Seer. The All Knowing..."), 3000);
|
|
}
|
|
|
|
SeerMainWindow::~SeerMainWindow() {
|
|
}
|
|
|
|
void SeerMainWindow::setExecutableName (const QString& executableName) {
|
|
centralwidget->setExecutableName(executableName);
|
|
}
|
|
|
|
const QString& SeerMainWindow::executableName () const {
|
|
return centralwidget->executableName();
|
|
}
|
|
|
|
void SeerMainWindow::setExecutableArguments (const QString& executableArguments) {
|
|
centralwidget->setExecutableArguments(executableArguments);
|
|
}
|
|
|
|
void SeerMainWindow::setExecutableArguments (const QStringList& executableArguments) {
|
|
|
|
QString arguments = executableArguments.join(" ");
|
|
|
|
setExecutableArguments(arguments);
|
|
}
|
|
|
|
const QString& SeerMainWindow::executableArguments () const {
|
|
return centralwidget->executableArguments();
|
|
}
|
|
|
|
void SeerMainWindow::setExecutableWorkingDirectory (const QString& executableWorkingDirectory) {
|
|
centralwidget->setExecutableWorkingDirectory(executableWorkingDirectory);
|
|
}
|
|
|
|
const QString& SeerMainWindow::executableWorkingDirectory () const {
|
|
return centralwidget->executableWorkingDirectory();
|
|
}
|
|
|
|
void SeerMainWindow::setExecutablePid (int pid) {
|
|
centralwidget->setExecutablePid(pid);
|
|
}
|
|
|
|
int SeerMainWindow::executablePid () const {
|
|
return centralwidget->executablePid();
|
|
}
|
|
|
|
void SeerMainWindow::setExecutableHostPort (const QString& executableHostPort) {
|
|
centralwidget->setExecutableHostPort(executableHostPort);
|
|
}
|
|
|
|
const QString& SeerMainWindow::executableHostPort () const {
|
|
return centralwidget->executableHostPort();
|
|
}
|
|
|
|
void SeerMainWindow::setExecutableCoreFilename (const QString& executableCoreFilename) {
|
|
centralwidget->setExecutableCoreFilename(executableCoreFilename);
|
|
}
|
|
|
|
const QString& SeerMainWindow::executableCoreFilename () const {
|
|
return centralwidget->executableCoreFilename();
|
|
}
|
|
|
|
void SeerMainWindow::launchExecutable (const QString& launchMode) {
|
|
|
|
if (launchMode == "start") {
|
|
centralwidget->handleGdbStartExecutable();
|
|
|
|
}else if (launchMode == "run") {
|
|
centralwidget->handleGdbRunExecutable();
|
|
|
|
}else if (launchMode == "attach") {
|
|
centralwidget->handleGdbAttachExecutable();
|
|
|
|
}else if (launchMode == "connect") {
|
|
centralwidget->handleGdbConnectExecutable();
|
|
|
|
}else if (launchMode == "corefile") {
|
|
centralwidget->handleGdbCoreFileExecutable();
|
|
|
|
}else if (launchMode == "none") {
|
|
|
|
// If no mode, schedule the opening of the debug dialog.
|
|
QTimer::singleShot(200, this, &SeerMainWindow::handleFileDebug);
|
|
|
|
}else{
|
|
qWarning() << "SeerMainWindow::launchMode(): bad launchMode:" << launchMode;
|
|
}
|
|
}
|
|
|
|
const QString& SeerMainWindow::executableLaunchMode () const {
|
|
return centralwidget->executableLaunchMode();
|
|
}
|
|
|
|
void SeerMainWindow::handleFileDebug () {
|
|
|
|
SeerDebugDialog dlg(this);
|
|
|
|
dlg.setExecutableName(executableName());
|
|
dlg.setExecutableWorkingDirectory(executableWorkingDirectory());
|
|
dlg.setExecutableArguments(executableArguments());
|
|
dlg.setAttachPid(executablePid());
|
|
dlg.setConnectHostPort(executableHostPort());
|
|
dlg.setCoreFilename(executableCoreFilename());
|
|
dlg.setLaunchMode(executableLaunchMode());
|
|
|
|
int ret = dlg.exec();
|
|
|
|
if (ret == 0) {
|
|
return;
|
|
}
|
|
|
|
QString launchMode = dlg.launchMode();
|
|
|
|
if (launchMode == "") {
|
|
return;
|
|
}
|
|
|
|
setExecutableName(dlg.executableName());
|
|
setExecutableWorkingDirectory(dlg.executableWorkingDirectory());
|
|
setExecutableArguments(dlg.executableArguments());
|
|
setExecutablePid(dlg.attachPid());
|
|
setExecutableHostPort(dlg.connectHostPort());
|
|
setExecutableCoreFilename(dlg.coreFilename());
|
|
|
|
launchExecutable(launchMode);
|
|
}
|
|
|
|
void SeerMainWindow::handleFileArguments () {
|
|
|
|
SeerArgumentsDialog dlg(this);
|
|
dlg.setExecutableArguments(executableArguments());
|
|
|
|
int ret = dlg.exec();
|
|
|
|
if (ret == 0) {
|
|
return;
|
|
}
|
|
|
|
setExecutableArguments(dlg.executableArguments());
|
|
}
|
|
|
|
void SeerMainWindow::handleFileQuit () {
|
|
QCoreApplication::exit(0);
|
|
}
|
|
|
|
void SeerMainWindow::handleText (const QString& text) {
|
|
|
|
if (text.startsWith("^error,msg=")) {
|
|
|
|
// ^error,msg="The program is not being run."
|
|
// ^error,msg="ptrace: No such process."
|
|
|
|
//qDebug() << __PRETTY_FUNCTION__ << ":" << text;
|
|
|
|
QString newtext = Seer::filterEscapes(text); // Filter escaped characters.
|
|
|
|
// Filter out less important errors.
|
|
if (newtext == "^error,msg=\"No registers.\"") {
|
|
return;
|
|
}
|
|
|
|
if (newtext == "^error,msg=\"Selected thread is running.\"") {
|
|
return;
|
|
}
|
|
|
|
// Display the error message.
|
|
QString msg_text = Seer::parseFirst(text, "msg=", false);
|
|
|
|
if (msg_text != "") {
|
|
|
|
statusBar()->showMessage(Seer::filterBookEnds(msg_text, '"', '"'), 3000);
|
|
|
|
QMessageBox::warning(this, "Error.", Seer::filterEscapes(msg_text));
|
|
|
|
return;
|
|
}
|
|
|
|
}else if (text == "^running") {
|
|
// Swallow this message.
|
|
// statusBar()->showMessage(text.mid(1), 3000);
|
|
return;
|
|
|
|
}else if (text == "^done") {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,files=[") && text.endsWith("]")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,shared-libraries=[") && text.endsWith("]")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,stack=[") && text.endsWith("]")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,variables=[") && text.endsWith("]")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,stack-args=[") && text.endsWith("]")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,BreakpointTable={") && text.endsWith("}")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,bkpt={") && text.endsWith("}")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,hw-awpt={")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,hw-rwpt={")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,wpt={")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,thread-ids={")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,new-thread-id=")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,threads=[")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,register-names=[") && text.endsWith("]")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,register-values=[") && text.endsWith("]")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,DataExpressionAdded={") && text.endsWith("}")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,DataExpressionDeleted={") && text.endsWith("}")) {
|
|
return;
|
|
|
|
}else if (text.startsWith("^done,DataExpressionTable={") && text.endsWith("}")) {
|
|
return;
|
|
|
|
}else if (text == "^exit") {
|
|
return;
|
|
|
|
}else if (text.contains(QRegExp("^([0-9]+)\\^done,value="))) {
|
|
return;
|
|
|
|
}else if (text.contains(QRegExp("^([0-9]+)\\^error,msg="))) {
|
|
return;
|
|
|
|
}else if (text.contains(QRegExp("^([0-9]+)\\^done,memory="))) {
|
|
return;
|
|
|
|
}else if (text.startsWith("*running,thread-id=\"")) {
|
|
|
|
QString threadid_text = Seer::parseFirst(text, "thread-id=", '"', '"', false);
|
|
|
|
statusBar()->showMessage("Program started. Thread id: " + threadid_text, 3000);
|
|
|
|
return;
|
|
|
|
}else if (text.startsWith("*stopped,frame=")) {
|
|
//*stopped,frame={addr=\"0x00007f0ee0d2d954\",func=\"rfft\",args=[{name=\"a\",value=\"...\"},...
|
|
return;
|
|
|
|
}else if (text.startsWith("^connected,frame=")) {
|
|
//^connected,frame={level=\"0\",addr=\"0x00007f48351f80c1\",func=\"read\",args=[],from=\"/lib64/libc.so.6\",arch=\"i386:x86-64\"}"
|
|
return;
|
|
|
|
}else if (text.startsWith("*stopped,reason=\"") || text.startsWith("*stopped,hw-awpt={")) {
|
|
|
|
QString reason_text = Seer::parseFirst(text, "reason=", '"', '"', false);
|
|
|
|
statusBar()->showMessage("Program stopped. Reason: " + reason_text, 3000);
|
|
|
|
if (reason_text == "signal-received") {
|
|
//*stopped,reason="signal-received",signal-name="SIGSEGV",signal-meaning="Segmentation fault", ...
|
|
|
|
QString signalname_text = Seer::parseFirst(text, "signal-name=", '"', '"', false);
|
|
|
|
QMessageBox::warning(this, "Warning.", "Program encountered a '" + signalname_text + "' signal.");
|
|
|
|
}else if (reason_text == "watchpoint-trigger") {
|
|
//*stopped,reason="watchpoint-trigger",wpt={number="3",exp="i"},value={old="32767",new="42"},frame={addr="0x0000000000400d79",func="function1",args=[{name="text",value="\"Hello, World!\""}],file="function1.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp",line="9",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="0"
|
|
|
|
QString wpt_text = Seer::parseFirst(text, "wpt=", '{', '}', false);
|
|
QString number_text = Seer::parseFirst(wpt_text, "number=", '"', '"', false);
|
|
QString exp_text = Seer::parseFirst(wpt_text, "exp=", '"', '"', false);
|
|
QString value_text = Seer::parseFirst(text, "value=", '{', '}', false);
|
|
QString old_text = Seer::parseFirst(value_text, "old=", '"', '"', false);
|
|
QString new_text = Seer::parseFirst(value_text, "new=", '"', '"', false);
|
|
|
|
QMessageBox::information(this, "Note.", QString("Watchpoint triggered.\n\nNumber: %1\nExpression: %2\nOld value: %3\nNew value: %4").arg(number_text).arg(exp_text).arg(old_text).arg(new_text) );
|
|
|
|
}else if (reason_text == "read-watchpoint-trigger") {
|
|
//*stopped,reason="read-watchpoint-trigger",hw-rwpt={number="5",exp="i"},value={value="42"},frame={addr="0x0000000000400d9a",func="function1",args=[{name="text",value="\"Hello, World!\""}],file="function1.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp",line="11",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="4"
|
|
|
|
QString hwwpt_text = Seer::parseFirst(text, "hw-rwpt=", '{', '}', false);
|
|
QString number_text = Seer::parseFirst(hwwpt_text, "number=", '"', '"', false);
|
|
QString exp_text = Seer::parseFirst(hwwpt_text, "exp=", '"', '"', false);
|
|
QString value_text = Seer::parseFirst(text, "value=", '{', '}', false);
|
|
QString value_text2 = Seer::parseFirst(value_text, "value=", '"', '"', false);
|
|
|
|
QMessageBox::information(this, "Note.", QString("Watchpoint triggered.\n\nNumber: %1\nExpression: %2\nValue: %3").arg(number_text).arg(exp_text).arg(value_text2) );
|
|
|
|
}else if (reason_text == "access-watchpoint-trigger") {
|
|
//*stopped,reason="access-watchpoint-trigger",hw-awpt={number="3",exp="v"},value={old="1",new="11"},frame={addr="0x000000000040059a",func="bar",args=[{name="v",value="11"}],file="helloonefile.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloonefile/helloonefile.cpp",line="15",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="3"
|
|
|
|
QString hwawpt_text = Seer::parseFirst(text, "hw-awpt=", '{', '}', false);
|
|
QString number_text = Seer::parseFirst(hwawpt_text, "number=", '"', '"', false);
|
|
QString exp_text = Seer::parseFirst(hwawpt_text, "exp=", '"', '"', false);
|
|
QString value_text = Seer::parseFirst(text, "value=", '{', '}', false);
|
|
QString old_text = Seer::parseFirst(value_text, "old=", '"', '"', false);
|
|
QString new_text = Seer::parseFirst(value_text, "new=", '"', '"', false);
|
|
|
|
QMessageBox::information(this, "Note.", QString("Watchpoint triggered.\n\nNumber: %1\nExpression: %2\nOld value: %3\nNew value: %4").arg(number_text).arg(exp_text).arg(old_text).arg(new_text) );
|
|
|
|
}else if (reason_text == "watchpoint-scope") {
|
|
//*stopped,reason="watchpoint-scope",wpnum="5", frame={func="callee3",args=[{name="strarg", value="0x11940 \"A string argument.\""}], file="../../../devo/gdb/testsuite/gdb.mi/basics.c", fullname="/home/foo/bar/devo/gdb/testsuite/gdb.mi/basics.c",line="18"}
|
|
|
|
QString wpnum_text = Seer::parseFirst(text, "wpnum=", '"', '"', false);
|
|
|
|
QMessageBox::information(this, "Note.", QString("Watchpoint went out of scope. Will be deleted.\n\nNumber: %1").arg(wpnum_text) );
|
|
|
|
}else if (reason_text == "exited-normally") {
|
|
//*stopped,reason="exited-normally"
|
|
|
|
QMessageBox::information(this, "Note.", "Program exited normally.");
|
|
|
|
}else if (reason_text == "exited") {
|
|
//*stopped,reason="exited",exit-code="01"
|
|
|
|
QString exitcode_text = Seer::parseFirst(text, "exit-code=", '"', '"', false);
|
|
|
|
QMessageBox::information(this, "Note.", "Program exited with code '" + exitcode_text +"'");
|
|
|
|
}else if (reason_text == "exited-signalled") {
|
|
//*stopped,reason="exited-signalled",signal-name="SIGSEGV",signal-meaning="Segmentation fault"
|
|
|
|
QString signalname_text = Seer::parseFirst(text, "signal-name=", '"', '"', false);
|
|
|
|
QMessageBox::warning(this, "Error.", "Program exited abnormally.\n\nIt encountered a '" + signalname_text + "' signal.");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
qDebug() << __PRETTY_FUNCTION__ << ":" << text;
|
|
}
|
|
|
|
void SeerMainWindow::closeEvent (QCloseEvent* event) {
|
|
|
|
event->accept();
|
|
|
|
QCoreApplication::exit(0);
|
|
}
|
|
|