2021-07-03 21:57:50 +08:00
|
|
|
#include "debugger.h"
|
2021-07-17 19:32:23 +08:00
|
|
|
#include "utils.h"
|
|
|
|
#include "mainwindow.h"
|
2021-07-24 11:18:25 +08:00
|
|
|
#include "editor.h"
|
2021-07-25 00:26:13 +08:00
|
|
|
#include "settings.h"
|
2021-08-01 23:24:37 +08:00
|
|
|
#include "widgets/cpudialog.h"
|
2021-10-12 19:39:24 +08:00
|
|
|
#include "systemconsts.h"
|
2021-07-25 00:26:13 +08:00
|
|
|
|
|
|
|
#include <QFile>
|
|
|
|
#include <QFileInfo>
|
|
|
|
#include <QMessageBox>
|
2021-08-01 10:00:27 +08:00
|
|
|
#include <QPlainTextEdit>
|
2021-08-01 01:06:43 +08:00
|
|
|
#include <QDebug>
|
2021-10-13 17:20:31 +08:00
|
|
|
#include <QDir>
|
2021-11-23 21:08:33 +08:00
|
|
|
#include <QJsonDocument>
|
|
|
|
#include <QJsonArray>
|
|
|
|
#include <QJsonObject>
|
2021-07-03 21:57:50 +08:00
|
|
|
|
|
|
|
Debugger::Debugger(QObject *parent) : QObject(parent)
|
|
|
|
{
|
2021-07-24 11:18:25 +08:00
|
|
|
mBreakpointModel=new BreakpointModel(this);
|
|
|
|
mBacktraceModel=new BacktraceModel(this);
|
2021-08-01 01:06:43 +08:00
|
|
|
mWatchModel = new WatchModel(this);
|
2021-08-01 23:24:37 +08:00
|
|
|
mRegisterModel = new RegisterModel(this);
|
2021-07-27 00:14:24 +08:00
|
|
|
mExecuting = false;
|
|
|
|
mUseUTF8 = false;
|
|
|
|
mReader = nullptr;
|
|
|
|
mCommandChanged = false;
|
|
|
|
mLeftPageIndexBackup = -1;
|
2021-07-24 11:18:25 +08:00
|
|
|
}
|
|
|
|
|
2021-08-20 12:43:01 +08:00
|
|
|
bool Debugger::start()
|
2021-07-25 00:26:13 +08:00
|
|
|
{
|
|
|
|
Settings::PCompilerSet compilerSet = pSettings->compilerSets().defaultSet();
|
|
|
|
if (!compilerSet) {
|
|
|
|
QMessageBox::critical(pMainWindow,
|
|
|
|
tr("No compiler set"),
|
|
|
|
tr("No compiler set is configured.")+tr("Can't start debugging."));
|
2021-08-20 12:43:01 +08:00
|
|
|
return false;
|
2021-07-25 00:26:13 +08:00
|
|
|
}
|
2021-07-26 22:29:47 +08:00
|
|
|
mExecuting = true;
|
2021-07-25 00:26:13 +08:00
|
|
|
QString debuggerPath = compilerSet->debugger();
|
2021-10-02 21:46:34 +08:00
|
|
|
//QFile debuggerProgram(debuggerPath);
|
|
|
|
if (!isTextAllAscii(debuggerPath)) {
|
|
|
|
mExecuting = false;
|
|
|
|
QMessageBox::critical(pMainWindow,
|
|
|
|
tr("Debugger path error"),
|
|
|
|
tr("Debugger's path \"%1\" contains non-ascii characters.")
|
|
|
|
.arg(debuggerPath)
|
|
|
|
+ "<br />"
|
|
|
|
+ tr("This prevents it from executing."));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!fileExists(debuggerPath)) {
|
2021-08-20 12:43:01 +08:00
|
|
|
mExecuting = false;
|
2021-07-25 00:26:13 +08:00
|
|
|
QMessageBox::critical(pMainWindow,
|
|
|
|
tr("Debugger not exists"),
|
|
|
|
tr("Can''t find debugger in : \"%1\"").arg(debuggerPath));
|
2021-08-20 12:43:01 +08:00
|
|
|
return false;
|
2021-07-25 00:26:13 +08:00
|
|
|
}
|
2021-07-26 00:22:08 +08:00
|
|
|
mReader = new DebugReader(this);
|
2021-07-25 00:26:13 +08:00
|
|
|
mReader->setDebuggerPath(debuggerPath);
|
2021-07-31 14:04:43 +08:00
|
|
|
connect(mReader, &QThread::finished,this,&Debugger::clearUpReader);
|
2021-07-26 11:47:54 +08:00
|
|
|
connect(mReader, &DebugReader::parseFinished,this,&Debugger::syncFinishedParsing,Qt::BlockingQueuedConnection);
|
2021-08-01 12:02:28 +08:00
|
|
|
connect(mReader, &DebugReader::changeDebugConsoleLastLine,this,&Debugger::onChangeDebugConsoleLastline);
|
2021-09-19 14:28:30 +08:00
|
|
|
connect(mReader, &DebugReader::cmdStarted,pMainWindow, &MainWindow::disableDebugActions);
|
|
|
|
connect(mReader, &DebugReader::cmdFinished,pMainWindow, &MainWindow::enableDebugActions);
|
2021-11-23 21:08:33 +08:00
|
|
|
|
2021-11-21 08:38:03 +08:00
|
|
|
connect(mReader, &DebugReader::breakpointInfoGetted, mBreakpointModel,
|
|
|
|
&BreakpointModel::updateBreakpointNumber);
|
2021-11-24 10:07:35 +08:00
|
|
|
connect(mReader, &DebugReader::localsUpdated, pMainWindow,
|
|
|
|
&MainWindow::onLocalsReady);
|
2021-11-24 17:53:25 +08:00
|
|
|
connect(mReader, &DebugReader::memoryUpdated,[this](const QStringList& memory) {
|
2021-11-24 10:07:35 +08:00
|
|
|
emit memoryExamineReady(memory);
|
|
|
|
});
|
2021-11-24 17:53:25 +08:00
|
|
|
connect(mReader, &DebugReader::evalUpdated,[this](const QString& value) {
|
|
|
|
emit evalValueReady(value);
|
|
|
|
});
|
|
|
|
connect(mReader, &DebugReader::inferiorStopped,pMainWindow,
|
|
|
|
&MainWindow::setActiveBreakpoint);
|
2021-09-19 14:28:30 +08:00
|
|
|
|
2021-07-25 00:26:13 +08:00
|
|
|
mReader->start();
|
2021-11-10 17:05:37 +08:00
|
|
|
mReader->waitStart();
|
2021-07-25 00:26:13 +08:00
|
|
|
|
2021-07-26 00:22:08 +08:00
|
|
|
pMainWindow->updateAppTitle();
|
2021-07-25 00:26:13 +08:00
|
|
|
|
2021-07-25 13:03:46 +08:00
|
|
|
//Application.HintHidePause := 5000;
|
2021-08-20 12:43:01 +08:00
|
|
|
return true;
|
2021-07-25 13:03:46 +08:00
|
|
|
}
|
2021-07-31 14:04:43 +08:00
|
|
|
void Debugger::stop() {
|
|
|
|
if (mExecuting) {
|
|
|
|
mReader->stopDebug();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void Debugger::clearUpReader()
|
2021-07-25 13:03:46 +08:00
|
|
|
{
|
|
|
|
if (mExecuting) {
|
|
|
|
mExecuting = false;
|
|
|
|
|
2021-07-26 00:22:08 +08:00
|
|
|
//stop debugger
|
|
|
|
mReader->deleteLater();
|
|
|
|
mReader=nullptr;
|
2021-07-31 14:04:43 +08:00
|
|
|
|
2021-07-26 00:22:08 +08:00
|
|
|
// if WatchVarList.Count = 0 then // nothing worth showing, restore view
|
|
|
|
// MainForm.LeftPageControl.ActivePageIndex := LeftPageIndexBackup;
|
2021-07-25 13:03:46 +08:00
|
|
|
|
2021-07-26 00:22:08 +08:00
|
|
|
// // Close CPU window
|
2021-08-01 23:24:37 +08:00
|
|
|
if (pMainWindow->cpuDialog()!=nullptr) {
|
|
|
|
pMainWindow->cpuDialog()->close();
|
|
|
|
}
|
2021-07-25 13:03:46 +08:00
|
|
|
|
|
|
|
// Free resources
|
2021-07-26 00:22:08 +08:00
|
|
|
pMainWindow->removeActiveBreakpoints();
|
2021-07-25 13:03:46 +08:00
|
|
|
|
2021-08-01 10:00:27 +08:00
|
|
|
pMainWindow->txtLocals()->clear();
|
|
|
|
|
2021-07-26 00:22:08 +08:00
|
|
|
pMainWindow->updateAppTitle();
|
2021-07-25 13:03:46 +08:00
|
|
|
|
2021-08-01 23:24:37 +08:00
|
|
|
pMainWindow->updateDebugEval("");
|
|
|
|
|
2021-07-26 11:47:54 +08:00
|
|
|
mBacktraceModel->clear();
|
2021-07-25 13:03:46 +08:00
|
|
|
|
2021-08-01 01:06:43 +08:00
|
|
|
for(PWatchVar var:mWatchModel->watchVars()) {
|
|
|
|
invalidateWatchVar(var);
|
|
|
|
}
|
2021-08-01 12:02:28 +08:00
|
|
|
|
|
|
|
pMainWindow->updateEditorActions();
|
2021-07-25 13:03:46 +08:00
|
|
|
}
|
2021-07-25 00:26:13 +08:00
|
|
|
}
|
|
|
|
|
2021-08-01 23:24:37 +08:00
|
|
|
RegisterModel *Debugger::registerModel() const
|
|
|
|
{
|
|
|
|
return mRegisterModel;
|
|
|
|
}
|
|
|
|
|
2021-08-01 01:06:43 +08:00
|
|
|
WatchModel *Debugger::watchModel() const
|
|
|
|
{
|
|
|
|
return mWatchModel;
|
|
|
|
}
|
|
|
|
|
2021-11-24 17:53:25 +08:00
|
|
|
void Debugger::sendCommand(const QString &command, const QString ¶ms, DebugCommandSource source)
|
2021-07-24 11:18:25 +08:00
|
|
|
{
|
|
|
|
if (mExecuting && mReader) {
|
2021-11-24 17:53:25 +08:00
|
|
|
mReader->postCommand(command,params,source);
|
2021-07-24 11:18:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-29 22:08:43 +08:00
|
|
|
bool Debugger::commandRunning()
|
|
|
|
{
|
|
|
|
if (mExecuting && mReader) {
|
|
|
|
return mReader->commandRunning();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-07-24 11:18:25 +08:00
|
|
|
void Debugger::addBreakpoint(int line, const Editor* editor)
|
|
|
|
{
|
|
|
|
addBreakpoint(line,editor->filename());
|
|
|
|
}
|
2021-07-03 21:57:50 +08:00
|
|
|
|
2021-07-24 11:18:25 +08:00
|
|
|
void Debugger::addBreakpoint(int line, const QString &filename)
|
|
|
|
{
|
|
|
|
PBreakpoint bp=std::make_shared<Breakpoint>();
|
2021-11-20 07:53:39 +08:00
|
|
|
bp->number = -1;
|
2021-07-24 11:18:25 +08:00
|
|
|
bp->line = line;
|
|
|
|
bp->filename = filename;
|
|
|
|
bp->condition = "";
|
2021-10-21 19:33:11 +08:00
|
|
|
bp->enabled = true;
|
2021-07-24 11:18:25 +08:00
|
|
|
mBreakpointModel->addBreakpoint(bp);
|
2021-07-25 13:03:46 +08:00
|
|
|
if (mExecuting) {
|
|
|
|
sendBreakpointCommand(bp);
|
|
|
|
}
|
2021-07-24 11:18:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::deleteBreakpoints(const QString &filename)
|
|
|
|
{
|
|
|
|
for (int i=mBreakpointModel->breakpoints().size()-1;i>=0;i--) {
|
|
|
|
PBreakpoint bp = mBreakpointModel->breakpoints()[i];
|
|
|
|
if (bp->filename == filename) {
|
|
|
|
mBreakpointModel->removeBreakpoint(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::deleteBreakpoints(const Editor *editor)
|
|
|
|
{
|
|
|
|
deleteBreakpoints(editor->filename());
|
|
|
|
}
|
|
|
|
|
2021-09-05 22:16:54 +08:00
|
|
|
void Debugger::deleteBreakpoints()
|
|
|
|
{
|
|
|
|
for (int i=mBreakpointModel->breakpoints().size()-1;i>=0;i--) {
|
|
|
|
removeBreakpoint(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-24 11:18:25 +08:00
|
|
|
void Debugger::removeBreakpoint(int line, const Editor *editor)
|
|
|
|
{
|
|
|
|
removeBreakpoint(line,editor->filename());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::removeBreakpoint(int line, const QString &filename)
|
|
|
|
{
|
|
|
|
for (int i=mBreakpointModel->breakpoints().size()-1;i>=0;i--) {
|
|
|
|
PBreakpoint bp = mBreakpointModel->breakpoints()[i];
|
|
|
|
if (bp->filename == filename && bp->line == line) {
|
|
|
|
removeBreakpoint(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::removeBreakpoint(int index)
|
|
|
|
{
|
|
|
|
sendClearBreakpointCommand(index);
|
|
|
|
mBreakpointModel->removeBreakpoint(index);
|
|
|
|
}
|
|
|
|
|
2021-09-03 10:30:08 +08:00
|
|
|
PBreakpoint Debugger::breakpointAt(int line, const QString& filename, int &index)
|
|
|
|
{
|
|
|
|
const QList<PBreakpoint>& breakpoints=mBreakpointModel->breakpoints();
|
|
|
|
for (index=0;index<breakpoints.count();index++){
|
|
|
|
PBreakpoint breakpoint = breakpoints[index];
|
|
|
|
if (breakpoint->line == line
|
|
|
|
&& breakpoint->filename == filename)
|
|
|
|
return breakpoint;
|
|
|
|
}
|
|
|
|
index=-1;
|
|
|
|
return PBreakpoint();
|
|
|
|
}
|
|
|
|
|
|
|
|
PBreakpoint Debugger::breakpointAt(int line, const Editor *editor, int &index)
|
|
|
|
{
|
|
|
|
return breakpointAt(line,editor->filename(),index);
|
|
|
|
}
|
|
|
|
|
2021-07-24 11:18:25 +08:00
|
|
|
void Debugger::setBreakPointCondition(int index, const QString &condition)
|
|
|
|
{
|
|
|
|
PBreakpoint breakpoint=mBreakpointModel->setBreakPointCondition(index,condition);
|
|
|
|
if (condition.isEmpty()) {
|
2021-11-10 12:29:02 +08:00
|
|
|
sendCommand("-break-condition",
|
2021-07-24 11:18:25 +08:00
|
|
|
QString("%1").arg(breakpoint->line));
|
|
|
|
} else {
|
2021-11-10 12:29:02 +08:00
|
|
|
sendCommand("-break-condition",
|
2021-07-24 11:18:25 +08:00
|
|
|
QString("%1 %2").arg(breakpoint->line).arg(condition));
|
|
|
|
}
|
2021-07-03 21:57:50 +08:00
|
|
|
}
|
|
|
|
|
2021-07-25 13:03:46 +08:00
|
|
|
void Debugger::sendAllBreakpointsToDebugger()
|
|
|
|
{
|
|
|
|
for (PBreakpoint breakpoint:mBreakpointModel->breakpoints()) {
|
|
|
|
sendBreakpointCommand(breakpoint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-31 20:19:45 +08:00
|
|
|
void Debugger::addWatchVar(const QString &namein)
|
2021-07-26 18:22:09 +08:00
|
|
|
{
|
2021-07-31 20:19:45 +08:00
|
|
|
// Don't allow duplicates...
|
|
|
|
PWatchVar oldVar = mWatchModel->findWatchVar(namein);
|
|
|
|
if (oldVar)
|
|
|
|
return;
|
2021-07-26 18:22:09 +08:00
|
|
|
|
2021-07-31 20:19:45 +08:00
|
|
|
PWatchVar var = std::make_shared<WatchVar>();
|
|
|
|
var->parent= nullptr;
|
|
|
|
var->name = namein;
|
2021-09-19 09:45:03 +08:00
|
|
|
var->value = tr("Execute to evaluate");
|
2021-07-31 20:19:45 +08:00
|
|
|
var->gdbIndex = -1;
|
2021-07-26 18:22:09 +08:00
|
|
|
|
2021-07-31 20:19:45 +08:00
|
|
|
mWatchModel->addWatchVar(var);
|
|
|
|
sendWatchCommand(var);
|
2021-07-26 18:22:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::renameWatchVar(const QString &oldname, const QString &newname)
|
|
|
|
{
|
2021-07-31 20:19:45 +08:00
|
|
|
// check if name already exists;
|
|
|
|
PWatchVar var = mWatchModel->findWatchVar(newname);
|
|
|
|
if (var)
|
|
|
|
return;
|
|
|
|
|
|
|
|
var = mWatchModel->findWatchVar(oldname);
|
|
|
|
if (var) {
|
|
|
|
var->name = newname;
|
2021-08-01 01:06:43 +08:00
|
|
|
if (mExecuting && var->gdbIndex!=-1)
|
|
|
|
sendRemoveWatchCommand(var);
|
|
|
|
invalidateWatchVar(var);
|
2021-07-31 20:19:45 +08:00
|
|
|
|
|
|
|
if (mExecuting) {
|
|
|
|
sendWatchCommand(var);
|
|
|
|
}
|
|
|
|
}
|
2021-07-26 18:22:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::refreshWatchVars()
|
|
|
|
{
|
2021-07-31 20:19:45 +08:00
|
|
|
for (PWatchVar var:mWatchModel->watchVars()) {
|
|
|
|
if (var->gdbIndex == -1)
|
|
|
|
sendWatchCommand(var);
|
|
|
|
}
|
2021-07-26 18:22:09 +08:00
|
|
|
}
|
|
|
|
|
2021-08-31 11:13:12 +08:00
|
|
|
void Debugger::removeWatchVars(bool deleteparent)
|
2021-07-26 18:22:09 +08:00
|
|
|
{
|
2021-07-31 20:19:45 +08:00
|
|
|
if (deleteparent) {
|
|
|
|
mWatchModel->clear();
|
|
|
|
} else {
|
2021-08-31 11:13:12 +08:00
|
|
|
for(const PWatchVar& var:mWatchModel->watchVars()) {
|
2021-07-31 20:19:45 +08:00
|
|
|
sendRemoveWatchCommand(var);
|
2021-08-01 01:06:43 +08:00
|
|
|
invalidateWatchVar(var);
|
2021-07-31 20:19:45 +08:00
|
|
|
}
|
|
|
|
}
|
2021-07-26 18:22:09 +08:00
|
|
|
}
|
|
|
|
|
2021-08-31 11:13:12 +08:00
|
|
|
void Debugger::removeWatchVar(const QModelIndex &index)
|
|
|
|
{
|
|
|
|
mWatchModel->removeWatchVar(index);
|
|
|
|
}
|
|
|
|
|
2021-07-26 18:22:09 +08:00
|
|
|
void Debugger::invalidateAllVars()
|
|
|
|
{
|
2021-07-31 20:19:45 +08:00
|
|
|
mReader->setInvalidateAllVars(true);
|
2021-07-26 18:22:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::sendAllWatchvarsToDebugger()
|
|
|
|
{
|
2021-07-31 20:19:45 +08:00
|
|
|
for (PWatchVar var:mWatchModel->watchVars()) {
|
|
|
|
sendWatchCommand(var);
|
|
|
|
}
|
2021-07-26 18:22:09 +08:00
|
|
|
}
|
|
|
|
|
2021-08-01 01:06:43 +08:00
|
|
|
void Debugger::invalidateWatchVar(const QString &name)
|
|
|
|
{
|
|
|
|
PWatchVar var = mWatchModel->findWatchVar(name);
|
|
|
|
if (var) {
|
|
|
|
invalidateWatchVar(var);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-26 18:22:09 +08:00
|
|
|
void Debugger::invalidateWatchVar(PWatchVar var)
|
|
|
|
{
|
2021-08-01 01:06:43 +08:00
|
|
|
var->gdbIndex = -1;
|
|
|
|
QString value;
|
|
|
|
if (mExecuting) {
|
|
|
|
value = tr("Not found in current context");
|
|
|
|
} else {
|
|
|
|
value = tr("Execute to evaluate");
|
|
|
|
}
|
2021-09-19 09:45:03 +08:00
|
|
|
var->value = value;
|
2021-09-19 01:58:09 +08:00
|
|
|
if (var->children.isEmpty()) {
|
|
|
|
mWatchModel->notifyUpdated(var);
|
|
|
|
} else {
|
|
|
|
mWatchModel->beginUpdate();
|
|
|
|
var->children.clear();
|
|
|
|
mWatchModel->endUpdate();
|
|
|
|
}
|
2021-08-01 01:06:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
PWatchVar Debugger::findWatchVar(const QString &name)
|
|
|
|
{
|
|
|
|
return mWatchModel->findWatchVar(name);
|
|
|
|
}
|
|
|
|
|
2021-09-19 02:00:25 +08:00
|
|
|
//void Debugger::notifyWatchVarUpdated(PWatchVar var)
|
|
|
|
//{
|
|
|
|
// mWatchModel->notifyUpdated(var);
|
|
|
|
//}
|
2021-07-26 18:22:09 +08:00
|
|
|
|
2021-09-19 01:58:09 +08:00
|
|
|
void Debugger::notifyBeforeProcessWatchVar()
|
|
|
|
{
|
|
|
|
mWatchModel->beginUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::notifyAfterProcessWatchVar()
|
|
|
|
{
|
|
|
|
mWatchModel->endUpdate();
|
|
|
|
}
|
|
|
|
|
2021-07-26 18:22:09 +08:00
|
|
|
void Debugger::updateDebugInfo()
|
|
|
|
{
|
2021-11-10 12:29:02 +08:00
|
|
|
sendCommand("-stack-list-frames", "");
|
|
|
|
sendCommand("-stack-list-variables", "--skip-unavailable --allvalues");
|
2021-07-26 18:22:09 +08:00
|
|
|
}
|
|
|
|
|
2021-07-24 08:12:51 +08:00
|
|
|
bool Debugger::useUTF8() const
|
|
|
|
{
|
|
|
|
return mUseUTF8;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::setUseUTF8(bool useUTF8)
|
|
|
|
{
|
|
|
|
mUseUTF8 = useUTF8;
|
|
|
|
}
|
|
|
|
|
2021-07-25 00:26:13 +08:00
|
|
|
BacktraceModel* Debugger::backtraceModel()
|
2021-07-24 08:12:51 +08:00
|
|
|
{
|
|
|
|
return mBacktraceModel;
|
|
|
|
}
|
|
|
|
|
2021-07-25 00:26:13 +08:00
|
|
|
BreakpointModel *Debugger::breakpointModel()
|
2021-07-24 11:18:25 +08:00
|
|
|
{
|
|
|
|
return mBreakpointModel;
|
|
|
|
}
|
|
|
|
|
2021-07-31 20:19:45 +08:00
|
|
|
void Debugger::sendWatchCommand(PWatchVar var)
|
2021-07-24 11:18:25 +08:00
|
|
|
{
|
2021-07-31 20:19:45 +08:00
|
|
|
sendCommand("display", var->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::sendRemoveWatchCommand(PWatchVar var)
|
|
|
|
{
|
|
|
|
sendCommand("undisplay",QString("%1").arg(var->gdbIndex));
|
2021-07-25 13:03:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::sendBreakpointCommand(PBreakpoint breakpoint)
|
|
|
|
{
|
|
|
|
if (breakpoint && mExecuting) {
|
|
|
|
// break "filename":linenum
|
|
|
|
QString condition;
|
|
|
|
if (!breakpoint->condition.isEmpty()) {
|
2021-11-10 12:29:02 +08:00
|
|
|
condition = " -c " + breakpoint->condition;
|
2021-07-25 13:03:46 +08:00
|
|
|
}
|
|
|
|
QString filename = breakpoint->filename;
|
|
|
|
filename.replace('\\','/');
|
2021-11-10 12:29:02 +08:00
|
|
|
sendCommand("-break-insert",
|
|
|
|
QString("%1 --source \"%2\" --line %3")
|
|
|
|
.arg(condition,filename)
|
|
|
|
.arg(breakpoint->line));
|
2021-07-24 11:18:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::sendClearBreakpointCommand(int index)
|
2021-07-25 13:03:46 +08:00
|
|
|
{
|
2021-07-26 11:47:54 +08:00
|
|
|
sendClearBreakpointCommand(mBreakpointModel->breakpoints()[index]);
|
2021-07-25 13:03:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::sendClearBreakpointCommand(PBreakpoint breakpoint)
|
2021-07-24 11:18:25 +08:00
|
|
|
{
|
|
|
|
// Debugger already running? Remove it from GDB
|
2021-11-20 07:53:39 +08:00
|
|
|
if (breakpoint && breakpoint->number>=0 && mExecuting) {
|
2021-07-24 11:18:25 +08:00
|
|
|
//clear "filename":linenum
|
|
|
|
QString filename = breakpoint->filename;
|
|
|
|
filename.replace('\\','/');
|
2021-11-20 07:53:39 +08:00
|
|
|
sendCommand("-break-delete",
|
|
|
|
QString("%1").arg(breakpoint->number));
|
2021-07-24 11:18:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-26 11:47:54 +08:00
|
|
|
void Debugger::syncFinishedParsing()
|
|
|
|
{
|
|
|
|
bool spawnedcpuform = false;
|
|
|
|
|
|
|
|
// GDB determined that the source code is more recent than the executable. Ask the user if he wants to rebuild.
|
2021-11-24 10:07:35 +08:00
|
|
|
if (mReader->receivedSFWarning()) {
|
2021-07-26 11:47:54 +08:00
|
|
|
if (QMessageBox::question(pMainWindow,
|
|
|
|
tr("Compile"),
|
|
|
|
tr("Source file is more recent than executable.")+"<BR /><BR />" + tr("Recompile?"),
|
|
|
|
QMessageBox::Yes | QMessageBox::No,
|
|
|
|
QMessageBox::Yes
|
|
|
|
) == QMessageBox::Yes) {
|
|
|
|
stop();
|
|
|
|
pMainWindow->compile();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The program to debug has stopped. Stop the debugger
|
2021-11-10 17:05:37 +08:00
|
|
|
if (mReader->processExited()) {
|
2021-07-26 11:47:54 +08:00
|
|
|
stop();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// show command output
|
2021-11-24 17:53:25 +08:00
|
|
|
if (pSettings->debugger().showCommandLog() ) {
|
2021-07-26 11:47:54 +08:00
|
|
|
if (pSettings->debugger().showAnnotations()) {
|
2021-11-24 17:53:25 +08:00
|
|
|
for (const QString& line:mReader->fullOutput()) {
|
|
|
|
pMainWindow->addDebugOutput(line);
|
2021-07-26 11:47:54 +08:00
|
|
|
}
|
2021-11-24 17:53:25 +08:00
|
|
|
} else {
|
|
|
|
for (const QString& line:mReader->consoleOutput()) {
|
2021-07-26 11:47:54 +08:00
|
|
|
pMainWindow->addDebugOutput(line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Some part of the CPU form has been updated
|
2021-11-24 17:53:25 +08:00
|
|
|
if (pMainWindow->cpuDialog()!=nullptr && !mReader->signalReceived()) {
|
|
|
|
// if (mReader->doregistersready) {
|
|
|
|
// mRegisterModel->update(mReader->mRegisters);
|
|
|
|
// mReader->mRegisters.clear();
|
|
|
|
// mReader->doregistersready = false;
|
|
|
|
// }
|
2021-07-26 11:47:54 +08:00
|
|
|
|
2021-11-24 17:53:25 +08:00
|
|
|
// if (mReader->dodisassemblerready) {
|
|
|
|
// pMainWindow->cpuDialog()->setDisassembly(mReader->mDisassembly);
|
|
|
|
// mReader->mDisassembly.clear();
|
|
|
|
// mReader->dodisassemblerready = false;
|
|
|
|
// }
|
2021-07-26 11:47:54 +08:00
|
|
|
}
|
|
|
|
|
2021-11-24 17:53:25 +08:00
|
|
|
// if (mReader->updateExecution()) {
|
|
|
|
// if (mReader->currentCmd() && mReader->currentCmd()->source == DebugCommandSource::Console) {
|
|
|
|
// pMainWindow->setActiveBreakpoint(mReader->breakPointFile(), mReader->breakPointLine(),false);
|
|
|
|
// } else {
|
|
|
|
// pMainWindow->setActiveBreakpoint(mReader->breakPointFile(), mReader->breakPointLine());
|
|
|
|
// }
|
|
|
|
// refreshWatchVars(); // update variable information
|
|
|
|
// }
|
2021-07-26 11:47:54 +08:00
|
|
|
|
2021-11-23 21:08:33 +08:00
|
|
|
if (mReader->signalReceived()) {
|
|
|
|
|
2021-07-26 11:47:54 +08:00
|
|
|
//SignalDialog := CreateMessageDialog(fSignal, mtError, [mbOk]);
|
|
|
|
//SignalCheck := TCheckBox.Create(SignalDialog);
|
|
|
|
|
|
|
|
//// Display it on top of everything
|
|
|
|
//SignalDialog.FormStyle := fsStayOnTop;
|
|
|
|
|
|
|
|
//SignalDialog.Height := 150;
|
|
|
|
|
|
|
|
//with SignalCheck do begin
|
|
|
|
// Parent := SignalDialog;
|
|
|
|
// Caption := 'Show CPU window';
|
|
|
|
// Top := Parent.ClientHeight - 22;
|
|
|
|
// Left := 8;
|
|
|
|
// Width := Parent.ClientWidth - 16;
|
|
|
|
// Checked := devData.ShowCPUSignal;
|
|
|
|
//end;
|
|
|
|
|
|
|
|
//MessageBeep(MB_ICONERROR);
|
|
|
|
//if SignalDialog.ShowModal = ID_OK then begin
|
|
|
|
// devData.ShowCPUSignal := SignalCheck.Checked;
|
|
|
|
// if SignalCheck.Checked and not Assigned(CPUForm) then begin
|
|
|
|
// MainForm.ViewCPUItemClick(nil);
|
|
|
|
// spawnedcpuform := true;
|
|
|
|
// end;
|
|
|
|
//end;
|
|
|
|
|
|
|
|
//SignalDialog.Free;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CPU form updates itself when spawned, don't update twice!
|
2021-11-23 21:08:33 +08:00
|
|
|
if ((mReader->updateCPUInfo() && !spawnedcpuform) && (pMainWindow->cpuDialog()!=nullptr)) {
|
2021-08-01 23:24:37 +08:00
|
|
|
pMainWindow->cpuDialog()->updateInfo();
|
2021-07-26 11:47:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-24 10:07:35 +08:00
|
|
|
void Debugger::onChangeDebugConsoleLastline(const QString& text)
|
2021-07-30 23:28:58 +08:00
|
|
|
{
|
|
|
|
//pMainWindow->changeDebugOutputLastline(text);
|
|
|
|
pMainWindow->addDebugOutput(text);
|
|
|
|
}
|
|
|
|
|
2021-07-26 18:22:09 +08:00
|
|
|
int Debugger::leftPageIndexBackup() const
|
|
|
|
{
|
|
|
|
return mLeftPageIndexBackup;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Debugger::setLeftPageIndexBackup(int leftPageIndexBackup)
|
|
|
|
{
|
|
|
|
mLeftPageIndexBackup = leftPageIndexBackup;
|
|
|
|
}
|
|
|
|
|
2021-07-26 11:47:54 +08:00
|
|
|
bool Debugger::executing() const
|
|
|
|
{
|
|
|
|
return mExecuting;
|
|
|
|
}
|
|
|
|
|
2021-07-27 00:14:24 +08:00
|
|
|
DebugReader::DebugReader(Debugger* debugger, QObject *parent) : QThread(parent),
|
|
|
|
mStartSemaphore(0)
|
2021-07-03 21:57:50 +08:00
|
|
|
{
|
2021-07-25 00:26:13 +08:00
|
|
|
mDebugger = debugger;
|
2021-07-27 00:14:24 +08:00
|
|
|
mProcess = nullptr;
|
|
|
|
mUseUTF8 = false;
|
2021-07-31 20:19:45 +08:00
|
|
|
mCmdRunning = false;
|
|
|
|
mInvalidateAllVars = false;
|
2021-07-03 21:57:50 +08:00
|
|
|
}
|
|
|
|
|
2021-11-24 17:53:25 +08:00
|
|
|
void DebugReader::postCommand(const QString &Command, const QString &Params,
|
|
|
|
DebugCommandSource Source)
|
2021-07-19 23:02:32 +08:00
|
|
|
{
|
|
|
|
QMutexLocker locker(&mCmdQueueMutex);
|
|
|
|
PDebugCommand pCmd = std::make_shared<DebugCommand>();
|
|
|
|
pCmd->command = Command;
|
|
|
|
pCmd->params = Params;
|
|
|
|
pCmd->source = Source;
|
|
|
|
mCmdQueue.enqueue(pCmd);
|
2021-07-30 23:28:58 +08:00
|
|
|
// if (!mCmdRunning)
|
2021-11-24 17:53:25 +08:00
|
|
|
// runNextCmd();
|
2021-07-19 23:02:32 +08:00
|
|
|
}
|
|
|
|
|
2021-11-24 17:53:25 +08:00
|
|
|
void DebugReader::registerInferiorStoppedCommand(const QString &Command, const QString &Params)
|
2021-07-03 21:57:50 +08:00
|
|
|
{
|
2021-07-19 23:02:32 +08:00
|
|
|
QMutexLocker locker(&mCmdQueueMutex);
|
2021-11-24 17:53:25 +08:00
|
|
|
PDebugCommand pCmd = std::make_shared<DebugCommand>();
|
|
|
|
pCmd->command = Command;
|
|
|
|
pCmd->params = Params;
|
|
|
|
pCmd->source = DebugCommandSource::Other;
|
|
|
|
mInferiorStoppedHookCommands.append(pCmd);
|
2021-07-18 00:18:07 +08:00
|
|
|
}
|
|
|
|
|
2021-11-24 17:53:25 +08:00
|
|
|
void DebugReader::clearCmdQueue()
|
2021-07-18 00:18:07 +08:00
|
|
|
{
|
2021-11-24 17:53:25 +08:00
|
|
|
QMutexLocker locker(&mCmdQueueMutex);
|
|
|
|
mCmdQueue.clear();
|
2021-07-18 00:18:07 +08:00
|
|
|
}
|
|
|
|
|
2021-11-12 10:51:00 +08:00
|
|
|
void DebugReader::processConsoleOutput(const QByteArray& line)
|
2021-07-18 00:18:07 +08:00
|
|
|
{
|
2021-11-10 17:05:37 +08:00
|
|
|
if (line.length()>3 && line.startsWith("~\"") && line.endsWith("\"")) {
|
2021-11-12 10:51:00 +08:00
|
|
|
mConsoleOutput.append(QString::fromLocal8Bit(line.mid(2,line.length()-3)));
|
2021-11-10 17:05:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-12 10:51:00 +08:00
|
|
|
void DebugReader::processResult(const QByteArray &result)
|
2021-11-10 17:05:37 +08:00
|
|
|
{
|
2021-11-20 07:53:39 +08:00
|
|
|
GDBMIResultParser parser;
|
|
|
|
GDBMIResultType resultType;
|
|
|
|
GDBMIResultParser::ParseValue parseValue;
|
|
|
|
bool parseOk = parser.parse(result,resultType,parseValue);
|
|
|
|
if (!parseOk)
|
|
|
|
return;
|
|
|
|
switch(resultType) {
|
2021-11-23 21:08:33 +08:00
|
|
|
case GDBMIResultType::BreakpointTable:
|
|
|
|
case GDBMIResultType::Frame:
|
|
|
|
case GDBMIResultType::Locals:
|
|
|
|
break;
|
2021-11-20 07:53:39 +08:00
|
|
|
case GDBMIResultType::Breakpoint:
|
|
|
|
handleBreakpoint(parseValue.object());
|
|
|
|
return;
|
2021-11-23 21:08:33 +08:00
|
|
|
case GDBMIResultType::FrameStack:
|
|
|
|
handleStack(parseValue.array());
|
|
|
|
return;
|
|
|
|
case GDBMIResultType::LocalVariables:
|
|
|
|
handleLocalVariables(parseValue.array());
|
|
|
|
return;
|
|
|
|
case GDBMIResultType::Evaluation:
|
|
|
|
handleEvaluation(parseValue.value());
|
|
|
|
return;
|
2021-11-20 07:53:39 +08:00
|
|
|
}
|
|
|
|
|
2021-11-10 17:05:37 +08:00
|
|
|
}
|
|
|
|
|
2021-11-21 10:36:50 +08:00
|
|
|
void DebugReader::processExecAsyncRecord(const QByteArray &line)
|
2021-11-10 17:05:37 +08:00
|
|
|
{
|
2021-11-21 10:36:50 +08:00
|
|
|
QByteArray result;
|
|
|
|
GDBMIResultParser::ParseObject multiValues;
|
|
|
|
GDBMIResultParser parser;
|
|
|
|
if (!parser.parseAsyncResult(line,result,multiValues))
|
|
|
|
return;
|
2021-11-24 17:53:25 +08:00
|
|
|
qDebug()<<result<<line;
|
2021-11-21 10:36:50 +08:00
|
|
|
if (result == "running") {
|
2021-11-24 10:07:35 +08:00
|
|
|
mInferiorRunning = true;
|
2021-11-24 17:53:25 +08:00
|
|
|
mCurrentAddress=0;
|
|
|
|
mCurrentFile.clear();
|
|
|
|
mCurrentLine=-1;
|
2021-11-24 10:07:35 +08:00
|
|
|
emit inferiorContinued();
|
2021-11-10 17:05:37 +08:00
|
|
|
return;
|
|
|
|
}
|
2021-11-24 17:53:25 +08:00
|
|
|
if (result == "stopped") {
|
2021-11-24 10:07:35 +08:00
|
|
|
mInferiorRunning = false;
|
2021-11-21 10:36:50 +08:00
|
|
|
QByteArray reason = multiValues["reason"].value();
|
|
|
|
if (reason == "exited") {
|
|
|
|
//inferior exited, gdb should terminate too
|
|
|
|
mProcessExited = true;
|
2021-11-10 17:05:37 +08:00
|
|
|
return;
|
2021-11-21 10:36:50 +08:00
|
|
|
}
|
|
|
|
if (reason == "exited-normally") {
|
2021-11-10 17:05:37 +08:00
|
|
|
//inferior exited, gdb should terminate too
|
|
|
|
mProcessExited = true;
|
|
|
|
return;
|
|
|
|
}
|
2021-11-24 10:07:35 +08:00
|
|
|
if (reason == "exited-signalled") {
|
|
|
|
//inferior exited, gdb should terminate too
|
|
|
|
mProcessExited = true;
|
|
|
|
mSignalReceived = true;
|
|
|
|
return;
|
|
|
|
}
|
2021-11-23 21:08:33 +08:00
|
|
|
mUpdateCPUInfo = true;
|
2021-11-24 17:53:25 +08:00
|
|
|
GDBMIResultParser::ParseValue frame(multiValues["frame"]);
|
|
|
|
if (frame.isValid()) {
|
|
|
|
GDBMIResultParser::ParseObject frameObj = frame.object();
|
|
|
|
mCurrentAddress = frameObj["addr"].hexValue();
|
|
|
|
mCurrentLine = frameObj["line"].intValue();
|
|
|
|
mCurrentFile = frameObj["fullname"].pathValue();
|
|
|
|
}
|
|
|
|
qDebug()<<mCurrentFile<<mCurrentLine;
|
2021-11-21 10:36:50 +08:00
|
|
|
if (reason == "signal-received") {
|
2021-11-23 21:08:33 +08:00
|
|
|
mSignalReceived = true;
|
2021-11-10 17:05:37 +08:00
|
|
|
}
|
2021-11-24 17:53:25 +08:00
|
|
|
runInferiorStoppedHook();
|
|
|
|
if (mCurrentCmd && mCurrentCmd->source == DebugCommandSource::Console)
|
|
|
|
emit inferiorStopped(mCurrentFile, mCurrentLine,false);
|
|
|
|
else
|
|
|
|
emit inferiorStopped(mCurrentFile, mCurrentLine,true);
|
2021-11-10 17:05:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-12 10:51:00 +08:00
|
|
|
void DebugReader::processError(const QByteArray &errorLine)
|
2021-11-10 17:05:37 +08:00
|
|
|
{
|
2021-11-12 10:51:00 +08:00
|
|
|
mConsoleOutput.append(QString::fromLocal8Bit(errorLine));
|
2021-07-18 00:18:07 +08:00
|
|
|
}
|
|
|
|
|
2021-11-12 10:51:00 +08:00
|
|
|
void DebugReader::processResultRecord(const QByteArray &line)
|
2021-11-10 12:57:18 +08:00
|
|
|
{
|
|
|
|
if (line.startsWith("^exit")) {
|
2021-11-10 17:05:37 +08:00
|
|
|
mProcessExited = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (line.startsWith("^error")) {
|
|
|
|
processError(line);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (line.startsWith("^done")
|
|
|
|
|| line.startsWith("^running")) {
|
|
|
|
int pos = line.indexOf(',');
|
|
|
|
if (pos>=0) {
|
2021-11-12 10:51:00 +08:00
|
|
|
QByteArray result = line.mid(pos+1);
|
2021-11-10 17:05:37 +08:00
|
|
|
processResult(result);
|
|
|
|
}
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
if (line.startsWith("^connected")) {
|
|
|
|
//TODO: connected to remote target
|
2021-11-10 12:57:18 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-12 10:51:00 +08:00
|
|
|
void DebugReader::processDebugOutput(const QByteArray& debugOutput)
|
2021-07-18 00:18:07 +08:00
|
|
|
{
|
|
|
|
// Only update once per update at most
|
2021-07-18 08:52:53 +08:00
|
|
|
//WatchView.Items.BeginUpdate;
|
|
|
|
|
|
|
|
if (mInvalidateAllVars) {
|
|
|
|
//invalidate all vars when there's first output
|
2021-08-31 11:13:12 +08:00
|
|
|
mDebugger->removeWatchVars(false);
|
2021-07-18 08:52:53 +08:00
|
|
|
mInvalidateAllVars = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit parseStarted();
|
|
|
|
|
2021-11-10 17:05:37 +08:00
|
|
|
mConsoleOutput.clear();
|
2021-11-24 17:53:25 +08:00
|
|
|
mFullOutput.clear();
|
2021-11-10 17:05:37 +08:00
|
|
|
|
2021-11-23 21:08:33 +08:00
|
|
|
mSignalReceived = false;
|
|
|
|
mUpdateCPUInfo = false;
|
2021-11-24 10:07:35 +08:00
|
|
|
mReceivedSFWarning = false;
|
2021-07-18 08:52:53 +08:00
|
|
|
|
2021-11-12 10:51:00 +08:00
|
|
|
QList<QByteArray> lines = splitByteArrayToLines(debugOutput);
|
2021-11-10 12:29:02 +08:00
|
|
|
|
2021-11-10 12:57:18 +08:00
|
|
|
for (int i=0;i<lines.count();i++) {
|
2021-11-12 10:51:00 +08:00
|
|
|
QByteArray line = lines[i];
|
2021-11-24 17:53:25 +08:00
|
|
|
mFullOutput.append(line);
|
2021-11-10 12:29:02 +08:00
|
|
|
line = removeToken(line);
|
|
|
|
if (line.isEmpty()) {
|
|
|
|
continue;
|
|
|
|
}
|
2021-11-12 10:51:00 +08:00
|
|
|
switch (line[0]) {
|
2021-11-10 12:29:02 +08:00
|
|
|
case '~': // console stream output
|
2021-11-10 17:05:37 +08:00
|
|
|
processConsoleOutput(line);
|
|
|
|
break;
|
2021-11-10 12:29:02 +08:00
|
|
|
case '@': // target stream output
|
|
|
|
case '&': // log stream output
|
|
|
|
break;
|
|
|
|
case '^': // result record
|
2021-11-10 12:57:18 +08:00
|
|
|
processResultRecord(line);
|
|
|
|
break;
|
|
|
|
case '*': // exec async output
|
2021-11-10 17:05:37 +08:00
|
|
|
processExecAsyncRecord(line);
|
|
|
|
break;
|
2021-11-10 12:57:18 +08:00
|
|
|
case '+': // status async output
|
|
|
|
case '=': // notify async output
|
|
|
|
break;
|
2021-11-10 12:29:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-18 08:52:53 +08:00
|
|
|
emit parseFinished();
|
|
|
|
}
|
|
|
|
|
2021-11-24 17:53:25 +08:00
|
|
|
void DebugReader::runInferiorStoppedHook()
|
|
|
|
{
|
|
|
|
foreach (const PDebugCommand& cmd, mInferiorStoppedHookCommands) {
|
|
|
|
mCmdQueue.push_front(cmd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-18 08:52:53 +08:00
|
|
|
QString DebugReader::processEvalOutput()
|
|
|
|
{
|
|
|
|
int indent = 0;
|
|
|
|
|
|
|
|
// First line gets special treatment
|
2021-11-24 17:53:25 +08:00
|
|
|
QString result ="";
|
2021-07-18 08:52:53 +08:00
|
|
|
if (result.startsWith('{'))
|
|
|
|
indent+=4;
|
|
|
|
|
|
|
|
// Collect all data, add formatting in between
|
2021-11-24 17:53:25 +08:00
|
|
|
// AnnotationType nextAnnotation;
|
|
|
|
// QString nextLine;
|
|
|
|
// bool shouldExit = false;
|
|
|
|
// do {
|
|
|
|
// nextAnnotation = getNextAnnotation();
|
|
|
|
// nextLine = getNextLine();
|
|
|
|
// switch(nextAnnotation) {
|
|
|
|
// // Change indent if { or } is found
|
|
|
|
// case AnnotationType::TFieldBegin:
|
|
|
|
// result += "\r\n" + QString(4,' ');
|
|
|
|
// break;
|
|
|
|
// case AnnotationType::TFieldValue:
|
|
|
|
// if (nextLine.startsWith('{') && (peekNextAnnotation() !=
|
|
|
|
// AnnotationType::TArrayBegin))
|
|
|
|
// indent+=4;
|
|
|
|
// break;
|
|
|
|
// case AnnotationType::TFieldEnd:
|
|
|
|
// if (nextLine.endsWith('}')) {
|
|
|
|
// indent-=4;
|
|
|
|
// result += "\r\n" + QString(4,' ');
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
// case AnnotationType::TEOF:
|
|
|
|
// case AnnotationType::TValueHistoryEnd:
|
|
|
|
// case AnnotationType::TDisplayEnd:
|
|
|
|
// shouldExit = true;
|
|
|
|
// default:
|
|
|
|
// break;
|
|
|
|
// }
|
|
|
|
// result += nextLine;
|
|
|
|
// } while (!shouldExit);
|
2021-08-01 01:06:43 +08:00
|
|
|
return result;
|
2021-07-18 08:52:53 +08:00
|
|
|
}
|
|
|
|
|
2021-08-01 01:06:43 +08:00
|
|
|
void DebugReader::processWatchOutput(PWatchVar watchVar)
|
2021-07-18 08:52:53 +08:00
|
|
|
{
|
2021-08-01 01:06:43 +08:00
|
|
|
// // Expand if it was expanded or if it didn't have any children
|
|
|
|
// bool ParentWasExpanded = false;
|
|
|
|
|
|
|
|
// Do not remove root node of watch variable
|
|
|
|
|
|
|
|
watchVar->children.clear();
|
2021-09-19 09:45:03 +08:00
|
|
|
watchVar->value = "";
|
2021-08-01 01:06:43 +08:00
|
|
|
// Process output parsed by ProcessEvalStruct
|
2021-09-19 14:28:30 +08:00
|
|
|
QString s = processEvalOutput();
|
2021-08-01 01:06:43 +08:00
|
|
|
|
2021-09-19 09:45:03 +08:00
|
|
|
QStringList tokens = tokenize(s);
|
|
|
|
PWatchVar parentVar = watchVar;
|
2021-09-19 14:28:30 +08:00
|
|
|
PWatchVar currentVar = watchVar;
|
2021-08-01 01:06:43 +08:00
|
|
|
|
2021-09-19 09:45:03 +08:00
|
|
|
QVector<PWatchVar> varStack;
|
|
|
|
int i=0;
|
|
|
|
while (i<tokens.length()) {
|
|
|
|
QString token = tokens[i];
|
|
|
|
QChar ch = token[0];
|
|
|
|
if (ch =='_' || (ch>='a' && ch<='z')
|
|
|
|
|| (ch>='A' && ch<='Z') || (ch>127)) {
|
2021-09-19 14:28:30 +08:00
|
|
|
//is identifier,create new child node
|
|
|
|
PWatchVar newVar = std::make_shared<WatchVar>();
|
|
|
|
newVar->parent = parentVar.get();
|
|
|
|
newVar->name = token;
|
|
|
|
newVar->fullName = parentVar->fullName + '.'+token;
|
|
|
|
newVar->value = "";
|
|
|
|
newVar->gdbIndex = -1;
|
|
|
|
parentVar->children.append(newVar);
|
|
|
|
currentVar = newVar;
|
2021-09-19 09:45:03 +08:00
|
|
|
} else if (ch == '{') {
|
|
|
|
if (parentVar->value.isEmpty()) {
|
|
|
|
parentVar->value = "{";
|
2021-08-01 01:06:43 +08:00
|
|
|
} else {
|
2021-09-19 01:58:09 +08:00
|
|
|
PWatchVar newVar = std::make_shared<WatchVar>();
|
2021-08-01 01:06:43 +08:00
|
|
|
newVar->parent = parentVar.get();
|
2021-09-19 09:45:03 +08:00
|
|
|
if (parentVar) {
|
|
|
|
int count = parentVar->children.count();
|
|
|
|
newVar->name = QString("[%1]").arg(count);
|
2021-09-19 14:28:30 +08:00
|
|
|
newVar->fullName = parentVar->fullName + newVar->name;
|
2021-09-19 09:45:03 +08:00
|
|
|
} else {
|
|
|
|
newVar->name = QString("[0]");
|
|
|
|
newVar->fullName = newVar->name;
|
|
|
|
}
|
|
|
|
newVar->value = "{";
|
2021-08-01 01:06:43 +08:00
|
|
|
parentVar->children.append(newVar);
|
2021-09-19 09:45:03 +08:00
|
|
|
varStack.push_back(parentVar);
|
|
|
|
parentVar = newVar;
|
|
|
|
}
|
2021-09-29 20:45:03 +08:00
|
|
|
currentVar = nullptr;
|
2021-09-19 09:45:03 +08:00
|
|
|
} else if (ch == '}') {
|
2021-09-29 20:45:03 +08:00
|
|
|
currentVar = nullptr;
|
2021-09-19 09:45:03 +08:00
|
|
|
PWatchVar newVar = std::make_shared<WatchVar>();
|
|
|
|
newVar->parent = parentVar.get();
|
|
|
|
newVar->name = "";
|
|
|
|
newVar->value = "}";
|
|
|
|
newVar->gdbIndex = -1;
|
|
|
|
parentVar->children.append(newVar);
|
|
|
|
if (!varStack.isEmpty()) {
|
|
|
|
parentVar = varStack.back();
|
|
|
|
varStack.pop_back();
|
|
|
|
}
|
2021-09-19 14:28:30 +08:00
|
|
|
} else if (ch == '=') {
|
|
|
|
// just skip it
|
|
|
|
} else if (ch == ',') {
|
2021-09-29 20:45:03 +08:00
|
|
|
currentVar = nullptr;
|
2021-09-19 09:45:03 +08:00
|
|
|
} else {
|
2021-09-19 14:28:30 +08:00
|
|
|
if (currentVar) {
|
2021-09-29 20:45:03 +08:00
|
|
|
if (currentVar->value.isEmpty()) {
|
|
|
|
currentVar->value = token;
|
|
|
|
} else {
|
|
|
|
currentVar->value += " "+token;
|
|
|
|
}
|
2021-09-19 09:45:03 +08:00
|
|
|
} else {
|
2021-09-19 14:28:30 +08:00
|
|
|
PWatchVar newVar = std::make_shared<WatchVar>();
|
|
|
|
newVar->parent = parentVar.get();
|
|
|
|
newVar->name = QString("[%1]")
|
|
|
|
.arg(parentVar->children.count());
|
|
|
|
newVar->fullName = parentVar->fullName + newVar->name;
|
|
|
|
newVar->value = token;
|
|
|
|
newVar->gdbIndex = -1;
|
|
|
|
parentVar->children.append(newVar);
|
2021-08-01 01:06:43 +08:00
|
|
|
}
|
|
|
|
}
|
2021-09-19 09:45:03 +08:00
|
|
|
i++;
|
2021-08-01 01:06:43 +08:00
|
|
|
}
|
2021-09-19 09:45:03 +08:00
|
|
|
// add placeholder name for variable name so we can format structs using one rule
|
|
|
|
|
|
|
|
// Add children based on indent
|
|
|
|
// QStringList lines = TextToLines(s);
|
|
|
|
|
|
|
|
// for (const QString& line:lines) {
|
|
|
|
// // Format node text. Remove trailing comma
|
|
|
|
// QString nodeText = line.trimmed();
|
|
|
|
// if (nodeText.endsWith(',')) {
|
|
|
|
// nodeText.remove(nodeText.length()-1,1);
|
|
|
|
// }
|
|
|
|
|
|
|
|
// if (nodeText.endsWith('{')) { // new member struct
|
|
|
|
// if (parentVar->text.isEmpty()) { // root node, replace text only
|
|
|
|
// parentVar->text = nodeText;
|
|
|
|
// } else {
|
|
|
|
// PWatchVar newVar = std::make_shared<WatchVar>();
|
|
|
|
// newVar->parent = parentVar.get();
|
|
|
|
// newVar->name = "";
|
|
|
|
// newVar->text = nodeText;
|
|
|
|
// newVar->gdbIndex = -1;
|
|
|
|
// parentVar->children.append(newVar);
|
|
|
|
// varStack.push_back(parentVar);
|
|
|
|
// parentVar = newVar;
|
|
|
|
// }
|
|
|
|
// } else if (nodeText.startsWith('}')) { // end of struct, change parent
|
|
|
|
// PWatchVar newVar = std::make_shared<WatchVar>();
|
|
|
|
// newVar->parent = parentVar.get();
|
|
|
|
// newVar->name = "";
|
|
|
|
// newVar->text = "}";
|
|
|
|
// newVar->gdbIndex = -1;
|
|
|
|
// parentVar->children.append(newVar);
|
|
|
|
// if (!varStack.isEmpty()) {
|
|
|
|
// parentVar = varStack.back();
|
|
|
|
// varStack.pop_back();
|
|
|
|
// }
|
|
|
|
// } else { // next parent member/child
|
|
|
|
// if (parentVar->text.isEmpty()) { // root node, replace text only
|
|
|
|
// parentVar->text = nodeText;
|
|
|
|
// } else {
|
|
|
|
// PWatchVar newVar = std::make_shared<WatchVar>();
|
|
|
|
// newVar->parent = parentVar.get();
|
|
|
|
// newVar->name = "";
|
|
|
|
// newVar->text = nodeText;
|
|
|
|
// newVar->gdbIndex = -1;
|
|
|
|
// parentVar->children.append(newVar);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
2021-08-01 01:06:43 +08:00
|
|
|
// TODO: remember expansion state
|
2021-07-17 19:32:23 +08:00
|
|
|
}
|
|
|
|
|
2021-07-19 23:02:32 +08:00
|
|
|
void DebugReader::runNextCmd()
|
|
|
|
{
|
|
|
|
QMutexLocker locker(&mCmdQueueMutex);
|
|
|
|
|
|
|
|
if (mCurrentCmd) {
|
|
|
|
mCurrentCmd.reset();
|
2021-11-24 17:53:25 +08:00
|
|
|
emit cmdFinished();
|
2021-07-19 23:02:32 +08:00
|
|
|
}
|
2021-11-24 17:53:25 +08:00
|
|
|
if (mCmdQueue.isEmpty())
|
|
|
|
return;
|
2021-07-19 23:02:32 +08:00
|
|
|
|
|
|
|
PDebugCommand pCmd = mCmdQueue.dequeue();
|
|
|
|
mCmdRunning = true;
|
2021-09-19 14:28:30 +08:00
|
|
|
mCurrentCmd = pCmd;
|
2021-11-24 17:53:25 +08:00
|
|
|
emit cmdStarted();
|
2021-07-19 23:02:32 +08:00
|
|
|
|
|
|
|
QByteArray s;
|
2021-11-10 21:28:08 +08:00
|
|
|
s=pCmd->command.toLocal8Bit();
|
2021-07-19 23:02:32 +08:00
|
|
|
if (!pCmd->params.isEmpty()) {
|
2021-11-10 21:28:08 +08:00
|
|
|
s+= ' '+pCmd->params.toLocal8Bit();
|
2021-07-19 23:02:32 +08:00
|
|
|
}
|
|
|
|
s+= "\n";
|
2021-07-27 00:14:24 +08:00
|
|
|
if (mProcess->write(s)<0) {
|
2021-07-19 23:02:32 +08:00
|
|
|
emit writeToDebugFailed();
|
|
|
|
}
|
|
|
|
|
|
|
|
// if devDebugger.ShowCommandLog or pCmd^.ShowInConsole then begin
|
2021-11-24 17:53:25 +08:00
|
|
|
if (pSettings->debugger().showCommandLog() ) {
|
2021-07-19 23:02:32 +08:00
|
|
|
//update debug console
|
2021-07-30 23:28:58 +08:00
|
|
|
if (!pSettings->debugger().showAnnotations()) {
|
|
|
|
emit changeDebugConsoleLastLine("(gdb)"+pCmd->command + ' ' + pCmd->params);
|
2021-07-19 23:02:32 +08:00
|
|
|
} else {
|
2021-07-30 23:28:58 +08:00
|
|
|
emit changeDebugConsoleLastLine("(gdb)"+pCmd->command + ' ' + pCmd->params);
|
2021-07-19 23:02:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-19 09:45:03 +08:00
|
|
|
QStringList DebugReader::tokenize(const QString &s)
|
|
|
|
{
|
|
|
|
QStringList result;
|
|
|
|
int tStart,tEnd;
|
|
|
|
int i=0;
|
|
|
|
while (i<s.length()) {
|
|
|
|
QChar ch = s[i];
|
|
|
|
if (ch == ' ' || ch == '\t'
|
|
|
|
|| ch == '\r'
|
|
|
|
|| ch == '\n') {
|
|
|
|
// if (!current.isEmpty()) {
|
|
|
|
// result.append(current);
|
|
|
|
// current = "";
|
|
|
|
// }
|
|
|
|
i++;
|
|
|
|
continue;
|
|
|
|
} else if (ch == '\'') {
|
|
|
|
tStart = i;
|
|
|
|
i++; //skip \'
|
|
|
|
while (i<s.length()) {
|
|
|
|
if (s[i]=='\'') {
|
|
|
|
i++;
|
|
|
|
break;
|
|
|
|
} else if (s[i] == '\\') {
|
|
|
|
i+=2;
|
2021-09-19 14:28:30 +08:00
|
|
|
continue;
|
2021-09-19 09:45:03 +08:00
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
tEnd = std::min(i,s.length());
|
|
|
|
result.append(s.mid(tStart,tEnd-tStart));
|
2021-09-19 14:28:30 +08:00
|
|
|
} else if (ch == '\"') {
|
2021-09-19 09:45:03 +08:00
|
|
|
tStart = i;
|
|
|
|
i++; //skip \'
|
|
|
|
while (i<s.length()) {
|
|
|
|
if (s[i]=='\"') {
|
|
|
|
i++;
|
|
|
|
break;
|
|
|
|
} else if (s[i] == '\\') {
|
|
|
|
i+=2;
|
2021-09-19 14:28:30 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
tEnd = std::min(i,s.length());
|
|
|
|
result.append(s.mid(tStart,tEnd-tStart));
|
|
|
|
} else if (ch == '<') {
|
|
|
|
tStart = i;
|
|
|
|
i++;
|
|
|
|
while (i<s.length()) {
|
|
|
|
if (s[i]=='>') {
|
|
|
|
i++;
|
2021-09-19 09:45:03 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
tEnd = std::min(i,s.length());
|
|
|
|
result.append(s.mid(tStart,tEnd-tStart));
|
2021-09-29 20:45:03 +08:00
|
|
|
} else if (ch == '(') {
|
|
|
|
tStart = i;
|
|
|
|
i++;
|
|
|
|
while (i<s.length()) {
|
|
|
|
if (s[i]==')') {
|
|
|
|
i++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
tEnd = std::min(i,s.length());
|
|
|
|
result.append(s.mid(tStart,tEnd-tStart));
|
2021-09-29 19:40:03 +08:00
|
|
|
} else if (ch == '_' ||
|
|
|
|
ch == '.' ||
|
|
|
|
ch == '+' ||
|
|
|
|
ch == '-' ||
|
|
|
|
ch.isLetterOrNumber() ) {
|
2021-09-19 09:45:03 +08:00
|
|
|
tStart = i;
|
|
|
|
while (i<s.length()) {
|
2021-09-29 19:40:03 +08:00
|
|
|
ch = s[i];
|
|
|
|
if (!(ch == '_' ||
|
|
|
|
ch == '.' ||
|
|
|
|
ch == '+' ||
|
|
|
|
ch == '-' ||
|
|
|
|
ch.isLetterOrNumber() ))
|
2021-09-19 09:45:03 +08:00
|
|
|
break;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
tEnd = std::min(i,s.length());
|
|
|
|
result.append(s.mid(tStart,tEnd-tStart));
|
|
|
|
} else {
|
|
|
|
result.append(s[i]);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-11-24 17:53:25 +08:00
|
|
|
bool DebugReader::outputTerminated(const QByteArray &text)
|
|
|
|
{
|
|
|
|
QStringList lines = textToLines(QString::fromUtf8(text));
|
|
|
|
foreach (const QString& line,lines) {
|
|
|
|
if (line.trimmed() == "(gdb)")
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-11-21 08:38:03 +08:00
|
|
|
void DebugReader::handleBreakpoint(const GDBMIResultParser::ParseObject& breakpoint)
|
2021-11-12 10:51:00 +08:00
|
|
|
{
|
2021-11-21 08:38:03 +08:00
|
|
|
// gdb use system encoding for file path
|
2021-11-23 21:08:33 +08:00
|
|
|
QString filename = breakpoint["fullname"].value();
|
2021-11-21 08:38:03 +08:00
|
|
|
int line = breakpoint["line"].intValue();
|
|
|
|
int number = breakpoint["number"].intValue();
|
|
|
|
emit breakpointInfoGetted(filename, line , number);
|
2021-11-12 10:51:00 +08:00
|
|
|
}
|
|
|
|
|
2021-11-23 21:08:33 +08:00
|
|
|
void DebugReader::handleStack(const QList<GDBMIResultParser::ParseValue> & stack)
|
|
|
|
{
|
|
|
|
mDebugger->backtraceModel()->clear();
|
|
|
|
foreach (const GDBMIResultParser::ParseValue& frameValue, stack) {
|
|
|
|
GDBMIResultParser::ParseObject frameObject = frameValue.object();
|
|
|
|
PTrace trace = std::make_shared<Trace>();
|
|
|
|
trace->funcname = frameObject["func"].value();
|
|
|
|
trace->filename = frameObject["fullname"].pathValue();
|
|
|
|
trace->line = frameObject["fullname"].intValue();
|
|
|
|
trace->level = frameObject["level"].intValue(0);
|
|
|
|
trace->address = frameObject["addr"].value();
|
|
|
|
mDebugger->backtraceModel()->addTrace(trace);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DebugReader::handleLocalVariables(const QList<GDBMIResultParser::ParseValue> &variables)
|
|
|
|
{
|
2021-11-24 10:07:35 +08:00
|
|
|
QStringList locals;
|
2021-11-23 21:08:33 +08:00
|
|
|
foreach (const GDBMIResultParser::ParseValue& varValue, variables) {
|
|
|
|
GDBMIResultParser::ParseObject varObject = varValue.object();
|
2021-11-24 10:07:35 +08:00
|
|
|
locals.append(QString("%1 = %2")
|
2021-11-23 21:08:33 +08:00
|
|
|
.arg(varObject["name"].value(),varObject["value"].value()));
|
|
|
|
}
|
2021-11-24 10:07:35 +08:00
|
|
|
emit localsUpdated(locals);
|
2021-11-23 21:08:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void DebugReader::handleEvaluation(const QString &value)
|
|
|
|
{
|
2021-11-24 10:07:35 +08:00
|
|
|
emit evalUpdated(value);
|
2021-11-23 21:08:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void DebugReader::handleMemory(const QList<GDBMIResultParser::ParseValue> &rows)
|
|
|
|
{
|
2021-11-24 10:07:35 +08:00
|
|
|
QStringList memory;
|
2021-11-23 21:08:33 +08:00
|
|
|
foreach (const GDBMIResultParser::ParseValue& row, rows) {
|
|
|
|
GDBMIResultParser::ParseObject rowObject = row.object();
|
|
|
|
QList<GDBMIResultParser::ParseValue> data = rowObject["data"].array();
|
|
|
|
QStringList values;
|
|
|
|
foreach (const GDBMIResultParser::ParseValue& val, data) {
|
|
|
|
values.append(val.value());
|
|
|
|
}
|
2021-11-24 10:07:35 +08:00
|
|
|
memory.append(QString("%1 %2")
|
2021-11-23 21:08:33 +08:00
|
|
|
.arg(rowObject["addr"].value(),values.join(" ")));
|
|
|
|
}
|
2021-11-24 10:07:35 +08:00
|
|
|
emit memoryUpdated(memory);
|
2021-11-23 21:08:33 +08:00
|
|
|
}
|
|
|
|
|
2021-11-12 10:51:00 +08:00
|
|
|
QByteArray DebugReader::removeToken(const QByteArray &line)
|
2021-11-10 17:05:37 +08:00
|
|
|
{
|
|
|
|
int p=0;
|
|
|
|
while (p<line.length()) {
|
2021-11-10 22:00:01 +08:00
|
|
|
QChar ch=line[p];
|
|
|
|
if (ch<'0' || ch>'9') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
p++;
|
2021-11-10 17:05:37 +08:00
|
|
|
}
|
2021-11-10 22:00:01 +08:00
|
|
|
if (p<line.length())
|
|
|
|
return line.mid(p);
|
|
|
|
return line;
|
2021-11-10 17:05:37 +08:00
|
|
|
}
|
|
|
|
|
2021-11-24 17:53:25 +08:00
|
|
|
const QStringList &DebugReader::fullOutput() const
|
2021-11-23 21:08:33 +08:00
|
|
|
{
|
2021-11-24 17:53:25 +08:00
|
|
|
return mFullOutput;
|
2021-11-23 21:08:33 +08:00
|
|
|
}
|
|
|
|
|
2021-11-24 17:53:25 +08:00
|
|
|
bool DebugReader::receivedSFWarning() const
|
2021-11-23 21:08:33 +08:00
|
|
|
{
|
2021-11-24 17:53:25 +08:00
|
|
|
return mReceivedSFWarning;
|
2021-11-23 21:08:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DebugReader::updateCPUInfo() const
|
|
|
|
{
|
|
|
|
return mUpdateCPUInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
const PDebugCommand &DebugReader::currentCmd() const
|
|
|
|
{
|
|
|
|
return mCurrentCmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QStringList &DebugReader::consoleOutput() const
|
|
|
|
{
|
|
|
|
return mConsoleOutput;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DebugReader::signalReceived() const
|
|
|
|
{
|
|
|
|
return mSignalReceived;
|
|
|
|
}
|
|
|
|
|
2021-11-10 17:05:37 +08:00
|
|
|
bool DebugReader::processExited() const
|
|
|
|
{
|
|
|
|
return mProcessExited;
|
|
|
|
}
|
|
|
|
|
2021-07-31 20:19:45 +08:00
|
|
|
bool DebugReader::invalidateAllVars() const
|
|
|
|
{
|
|
|
|
return mInvalidateAllVars;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DebugReader::setInvalidateAllVars(bool invalidateAllVars)
|
|
|
|
{
|
|
|
|
mInvalidateAllVars = invalidateAllVars;
|
|
|
|
}
|
|
|
|
|
2021-07-25 00:26:13 +08:00
|
|
|
QString DebugReader::debuggerPath() const
|
|
|
|
{
|
|
|
|
return mDebuggerPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DebugReader::setDebuggerPath(const QString &debuggerPath)
|
|
|
|
{
|
|
|
|
mDebuggerPath = debuggerPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DebugReader::stopDebug()
|
|
|
|
{
|
|
|
|
mStop = true;
|
|
|
|
}
|
|
|
|
|
2021-08-29 22:08:43 +08:00
|
|
|
bool DebugReader::commandRunning()
|
|
|
|
{
|
|
|
|
return !mCmdQueue.isEmpty();
|
|
|
|
}
|
|
|
|
|
2021-11-24 17:53:25 +08:00
|
|
|
void DebugReader::waitStart()
|
2021-11-10 17:05:37 +08:00
|
|
|
{
|
|
|
|
mStartSemaphore.acquire(1);
|
|
|
|
}
|
|
|
|
|
2021-07-19 23:02:32 +08:00
|
|
|
void DebugReader::run()
|
|
|
|
{
|
|
|
|
mStop = false;
|
2021-11-24 10:07:35 +08:00
|
|
|
mInferiorRunning = false;
|
2021-11-10 17:05:37 +08:00
|
|
|
mProcessExited = false;
|
2021-07-19 23:02:32 +08:00
|
|
|
bool errorOccurred = false;
|
2021-07-25 00:26:13 +08:00
|
|
|
QString cmd = mDebuggerPath;
|
2021-10-13 17:20:31 +08:00
|
|
|
// QString arguments = "--annotate=2";
|
2021-11-10 12:29:02 +08:00
|
|
|
QString arguments = "--interpret=mi --silent";
|
2021-07-25 00:26:13 +08:00
|
|
|
QString workingDir = QFileInfo(mDebuggerPath).path();
|
|
|
|
|
2021-07-27 00:14:24 +08:00
|
|
|
mProcess = new QProcess();
|
|
|
|
mProcess->setProgram(cmd);
|
|
|
|
mProcess->setArguments(QProcess::splitCommand(arguments));
|
2021-10-13 17:20:31 +08:00
|
|
|
mProcess->setProcessChannelMode(QProcess::MergedChannels);
|
2021-10-12 19:39:24 +08:00
|
|
|
QString cmdDir = extractFileDir(cmd);
|
|
|
|
if (!cmdDir.isEmpty()) {
|
|
|
|
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
|
|
|
QString path = env.value("PATH");
|
2021-10-13 17:20:31 +08:00
|
|
|
cmdDir.replace("/",QDir::separator());
|
2021-10-12 19:39:24 +08:00
|
|
|
if (path.isEmpty()) {
|
|
|
|
path = cmdDir;
|
|
|
|
} else {
|
|
|
|
path = cmdDir + PATH_SEPARATOR + path;
|
|
|
|
}
|
|
|
|
env.insert("PATH",path);
|
|
|
|
mProcess->setProcessEnvironment(env);
|
|
|
|
}
|
2021-07-27 00:14:24 +08:00
|
|
|
mProcess->setWorkingDirectory(workingDir);
|
2021-07-19 23:02:32 +08:00
|
|
|
|
2021-07-27 00:14:24 +08:00
|
|
|
connect(mProcess, &QProcess::errorOccurred,
|
2021-07-19 23:02:32 +08:00
|
|
|
[&](){
|
|
|
|
errorOccurred= true;
|
|
|
|
});
|
2021-10-13 17:20:31 +08:00
|
|
|
QByteArray buffer;
|
|
|
|
QByteArray readed;
|
|
|
|
|
2021-07-27 00:14:24 +08:00
|
|
|
mProcess->start();
|
|
|
|
mProcess->waitForStarted(5000);
|
|
|
|
mStartSemaphore.release(1);
|
2021-07-19 23:02:32 +08:00
|
|
|
while (true) {
|
2021-08-01 01:06:43 +08:00
|
|
|
mProcess->waitForFinished(1);
|
2021-07-27 00:14:24 +08:00
|
|
|
if (mProcess->state()!=QProcess::Running) {
|
2021-07-19 23:02:32 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (mStop) {
|
2021-08-01 23:24:37 +08:00
|
|
|
mProcess->closeReadChannel(QProcess::StandardOutput);
|
|
|
|
mProcess->closeReadChannel(QProcess::StandardError);
|
|
|
|
mProcess->closeWriteChannel();
|
2021-07-27 00:14:24 +08:00
|
|
|
mProcess->terminate();
|
2021-08-01 23:24:37 +08:00
|
|
|
mProcess->kill();
|
2021-07-31 14:04:43 +08:00
|
|
|
break;
|
2021-07-19 23:02:32 +08:00
|
|
|
}
|
|
|
|
if (errorOccurred)
|
|
|
|
break;
|
2021-07-30 23:28:58 +08:00
|
|
|
readed = mProcess->readAll();
|
|
|
|
buffer += readed;
|
2021-11-10 12:29:02 +08:00
|
|
|
|
2021-11-24 17:53:25 +08:00
|
|
|
if ( readed.endsWith("\n")&& outputTerminated(buffer)) {
|
2021-11-12 10:51:00 +08:00
|
|
|
processDebugOutput(buffer);
|
2021-07-30 23:28:58 +08:00
|
|
|
buffer.clear();
|
2021-07-19 23:02:32 +08:00
|
|
|
mCmdRunning = false;
|
|
|
|
runNextCmd();
|
2021-07-30 23:28:58 +08:00
|
|
|
} else if (!mCmdRunning && readed.isEmpty()){
|
|
|
|
runNextCmd();
|
2021-08-01 01:06:43 +08:00
|
|
|
} else if (readed.isEmpty()){
|
2021-10-02 17:01:08 +08:00
|
|
|
msleep(1);
|
2021-07-19 23:02:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (errorOccurred) {
|
2021-07-27 00:14:24 +08:00
|
|
|
emit processError(mProcess->error());
|
2021-07-19 23:02:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-17 19:32:23 +08:00
|
|
|
|
|
|
|
|
2021-07-24 11:18:25 +08:00
|
|
|
BreakpointModel::BreakpointModel(QObject *parent):QAbstractTableModel(parent)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-07-17 19:32:23 +08:00
|
|
|
int BreakpointModel::rowCount(const QModelIndex &) const
|
|
|
|
{
|
|
|
|
return mList.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
int BreakpointModel::columnCount(const QModelIndex &) const
|
|
|
|
{
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant BreakpointModel::data(const QModelIndex &index, int role) const
|
|
|
|
{
|
|
|
|
if (!index.isValid())
|
|
|
|
return QVariant();
|
|
|
|
if (index.row()<0 || index.row() >= static_cast<int>(mList.size()))
|
|
|
|
return QVariant();
|
|
|
|
PBreakpoint breakpoint = mList[index.row()];
|
|
|
|
if (!breakpoint)
|
|
|
|
return QVariant();
|
|
|
|
switch (role) {
|
|
|
|
case Qt::DisplayRole:
|
2021-09-03 10:30:08 +08:00
|
|
|
switch (index.column()) {
|
|
|
|
case 0: {
|
2021-09-10 12:37:02 +08:00
|
|
|
return extractFileName(breakpoint->filename);
|
2021-09-03 10:30:08 +08:00
|
|
|
}
|
|
|
|
case 1:
|
|
|
|
if (breakpoint->line>0)
|
|
|
|
return breakpoint->line;
|
|
|
|
else
|
|
|
|
return "";
|
|
|
|
case 2:
|
|
|
|
return breakpoint->condition;
|
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
case Qt::ToolTipRole:
|
2021-07-17 19:32:23 +08:00
|
|
|
switch (index.column()) {
|
|
|
|
case 0:
|
|
|
|
return breakpoint->filename;
|
|
|
|
case 1:
|
|
|
|
if (breakpoint->line>0)
|
|
|
|
return breakpoint->line;
|
|
|
|
else
|
|
|
|
return "";
|
|
|
|
case 2:
|
|
|
|
return breakpoint->condition;
|
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant BreakpointModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
|
|
{
|
|
|
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
|
|
|
switch(section) {
|
|
|
|
case 0:
|
|
|
|
return tr("Filename");
|
|
|
|
case 1:
|
|
|
|
return tr("Line");
|
|
|
|
case 2:
|
|
|
|
return tr("Condition");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BreakpointModel::addBreakpoint(PBreakpoint p)
|
|
|
|
{
|
|
|
|
beginInsertRows(QModelIndex(),mList.size(),mList.size());
|
|
|
|
mList.push_back(p);
|
|
|
|
endInsertRows();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BreakpointModel::clear()
|
|
|
|
{
|
|
|
|
beginRemoveRows(QModelIndex(),0,mList.size()-1);
|
|
|
|
mList.clear();
|
|
|
|
endRemoveRows();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BreakpointModel::removeBreakpoint(int row)
|
|
|
|
{
|
|
|
|
beginRemoveRows(QModelIndex(),row,row);
|
|
|
|
mList.removeAt(row);
|
|
|
|
endRemoveRows();
|
|
|
|
}
|
|
|
|
|
2021-11-21 08:38:03 +08:00
|
|
|
void BreakpointModel::invalidateAllBreakpointNumbers()
|
|
|
|
{
|
|
|
|
foreach (PBreakpoint bp,mList) {
|
|
|
|
bp->number = -1;
|
|
|
|
}
|
|
|
|
//emit dateChanged(createIndex(0,0),)
|
|
|
|
}
|
|
|
|
|
2021-07-24 11:18:25 +08:00
|
|
|
PBreakpoint BreakpointModel::setBreakPointCondition(int index, const QString &condition)
|
|
|
|
{
|
|
|
|
PBreakpoint breakpoint = mList[index];
|
|
|
|
breakpoint->condition = condition;
|
2021-07-31 20:19:45 +08:00
|
|
|
emit dataChanged(createIndex(index,0),createIndex(index,2));
|
2021-07-24 11:18:25 +08:00
|
|
|
return breakpoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
const QList<PBreakpoint> &BreakpointModel::breakpoints() const
|
|
|
|
{
|
|
|
|
return mList;
|
|
|
|
}
|
|
|
|
|
2021-09-05 21:05:38 +08:00
|
|
|
PBreakpoint BreakpointModel::breakpoint(int index) const
|
|
|
|
{
|
|
|
|
if (index<0 && index>=mList.count())
|
|
|
|
return PBreakpoint();
|
|
|
|
return mList[index];
|
|
|
|
}
|
|
|
|
|
2021-10-21 19:33:11 +08:00
|
|
|
void BreakpointModel::save(const QString &filename)
|
|
|
|
{
|
|
|
|
QFile file(filename);
|
|
|
|
if (file.open(QFile::WriteOnly | QFile::Truncate)) {
|
|
|
|
QJsonArray array;
|
|
|
|
foreach (const PBreakpoint& breakpoint, mList) {
|
|
|
|
QJsonObject obj;
|
|
|
|
obj["filename"]=breakpoint->filename;
|
|
|
|
obj["line"]=breakpoint->line;
|
|
|
|
obj["condition"]=breakpoint->condition;
|
|
|
|
obj["enabled"]=breakpoint->enabled;
|
|
|
|
array.append(obj);
|
|
|
|
}
|
|
|
|
QJsonDocument doc;
|
|
|
|
doc.setArray(array);
|
|
|
|
if (file.write(doc.toJson())<0) {
|
|
|
|
throw FileError(tr("Save file '%1' failed.")
|
|
|
|
.arg(filename));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw FileError(tr("Can't open file '%1' for write.")
|
|
|
|
.arg(filename));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BreakpointModel::load(const QString &filename)
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
QFile file(filename);
|
|
|
|
if (!file.exists())
|
|
|
|
return;
|
|
|
|
if (file.open(QFile::ReadOnly)) {
|
|
|
|
QByteArray content = file.readAll();
|
|
|
|
QJsonParseError error;
|
|
|
|
QJsonDocument doc(QJsonDocument::fromJson(content,&error));
|
|
|
|
if (error.error != QJsonParseError::NoError) {
|
|
|
|
throw FileError(tr("Error in json file '%1':%2 : %3")
|
|
|
|
.arg(filename)
|
|
|
|
.arg(error.offset)
|
|
|
|
.arg(error.errorString()));
|
|
|
|
}
|
|
|
|
QJsonArray array = doc.array();
|
|
|
|
for (int i=0;i<array.count();i++) {
|
|
|
|
QJsonValue value = array[i];
|
|
|
|
QJsonObject obj=value.toObject();
|
|
|
|
PBreakpoint breakpoint = std::make_shared<Breakpoint>();
|
2021-10-23 17:32:03 +08:00
|
|
|
breakpoint->filename = QFileInfo(obj["filename"].toString()).absoluteFilePath();
|
2021-10-21 19:33:11 +08:00
|
|
|
breakpoint->line = obj["line"].toInt();
|
|
|
|
breakpoint->condition = obj["condition"].toString();
|
|
|
|
breakpoint->enabled = obj["enabled"].toBool();
|
|
|
|
|
|
|
|
addBreakpoint(breakpoint);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw FileError(tr("Can't open file '%1' for read.")
|
|
|
|
.arg(filename));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-24 10:07:35 +08:00
|
|
|
void BreakpointModel::updateBreakpointNumber(const QString& filename, int line, int number)
|
2021-11-21 08:38:03 +08:00
|
|
|
{
|
|
|
|
foreach (PBreakpoint bp, mList) {
|
2021-11-21 10:36:50 +08:00
|
|
|
if (bp->filename == filename && bp->line == line) {
|
2021-11-21 08:38:03 +08:00
|
|
|
bp->number = number;
|
2021-11-23 21:08:33 +08:00
|
|
|
return;
|
2021-11-21 08:38:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-24 10:07:35 +08:00
|
|
|
void BreakpointModel::onFileDeleteLines(const QString& filename, int startLine, int count)
|
2021-09-05 22:16:54 +08:00
|
|
|
{
|
|
|
|
for (int i = mList.count()-1;i>=0;i--){
|
|
|
|
PBreakpoint breakpoint = mList[i];
|
|
|
|
if (breakpoint->filename == filename
|
|
|
|
&& breakpoint->line>=startLine) {
|
|
|
|
if (breakpoint->line >= startLine+count) {
|
|
|
|
breakpoint->line -= count;
|
2021-10-21 17:31:25 +08:00
|
|
|
emit dataChanged(createIndex(i,0),createIndex(i,2));
|
2021-09-05 22:16:54 +08:00
|
|
|
} else {
|
2021-10-21 17:31:25 +08:00
|
|
|
removeBreakpoint(i);
|
2021-09-05 22:16:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-24 10:07:35 +08:00
|
|
|
void BreakpointModel::onFileInsertLines(const QString& filename, int startLine, int count)
|
2021-09-05 22:16:54 +08:00
|
|
|
{
|
|
|
|
for (int i = mList.count()-1;i>=0;i--){
|
|
|
|
PBreakpoint breakpoint = mList[i];
|
|
|
|
if (breakpoint->filename == filename
|
|
|
|
&& breakpoint->line>=startLine) {
|
|
|
|
breakpoint->line+=count;
|
2021-10-21 17:31:25 +08:00
|
|
|
emit dataChanged(createIndex(i,0),createIndex(i,2));
|
2021-09-05 22:16:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-24 11:18:25 +08:00
|
|
|
|
|
|
|
BacktraceModel::BacktraceModel(QObject *parent):QAbstractTableModel(parent)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
2021-07-17 19:32:23 +08:00
|
|
|
|
|
|
|
int BacktraceModel::rowCount(const QModelIndex &) const
|
|
|
|
{
|
|
|
|
return mList.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
int BacktraceModel::columnCount(const QModelIndex &) const
|
|
|
|
{
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant BacktraceModel::data(const QModelIndex &index, int role) const
|
|
|
|
{
|
|
|
|
if (!index.isValid())
|
|
|
|
return QVariant();
|
|
|
|
if (index.row()<0 || index.row() >= static_cast<int>(mList.size()))
|
|
|
|
return QVariant();
|
|
|
|
PTrace trace = mList[index.row()];
|
|
|
|
if (!trace)
|
|
|
|
return QVariant();
|
|
|
|
switch (role) {
|
|
|
|
case Qt::DisplayRole:
|
|
|
|
switch (index.column()) {
|
|
|
|
case 0:
|
|
|
|
return trace->funcname;
|
|
|
|
case 1:
|
|
|
|
return trace->filename;
|
|
|
|
case 2:
|
|
|
|
if (trace->line>0)
|
|
|
|
return trace->line;
|
|
|
|
else
|
|
|
|
return "";
|
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant BacktraceModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
|
|
{
|
|
|
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
|
|
|
switch(section) {
|
|
|
|
case 0:
|
|
|
|
return tr("Function");
|
|
|
|
case 1:
|
|
|
|
return tr("Filename");
|
|
|
|
case 2:
|
|
|
|
return tr("Line");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BacktraceModel::addTrace(PTrace p)
|
|
|
|
{
|
|
|
|
beginInsertRows(QModelIndex(),mList.size(),mList.size());
|
|
|
|
mList.push_back(p);
|
|
|
|
endInsertRows();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BacktraceModel::clear()
|
|
|
|
{
|
|
|
|
beginRemoveRows(QModelIndex(),0,mList.size()-1);
|
|
|
|
mList.clear();
|
|
|
|
endRemoveRows();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BacktraceModel::removeTrace(int row)
|
|
|
|
{
|
|
|
|
beginRemoveRows(QModelIndex(),row,row);
|
|
|
|
mList.removeAt(row);
|
|
|
|
endRemoveRows();
|
|
|
|
}
|
2021-07-24 11:18:25 +08:00
|
|
|
|
|
|
|
const QList<PTrace> &BacktraceModel::backtraces() const
|
|
|
|
{
|
|
|
|
return mList;
|
|
|
|
}
|
2021-07-31 14:04:43 +08:00
|
|
|
|
2021-09-05 21:05:38 +08:00
|
|
|
PTrace BacktraceModel::backtrace(int index) const
|
|
|
|
{
|
|
|
|
if (index>=0 && index < mList.count()){
|
|
|
|
return mList[index];
|
|
|
|
}
|
|
|
|
return PTrace();
|
|
|
|
}
|
|
|
|
|
2021-07-31 20:19:45 +08:00
|
|
|
WatchModel::WatchModel(QObject *parent):QAbstractItemModel(parent)
|
|
|
|
{
|
2021-09-19 01:58:09 +08:00
|
|
|
mUpdateCount = 0;
|
2021-07-31 20:19:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
QVariant WatchModel::data(const QModelIndex &index, int role) const
|
|
|
|
{
|
|
|
|
if (!index.isValid()) {
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
WatchVar* item = static_cast<WatchVar*>(index.internalPointer());
|
|
|
|
switch (role) {
|
|
|
|
case Qt::DisplayRole:
|
2021-09-17 08:01:02 +08:00
|
|
|
//qDebug()<<"item->text:"<<item->text;
|
2021-09-19 09:45:03 +08:00
|
|
|
switch(index.column()) {
|
|
|
|
case 0:
|
|
|
|
return item->name;
|
|
|
|
case 1:
|
|
|
|
return item->value;
|
|
|
|
}
|
2021-07-31 20:19:45 +08:00
|
|
|
}
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
2021-07-31 14:04:43 +08:00
|
|
|
QModelIndex WatchModel::index(int row, int column, const QModelIndex &parent) const
|
|
|
|
{
|
|
|
|
if (!hasIndex(row,column,parent))
|
|
|
|
return QModelIndex();
|
|
|
|
|
|
|
|
WatchVar* parentItem;
|
|
|
|
PWatchVar pChild;
|
|
|
|
if (!parent.isValid()) {
|
|
|
|
parentItem = nullptr;
|
|
|
|
pChild = mWatchVars[row];
|
|
|
|
} else {
|
|
|
|
parentItem = static_cast<WatchVar*>(parent.internalPointer());
|
|
|
|
pChild = parentItem->children[row];
|
|
|
|
}
|
2021-09-19 01:58:09 +08:00
|
|
|
if (pChild) {
|
2021-07-31 14:04:43 +08:00
|
|
|
return createIndex(row,column,pChild.get());
|
2021-09-19 01:58:09 +08:00
|
|
|
}
|
2021-07-31 14:04:43 +08:00
|
|
|
return QModelIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
static int getWatchIndex(WatchVar* var, const QList<PWatchVar> list) {
|
|
|
|
for (int i=0;i<list.size();i++) {
|
|
|
|
PWatchVar v = list[i];
|
|
|
|
if (v.get() == var) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
2021-08-27 23:51:42 +08:00
|
|
|
return -1;
|
2021-07-31 14:04:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
QModelIndex WatchModel::parent(const QModelIndex &index) const
|
|
|
|
{
|
|
|
|
if (!index.isValid()) {
|
|
|
|
return QModelIndex();
|
|
|
|
}
|
|
|
|
WatchVar* childItem = static_cast<WatchVar*>(index.internalPointer());
|
2021-08-01 01:06:43 +08:00
|
|
|
WatchVar* parentItem = childItem->parent;
|
2021-07-31 14:04:43 +08:00
|
|
|
|
|
|
|
//parent is root
|
|
|
|
if (parentItem == nullptr) {
|
|
|
|
return QModelIndex();
|
|
|
|
}
|
|
|
|
int row;
|
|
|
|
WatchVar* grandItem = parentItem->parent;
|
|
|
|
if (grandItem == nullptr) {
|
|
|
|
row = getWatchIndex(parentItem,mWatchVars);
|
|
|
|
} else {
|
|
|
|
row = getWatchIndex(parentItem,grandItem->children);
|
|
|
|
}
|
|
|
|
return createIndex(row,0,parentItem);
|
|
|
|
}
|
|
|
|
|
|
|
|
int WatchModel::rowCount(const QModelIndex &parent) const
|
|
|
|
{
|
|
|
|
if (!parent.isValid()) {
|
|
|
|
return mWatchVars.count();
|
|
|
|
} else {
|
|
|
|
WatchVar* parentItem = static_cast<WatchVar*>(parent.internalPointer());
|
|
|
|
return parentItem->children.count();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-31 20:19:45 +08:00
|
|
|
int WatchModel::columnCount(const QModelIndex&) const
|
2021-07-31 14:04:43 +08:00
|
|
|
{
|
2021-09-19 09:45:03 +08:00
|
|
|
return 2;
|
2021-07-31 14:04:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void WatchModel::addWatchVar(PWatchVar watchVar)
|
|
|
|
{
|
|
|
|
for (PWatchVar var:mWatchVars) {
|
|
|
|
if (watchVar->name == var->name) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2021-07-31 20:19:45 +08:00
|
|
|
this->beginInsertRows(QModelIndex(),mWatchVars.size(),mWatchVars.size());
|
2021-07-31 14:04:43 +08:00
|
|
|
mWatchVars.append(watchVar);
|
2021-07-31 20:19:45 +08:00
|
|
|
this->endInsertRows();
|
2021-07-31 14:04:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void WatchModel::removeWatchVar(const QString &name)
|
|
|
|
{
|
2021-09-19 01:58:09 +08:00
|
|
|
for (int i=mWatchVars.size()-1;i>=0;i--) {
|
2021-07-31 20:19:45 +08:00
|
|
|
PWatchVar var = mWatchVars[i];
|
2021-07-31 14:04:43 +08:00
|
|
|
if (name == var->name) {
|
2021-09-19 01:58:09 +08:00
|
|
|
this->beginResetModel();
|
|
|
|
//this->beginRemoveRows(QModelIndex(),i,i);
|
|
|
|
mWatchVars.removeAt(i);
|
|
|
|
//this->endRemoveRows();
|
|
|
|
this->endResetModel();
|
2021-07-31 14:04:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void WatchModel::removeWatchVar(int gdbIndex)
|
|
|
|
{
|
2021-09-19 01:58:09 +08:00
|
|
|
for (int i=mWatchVars.size()-1;i>=0;i--) {
|
2021-07-31 20:19:45 +08:00
|
|
|
PWatchVar var = mWatchVars[i];
|
2021-07-31 14:04:43 +08:00
|
|
|
if (gdbIndex == var->gdbIndex) {
|
2021-09-19 01:58:09 +08:00
|
|
|
this->beginResetModel();
|
|
|
|
//this->beginRemoveRows(QModelIndex(),i,i);
|
|
|
|
mWatchVars.removeAt(i);
|
|
|
|
//this->endRemoveRows();
|
|
|
|
this->endResetModel();
|
2021-07-31 14:04:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-31 11:13:12 +08:00
|
|
|
void WatchModel::removeWatchVar(const QModelIndex &index)
|
|
|
|
{
|
|
|
|
int r=index.row();
|
|
|
|
this->beginRemoveRows(QModelIndex(),r,r);
|
|
|
|
mWatchVars.removeAt(r);
|
|
|
|
this->endRemoveRows();
|
|
|
|
}
|
|
|
|
|
2021-07-31 14:04:43 +08:00
|
|
|
void WatchModel::clear()
|
|
|
|
{
|
2021-07-31 20:19:45 +08:00
|
|
|
this->beginResetModel();
|
2021-07-31 14:04:43 +08:00
|
|
|
mWatchVars.clear();
|
2021-07-31 20:19:45 +08:00
|
|
|
this->endResetModel();
|
2021-07-31 14:04:43 +08:00
|
|
|
}
|
|
|
|
|
2021-07-31 20:19:45 +08:00
|
|
|
const QList<PWatchVar> &WatchModel::watchVars()
|
2021-07-31 14:04:43 +08:00
|
|
|
{
|
|
|
|
return mWatchVars;
|
|
|
|
}
|
|
|
|
|
|
|
|
PWatchVar WatchModel::findWatchVar(const QString &name)
|
|
|
|
{
|
|
|
|
for (PWatchVar var:mWatchVars) {
|
|
|
|
if (name == var->name) {
|
|
|
|
return var;
|
|
|
|
}
|
|
|
|
}
|
2021-07-31 20:19:45 +08:00
|
|
|
return PWatchVar();
|
2021-07-31 14:04:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
PWatchVar WatchModel::findWatchVar(int gdbIndex)
|
|
|
|
{
|
|
|
|
for (PWatchVar var:mWatchVars) {
|
|
|
|
if (gdbIndex == var->gdbIndex) {
|
|
|
|
return var;
|
|
|
|
}
|
|
|
|
}
|
2021-07-31 20:19:45 +08:00
|
|
|
return PWatchVar();
|
|
|
|
}
|
|
|
|
|
2021-09-19 01:58:09 +08:00
|
|
|
void WatchModel::beginUpdate()
|
|
|
|
{
|
|
|
|
if (mUpdateCount == 0) {
|
|
|
|
beginResetModel();
|
|
|
|
}
|
|
|
|
mUpdateCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WatchModel::endUpdate()
|
|
|
|
{
|
|
|
|
mUpdateCount--;
|
|
|
|
if (mUpdateCount == 0) {
|
|
|
|
endResetModel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-31 20:19:45 +08:00
|
|
|
void WatchModel::notifyUpdated(PWatchVar var)
|
|
|
|
{
|
|
|
|
if (!var)
|
|
|
|
return;
|
|
|
|
int row;
|
|
|
|
if (var->parent==nullptr) {
|
|
|
|
row = mWatchVars.indexOf(var);
|
|
|
|
} else {
|
|
|
|
row = var->parent->children.indexOf(var);
|
|
|
|
}
|
|
|
|
if (row<0)
|
|
|
|
return;
|
2021-09-17 08:01:02 +08:00
|
|
|
//qDebug()<<"dataChanged"<<row<<":"<<var->text;
|
2021-07-31 20:19:45 +08:00
|
|
|
emit dataChanged(createIndex(row,0,var.get()),createIndex(row,0,var.get()));
|
2021-07-31 14:04:43 +08:00
|
|
|
}
|
2021-08-01 23:24:37 +08:00
|
|
|
|
2021-10-21 19:33:11 +08:00
|
|
|
void WatchModel::save(const QString &filename)
|
|
|
|
{
|
|
|
|
QFile file(filename);
|
|
|
|
if (file.open(QFile::WriteOnly | QFile::Truncate)) {
|
|
|
|
QJsonArray array;
|
|
|
|
foreach (const PWatchVar& watchVar, mWatchVars) {
|
|
|
|
QJsonObject obj;
|
|
|
|
obj["name"]=watchVar->name;
|
|
|
|
array.append(obj);
|
|
|
|
}
|
|
|
|
QJsonDocument doc;
|
|
|
|
doc.setArray(array);
|
|
|
|
if (file.write(doc.toJson())<0) {
|
|
|
|
throw FileError(tr("Save file '%1' failed.")
|
|
|
|
.arg(filename));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw FileError(tr("Can't open file '%1' for write.")
|
|
|
|
.arg(filename));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void WatchModel::load(const QString &filename)
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
QFile file(filename);
|
|
|
|
if (!file.exists())
|
|
|
|
return;
|
|
|
|
if (file.open(QFile::ReadOnly)) {
|
|
|
|
QByteArray content = file.readAll();
|
|
|
|
QJsonParseError error;
|
|
|
|
QJsonDocument doc(QJsonDocument::fromJson(content,&error));
|
|
|
|
if (error.error != QJsonParseError::NoError) {
|
|
|
|
throw FileError(tr("Error in json file '%1':%2 : %3")
|
|
|
|
.arg(filename)
|
|
|
|
.arg(error.offset)
|
|
|
|
.arg(error.errorString()));
|
|
|
|
}
|
|
|
|
QJsonArray array = doc.array();
|
|
|
|
for (int i=0;i<array.count();i++) {
|
|
|
|
QJsonValue value = array[i];
|
|
|
|
QJsonObject obj=value.toObject();
|
|
|
|
PWatchVar var = std::make_shared<WatchVar>();
|
|
|
|
var->parent= nullptr;
|
|
|
|
var->name = obj["name"].toString();
|
|
|
|
var->value = tr("Execute to evaluate");
|
|
|
|
var->gdbIndex = -1;
|
|
|
|
|
|
|
|
addWatchVar(var);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw FileError(tr("Can't open file '%1' for read.")
|
|
|
|
.arg(filename));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-09-19 14:28:30 +08:00
|
|
|
QVariant WatchModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
|
|
{
|
|
|
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
|
|
|
switch(section) {
|
|
|
|
case 0:
|
|
|
|
return tr("Expression");
|
|
|
|
case 1:
|
|
|
|
return tr("Value");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
2021-08-01 23:24:37 +08:00
|
|
|
RegisterModel::RegisterModel(QObject *parent):QAbstractTableModel(parent)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-10-20 18:05:43 +08:00
|
|
|
int RegisterModel::rowCount(const QModelIndex &) const
|
2021-08-01 23:24:37 +08:00
|
|
|
{
|
|
|
|
return mRegisters.count();
|
|
|
|
}
|
|
|
|
|
2021-10-20 18:05:43 +08:00
|
|
|
int RegisterModel::columnCount(const QModelIndex &) const
|
2021-08-01 23:24:37 +08:00
|
|
|
{
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant RegisterModel::data(const QModelIndex &index, int role) const
|
|
|
|
{
|
|
|
|
if (!index.isValid())
|
|
|
|
return QVariant();
|
|
|
|
if (index.row()<0 || index.row() >= static_cast<int>(mRegisters.size()))
|
|
|
|
return QVariant();
|
|
|
|
PRegister reg = mRegisters[index.row()];
|
|
|
|
if (!reg)
|
|
|
|
return QVariant();
|
|
|
|
switch (role) {
|
|
|
|
case Qt::DisplayRole:
|
|
|
|
switch (index.column()) {
|
|
|
|
case 0:
|
|
|
|
return reg->name;
|
|
|
|
case 1:
|
|
|
|
return reg->hexValue;
|
|
|
|
case 2:
|
|
|
|
return reg->decValue;
|
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QVariant RegisterModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
|
|
{
|
|
|
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
|
|
|
switch(section) {
|
|
|
|
case 0:
|
|
|
|
return tr("Register");
|
|
|
|
case 1:
|
|
|
|
return tr("Value(Hex)");
|
|
|
|
case 2:
|
|
|
|
return tr("Value(Dec)");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return QVariant();
|
|
|
|
}
|
|
|
|
|
|
|
|
void RegisterModel::update(const QList<PRegister> ®s)
|
|
|
|
{
|
|
|
|
beginResetModel();
|
|
|
|
mRegisters.clear();
|
|
|
|
mRegisters.append(regs);
|
|
|
|
endResetModel();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegisterModel::clear()
|
|
|
|
{
|
|
|
|
beginResetModel();
|
|
|
|
mRegisters.clear();
|
|
|
|
endResetModel();
|
|
|
|
}
|