#include "debugger.h" #include "utils.h" #include "mainwindow.h" Debugger::Debugger(QObject *parent) : QObject(parent) { } DebugReader::DebugReader(QObject *parent) : QObject(parent) { } void DebugReader::clearCmdQueue() { QMutexLocker locker(&mMutex); mCmdQueue.clear(); while (mUpdateCount>0) { //WatchView.Items.EndUpdate(); mUpdateCount--; } } bool DebugReader::findAnnotation(AnnotationType annotation) { AnnotationType NextAnnotation; do { NextAnnotation = getNextAnnotation(); if (NextAnnotation == AnnotationType::TEOF) return false; } while (NextAnnotation != annotation); return true; } AnnotationType DebugReader::getAnnotation(const QString &s) { if (s == "pre-prompt") { return AnnotationType::TPrePrompt; } else if (s == "prompt") { return AnnotationType::TPrompt; } else if (s == "post-prompt") { AnnotationType result = AnnotationType::TPostPrompt; int IndexBackup = mIndex; QString t = getNextFilledLine(); int mIndex = IndexBackup; //hack to catch local if ((mCurrentCmd) && (mCurrentCmd->command == "info locals")) { result = AnnotationType::TLocal; } else if ((mCurrentCmd) && (mCurrentCmd->command == "info args")) { //hack to catch params result = AnnotationType::TParam; } else if (t.startsWith("rax ") || t.startsWith("eax ")) { // Hack fix to catch register dump result = AnnotationType::TInfoReg; } else { // Another hack to catch assembler if (t.startsWith("Dump of assembler code for function ")) result = AnnotationType::TInfoAsm; } return result; } else if (s == "error-begin") { return AnnotationType::TErrorBegin; } else if (s == "error-end") { return AnnotationType::TErrorEnd; } else if (s == "display-begin") { return AnnotationType::TDisplayBegin; } else if (s == "display-expression") { return AnnotationType::TDisplayExpression; } else if (s == "display-end") { return AnnotationType::TDisplayEnd; } else if (s == "frame-source-begin") { return AnnotationType::TFrameSourceBegin; } else if (s == "frame-source-file") { return AnnotationType::TFrameSourceFile; } else if (s == "frame-source-line") { return AnnotationType::TFrameSourceLine; } else if (s == "frame-function-name") { return AnnotationType::TFrameFunctionName; } else if (s == "frame-args") { return AnnotationType::TFrameArgs; } else if (s == "frame-begin") { return AnnotationType::TFrameBegin; } else if (s == "frame-end") { return AnnotationType::TFrameEnd; } else if (s == "frame-where") { return AnnotationType::TFrameWhere; } else if (s == "source") { return AnnotationType::TSource; } else if (s == "exited") { return AnnotationType::TExit; } else if (s == "arg-begin") { return AnnotationType::TArgBegin; } else if (s == "arg-name-end") { return AnnotationType::TArgNameEnd; } else if (s == "arg-value") { return AnnotationType::TArgValue; } else if (s == "arg-end") { return AnnotationType::TArgEnd; } else if (s == "array-section-begin") { return AnnotationType::TArrayBegin; } else if (s == "array-section-end") { return AnnotationType::TArrayEnd; } else if (s == "elt") { return AnnotationType::TElt; } else if (s == "elt-rep") { return AnnotationType::TEltRep; } else if (s == "elt-rep-end") { return AnnotationType::TEltRepEnd; } else if (s == "field-begin") { return AnnotationType::TFieldBegin; } else if (s == "field-name-end") { return AnnotationType::TFieldNameEnd; } else if (s == "field-value") { return AnnotationType::TFieldValue; } else if (s == "field-end") { return AnnotationType::TFieldEnd; } else if (s == "value-history-value") { return AnnotationType::TValueHistoryValue; } else if (s == "value-history-begin") { return AnnotationType::TValueHistoryBegin; } else if (s == "value-history-end") { return AnnotationType::TValueHistoryEnd; } else if (s == "signal") { return AnnotationType::TSignal; } else if (s == "signal-name") { return AnnotationType::TSignalName; } else if (s == "signal-name-end") { return AnnotationType::TSignalNameEnd; } else if (s == "signal-string") { return AnnotationType::TSignalString; } else if (s == "signal-string-end") { return AnnotationType::TSignalStringEnd; } else if (mIndex >= mOutput.length()) { return AnnotationType::TEOF; } else { return AnnotationType::TUnknown;; } } AnnotationType DebugReader::getLastAnnotation(const QString &text, int curpos, int len) { // Walk back until end of #26's while ((curpos >= 0) && (text[curpos] != 26)) curpos--; curpos++; // Tiny rewrite of GetNextWord for special purposes QString s = ""; while ((curpos < len) && (text[curpos]>32)) { s = s + text[curpos]; curpos++; } return getAnnotation(s); } AnnotationType DebugReader::getNextAnnotation() { // Skip until end of #26's, i.e. GDB formatted output skipToAnnotation(); // Get part this line, after #26#26 return getAnnotation(getNextWord()); } QString DebugReader::getNextFilledLine() { // Walk up to an enter sequence while (mIndex=mOutput.length()) return ""; // Skip ONE enter sequence (CRLF, CR, LF, etc.) if ((mOutput[mIndex] == 13) && (mOutput[mIndex] == 10)) // DOS mIndex+=2; else if (mOutput[mIndex] == 13) // UNIX mIndex++; else if (mOutput[mIndex] == 10) // MAC mIndex++; // Return next line return getRemainingLine(); } QString DebugReader::getNextWord() { QString Result; // Called when at a space? Skip over skipSpaces(); // Skip until a space while (mIndex32) { Result += mOutput[mIndex]; mIndex++; } return Result; } QString DebugReader::getRemainingLine() { QString Result; // Return part of line still ahead of us while (mIndexgdbIndex = s.toInt(); processWatchOutput(watchVar); } } void DebugReader::handleError() { QString s = getNextLine(); // error text if (s.startsWith("Cannot find bounds of current function")) { //We have exited handleExit(); } else if (s.startsWith("No symbol \"")) { int head = s.indexOf('\"'); int tail = s.lastIndexOf('\"'); QString watchName = s.mid(head+1, tail-head-1); // Update current... auto result = mWatchVarList.find(watchName); if (result != mWatchVarList.end()) { PWatchVar watchVar = result.value(); //todo: update watch value to invalid invalidateWatchVar(watchVar); watchVar->gdbIndex = -1; dorescanwatches = true; } } } void DebugReader::handleExit() { doprocessexited=true; } void DebugReader::handleFrames() { QString s = getNextLine(); // Is this a backtrace dump? if (s.startsWith("#")) { // Find function name if (!findAnnotation(AnnotationType::TFrameFunctionName)) return; PTrace trace = std::make_shared(); trace->funcname = getNextLine(); // Find argument list start if (!findAnnotation(AnnotationType::TFrameArgs)) return; // Arguments are either () or detailed list s = getNextLine(); while (peekNextAnnotation() == AnnotationType::TArgBegin) { // argument name if (!findAnnotation(AnnotationType::TArgBegin)) return; s = s + getNextLine(); // = if (!findAnnotation(AnnotationType::TArgNameEnd)) return; s = s + ' ' + getNextLine() + ' '; // should be = // argument value if (!findAnnotation(AnnotationType::TArgValue)) return; s = s + getNextLine(); // argument end if (!findAnnotation(AnnotationType::TArgEnd)) return; s = s + getNextLine(); } trace->funcname = trace->funcname + s.trimmed(); // source info if (peekNextAnnotation() == AnnotationType::TFrameSourceBegin) { // Find filename if (!findAnnotation(AnnotationType::TFrameSourceFile)) return; trace->filename = getNextLine(); // find line if (!findAnnotation(AnnotationType::TFrameSourceLine)) return; trace->line = getNextLine().trimmed().toInt(); } else { trace->filename = ""; trace->line = 0; } mBacktraceModel.addTrace(trace); // Skip over the remaining frame part... if (!findAnnotation(AnnotationType::TFrameEnd)) return; // Not another one coming? Done! if (peekNextAnnotation() != AnnotationType::TFrameBegin) { // End of stack trace dump! dobacktraceready = true; } } else doupdatecpuwindow = true; } void DebugReader::handleLocalOutput() { // name(spaces)hexvalue(tab)decimalvalue QString s = getNextFilledLine(); bool breakLine = false; while (true) { if (s.startsWith("\032\032")) { s = TrimLeft(s); if (s == "No locals.") { return; } if (s == "No arguments.") { return; } //todo: update local view // if (breakLine and (MainForm.txtLocals.Lines.Count>0) then begin // MainForm.txtLocals.Lines[MainForm.txtLocals.Lines.Count-1] := MainForm.txtLocals.Lines[MainForm.txtLocals.Lines.Count-1] + s; // end else begin // MainForm.txtLocals.Lines.Add(s); // end; breakLine=false; } else { breakLine = true; } s = getNextLine(); if (!breakLine && s.isEmpty()) break; } } void DebugReader::handleLocals() { //todo: clear local view handleLocalOutput(); } void DebugReader::handleParams(){ handleLocalOutput(); } void DebugReader::handleRegisters() { // name(spaces)hexvalue(tab)decimalvalue QString s = getNextFilledLine(); while (true) { PRegister reg = std::make_shared(); // Cut name from 1 to first space int x = s.indexOf(' '); reg->name = s.mid(0,x-1); s.remove(0,x); // Remove spaces s = TrimLeft(s); // Cut hex value from 1 to first tab x = s.indexOf('\t'); if (x<0) x = s.indexOf(' '); reg->hexValue = s.mid(0,x - 1); s.remove(0,x); // delete tab too s = TrimLeft(s); // Remaining part contains decimal value reg->decValue = s; mRegisters.append(reg); s = getNextLine(); if (s.isEmpty()) break; } doregistersready := true; } 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(mList.size())) return QVariant(); PBreakpoint breakpoint = mList[index.row()]; if (!breakpoint) return QVariant(); switch (role) { case Qt::DisplayRole: 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(); } 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(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(); }