From d0b7c12430f6b19a619d14b915d8c498620be4b8 Mon Sep 17 00:00:00 2001 From: hjk <qtc-committer@nokia.com> Date: Wed, 24 Nov 2010 15:55:09 +0100 Subject: [PATCH] debugger: make debugger view data store more structured --- src/plugins/debugger/cdb2/cdbparsehelpers.cpp | 11 +- src/plugins/debugger/cdb2/cdbparsehelpers.h | 3 +- src/plugins/debugger/debuggeragents.cpp | 141 ++++++++++-------- src/plugins/debugger/debuggeragents.h | 36 ++++- src/plugins/debugger/gdb/gdbengine.cpp | 83 ++++++----- src/plugins/debugger/gdb/gdbengine.h | 3 +- src/plugins/debugger/lldb/ipcenginehost.cpp | 6 +- 7 files changed, 170 insertions(+), 113 deletions(-) diff --git a/src/plugins/debugger/cdb2/cdbparsehelpers.cpp b/src/plugins/debugger/cdb2/cdbparsehelpers.cpp index c2a9bf34397..1a1ad80d621 100644 --- a/src/plugins/debugger/cdb2/cdbparsehelpers.cpp +++ b/src/plugins/debugger/cdb2/cdbparsehelpers.cpp @@ -33,6 +33,7 @@ #include "threadshandler.h" #include "registerhandler.h" #include "bytearrayinputstream.h" +#include "debuggeragents.h" #include "gdb/gdbmi.h" #ifdef Q_OS_WIN # include "shared/dbgwinutils.h" @@ -99,19 +100,17 @@ QByteArray cdbAddBreakpointCommand(const Debugger::Internal::BreakpointParameter // Remove the address separator. Format the address exactly as // the agent does (0xhex, as taken from frame) for the location mark to trigger. -QString formatCdbDisassembler(const QList<QByteArray> &in) +Internal::DisassemblerLines formatCdbDisassembler(const QList<QByteArray> &in) { - QString disassembly; - const QChar newLine = QLatin1Char('\n'); + Internal::DisassemblerLines result; foreach(QByteArray line, in) { // Remove 64bit separator. if (line.size() >= 9 && line.at(8) == '`') line.remove(8, 1); // Ensure address is as wide as agent's address. - disassembly += QString::fromLatin1(line); - disassembly += newLine; + result.appendLine(Internal::DisassemblerLine(line)); } - return disassembly; + return result; } // Fix a CDB integer value: '00000000`0012a290' -> '12a290', '0n10' ->'10' diff --git a/src/plugins/debugger/cdb2/cdbparsehelpers.h b/src/plugins/debugger/cdb2/cdbparsehelpers.h index 6ee8b03d04f..5ada8612e7b 100644 --- a/src/plugins/debugger/cdb2/cdbparsehelpers.h +++ b/src/plugins/debugger/cdb2/cdbparsehelpers.h @@ -44,6 +44,7 @@ namespace Debugger { namespace Internal { class BreakpointData; class BreakpointParameters; +class DisassemblerLines; class StackFrame; struct ThreadData; class Register; @@ -56,7 +57,7 @@ namespace Cdb { QByteArray cdbAddBreakpointCommand(const Debugger::Internal::BreakpointParameters &d, bool oneshot = false, int id = -1); // Format CDB Dissambler output. -QString formatCdbDisassembler(const QList<QByteArray> &in); +Internal::DisassemblerLines formatCdbDisassembler(const QList<QByteArray> &in); // Convert a CDB integer value: '00000000`0012a290' -> '12a290', '0n10' ->'10' QByteArray fixCdbIntegerValue(QByteArray t, bool stripLeadingZeros = false, int *basePtr = 0); diff --git a/src/plugins/debugger/debuggeragents.cpp b/src/plugins/debugger/debuggeragents.cpp index e16178416ad..aa4247b443e 100644 --- a/src/plugins/debugger/debuggeragents.cpp +++ b/src/plugins/debugger/debuggeragents.cpp @@ -50,9 +50,11 @@ #include <QtCore/QDebug> #include <QtCore/QMetaObject> +#include <QtCore/QTimer> #include <QtGui/QMessageBox> #include <QtGui/QPlainTextEdit> +#include <QtGui/QTextBlock> #include <QtGui/QTextCursor> #include <QtGui/QIcon> @@ -202,23 +204,25 @@ public: void documentClosing() {} }; -struct DisassemblerViewAgentPrivate +class DisassemblerViewAgentPrivate { +public: DisassemblerViewAgentPrivate(); void configureMimeType(); +public: QPointer<TextEditor::ITextEditor> editor; StackFrame frame; bool tryMixed; bool setMarker; QPointer<DebuggerEngine> engine; LocationMark2 *locationMark; - QHash<QString, QString> cache; + QHash<QString, DisassemblerLines> cache; QString mimeType; }; -DisassemblerViewAgentPrivate::DisassemblerViewAgentPrivate() : - editor(0), +DisassemblerViewAgentPrivate::DisassemblerViewAgentPrivate() + : editor(0), tryMixed(true), setMarker(true), locationMark(new LocationMark2), @@ -226,6 +230,7 @@ DisassemblerViewAgentPrivate::DisassemblerViewAgentPrivate() : { } + /*! \class DisassemblerViewAgent @@ -288,7 +293,8 @@ void DisassemblerViewAgent::setFrame(const StackFrame &frame, bool tryMixed, d->setMarker = setMarker; d->tryMixed = tryMixed; if (isMixed()) { - QHash<QString, QString>::ConstIterator it = d->cache.find(frameKey(frame)); + QHash<QString, DisassemblerLines>::ConstIterator it = + d->cache.find(frameKey(frame)); if (it != d->cache.end()) { QString msg = _("Use cache disassembler for '%1' in '%2'") .arg(frame.function).arg(frame.file); @@ -334,37 +340,12 @@ void DisassemblerViewAgent::setMimeType(const QString &mt) d->configureMimeType(); } -// Return a pair of <linenumber [1..n], character position> of an address -// in assembly code, assuming lines start with a sane hex address. -static QPair<int, int> lineNumberOfAddress(const QString &disassembly, quint64 address) -{ - if (disassembly.isEmpty()) - return QPair<int, int>(-1, -1); - - int pos = 0; - const QChar newLine = QLatin1Char('\n'); - - const int size = disassembly.size(); - for (int lineNumber = 1; pos < size; lineNumber++) { - int endOfLinePos = disassembly.indexOf(newLine, pos); - if (endOfLinePos == -1) - endOfLinePos = size; - const QString line = disassembly.mid(pos, endOfLinePos - pos); - if (DisassemblerViewAgent::addressFromDisassemblyLine(line) == address) - return QPair<int, int>(lineNumber, pos); - pos = endOfLinePos + 1; - } - return QPair<int, int>(-1, -1);; -} - -void DisassemblerViewAgent::setContents(const QString &contents) +void DisassemblerViewAgent::setContents(const DisassemblerLines &contents) { QTC_ASSERT(d, return); using namespace Core; using namespace TextEditor; - d->cache.insert(frameKey(d->frame), contents); - QPlainTextEdit *plainTextEdit = 0; EditorManager *editorManager = EditorManager::instance(); if (!d->editor) { QString titlePattern = "Disassembler"; @@ -380,33 +361,37 @@ void DisassemblerViewAgent::setContents(const QString &contents) editorManager->activateEditor(d->editor); - plainTextEdit = qobject_cast<QPlainTextEdit *>(d->editor->widget()); - if (plainTextEdit) { - plainTextEdit->setPlainText(contents); - plainTextEdit->setReadOnly(true); + QPlainTextEdit *plainTextEdit = + qobject_cast<QPlainTextEdit *>(d->editor->widget()); + QTC_ASSERT(plainTextEdit, return); + + QString str; + for (int i = 0, n = contents.size(); i != n; ++i) { + const DisassemblerLine &dl = contents.at(i); + if (dl.address) { + str += QString("0x"); + str += QString::number(dl.address, 16); + str += " "; + } + str += dl.data; + str += "\n"; } + plainTextEdit->setPlainText(str); + plainTextEdit->setReadOnly(true); if (d->setMarker) d->editor->markableInterface()->removeMark(d->locationMark); d->editor->setDisplayName(_("Disassembler (%1)").arg(d->frame.function)); + d->cache.insert(frameKey(d->frame), contents); - const QPair<int, int> lineNumberPos = - lineNumberOfAddress(contents, d->frame.address); - if (lineNumberPos.first > 0) { - if (d->setMarker) - d->editor->markableInterface()->addMark(d->locationMark, lineNumberPos.first); - if (plainTextEdit) { - QTextCursor tc = plainTextEdit->textCursor(); - tc.setPosition(lineNumberPos.second); - plainTextEdit->setTextCursor(tc); - } - } -} + int lineNumber = contents.m_rowCache[d->frame.address]; + if (lineNumber && d->setMarker) + d->editor->markableInterface()->addMark(d->locationMark, lineNumber); -bool DisassemblerViewAgent::contentsCoversAddress(const QString &contents) const -{ - QTC_ASSERT(d, return false); - return lineNumberOfAddress(contents, d->frame.address).first > 0; + QTextCursor tc = plainTextEdit->textCursor(); + QTextBlock block = tc.document()->findBlockByNumber(lineNumber - 1); + tc.setPosition(block.position()); + plainTextEdit->setTextCursor(tc); } quint64 DisassemblerViewAgent::address() const @@ -416,20 +401,54 @@ quint64 DisassemblerViewAgent::address() const // Return address of an assembly line "0x0dfd bla" quint64 DisassemblerViewAgent::addressFromDisassemblyLine(const QString &line) +{ + return DisassemblerLine(line).address; +} + +DisassemblerLine::DisassemblerLine(const QString &unparsed) { // Mac gdb has an overflow reporting 64bit addresses causing the instruction // to follow the last digit "0x000000013fff4810mov 1,1". Truncate here. - const int pos = qMin(line.indexOf(QLatin1Char(' ')), 19); - if (pos < 0) - return 0; - QString addressS = line.left(pos); - if (addressS.endsWith(':')) // clang - addressS.chop(1); - if (addressS.startsWith(QLatin1String("0x"))) - addressS.remove(0, 2); + const int pos = qMin(unparsed.indexOf(QLatin1Char(' ')), 19); + if (pos < 0) { + address = 0; + data = unparsed; + return; + } + QString addr = unparsed.left(pos); + if (addr.endsWith(':')) // clang + addr.chop(1); + if (addr.startsWith(QLatin1String("0x"))) + addr.remove(0, 2); bool ok; - const quint64 address = addressS.toULongLong(&ok, 16); - return ok ? address : quint64(0); + address = addr.toULongLong(&ok, 16); + if (address) + data = unparsed.mid(pos + 1); + else + data = unparsed; +} + +int DisassemblerLines::lineForAddress(quint64 address) const +{ + return m_rowCache.value(address); +} + +bool DisassemblerLines::coversAddress(quint64 address) const +{ + return m_rowCache.value(address) != 0; +} + +void DisassemblerLines::appendComment(const QString &comment) +{ + DisassemblerLine dl; + dl.data = comment; + m_data.append(dl); +} + +void DisassemblerLines::appendLine(const DisassemblerLine &dl) +{ + m_data.append(dl); + m_rowCache[dl.address] = m_data.size(); } } // namespace Internal diff --git a/src/plugins/debugger/debuggeragents.h b/src/plugins/debugger/debuggeragents.h index 3db89008101..7cbcdae0ba9 100644 --- a/src/plugins/debugger/debuggeragents.h +++ b/src/plugins/debugger/debuggeragents.h @@ -31,7 +31,9 @@ #define DEBUGGER_AGENTS_H #include <QtCore/QObject> +#include <QtCore/QHash> #include <QtCore/QPointer> +#include <QtCore/QVector> namespace Core { class IEditor; @@ -44,6 +46,8 @@ class DebuggerEngine; namespace Internal { class StackFrame; +class DisassemblerViewAgent; +class DisassemblerViewAgentPrivate; class MemoryViewAgent : public QObject { @@ -72,7 +76,32 @@ private: QPointer<Debugger::DebuggerEngine> m_engine; }; -struct DisassemblerViewAgentPrivate; +class DisassemblerLine +{ +public: + DisassemblerLine() : address(0) {} + DisassemblerLine(const QString &unparsed); + + quint64 address; + QString data; +}; + +class DisassemblerLines +{ +public: + DisassemblerLines() {} + bool coversAddress(quint64 address) const; + void appendLine(const DisassemblerLine &dl); + void appendComment(const QString &comment); + int size() const { return m_data.size(); } + const DisassemblerLine &at(int i) const { return m_data.at(i); } + int lineForAddress(quint64 address) const; + +private: + friend class DisassemblerViewAgent; + QVector<DisassemblerLine> m_data; + QHash<quint64, int> m_rowCache; +}; class DisassemblerViewAgent : public QObject { @@ -86,7 +115,7 @@ public: void setFrame(const StackFrame &frame, bool tryMixed, bool setMarker); const StackFrame &frame() const; void resetLocation(); - Q_SLOT void setContents(const QString &contents); + void setContents(const DisassemblerLines &contents); // Mimetype: "text/a-asm" or some specialized architecture QString mimeType() const; @@ -98,8 +127,7 @@ public: bool isMixed() const; // Return address of an assembly line "0x0dfd bla" - static quint64 addressFromDisassemblyLine(const QString &line); - + static quint64 addressFromDisassemblyLine(const QString &data); private: DisassemblerViewAgentPrivate *d; }; diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 4e93dfb5c1b..92235c17f02 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -874,6 +874,23 @@ void GdbEngine::handleResultRecord(GdbResponse *response) //shutdown(); //showMessageBox(QMessageBox::Critical, // tr("Executable failed"), QString::fromLocal8Bit(msg)); + } else if (msg.contains("Cannot insert breakpoint")) { + // For breakpoints set by address to non-existent addresses we + // might get something like "6^error,msg="Warning:\nCannot insert + // breakpoint 3.\nError accessing memory address 0x34592327: + // Input/output error.\nCannot insert breakpoint 4.\nError + // accessing memory address 0x34592335: Input/output error.\n". + // This should not stop us from proceeding. + // Most notably, that happens after a "6^running" and "*running" + // We are probably sitting at _start and can't proceed as + // long as the breakpoints are enabled. + // FIXME: Should we silently disable the offending breakpoints? + showMessage(_("APPLYING WORKAROUND #5")); + showMessageBox(QMessageBox::Critical, + tr("Setting breakpoints failed"), QString::fromLocal8Bit(msg)); + QTC_ASSERT(state() == InferiorRunOk, /**/); + notifyInferiorSpontaneousStop(); + notifyEngineIll(); } else { showMessageBox(QMessageBox::Critical, tr("Executable failed"), QString::fromLocal8Bit(msg)); @@ -3876,24 +3893,20 @@ void GdbEngine::fetchDisassemblerByAddressCli(const DisassemblerAgentCookie &ac0 QVariant::fromValue(ac)); } -static QByteArray parseLine(const GdbMi &line) +static DisassemblerLine parseLine(const GdbMi &line) { - QByteArray ba; - ba.reserve(200); + DisassemblerLine dl; QByteArray address = line.findChild("address").data(); //QByteArray funcName = line.findChild("func-name").data(); //QByteArray offset = line.findChild("offset").data(); - QByteArray inst = line.findChild("inst").data(); - ba += address; - ba += QByteArray(15 - address.size(), ' '); + dl.address = address.toULongLong(); //ba += funcName + "+" + offset + " "; //ba += QByteArray(30 - funcName.size() - offset.size(), ' '); - ba += inst; - ba += '\n'; - return ba; + dl.data = _(line.findChild("inst").data()); + return dl; } -QString GdbEngine::parseDisassembler(const GdbMi &lines) +DisassemblerLines GdbEngine::parseDisassembler(const GdbMi &lines) { // ^done,data={asm_insns=[src_and_asm_line={line="1243",file=".../app.cpp", // line_asm_insn=[{address="0x08054857",func-name="main",offset="27", @@ -3906,10 +3919,9 @@ QString GdbEngine::parseDisassembler(const GdbMi &lines) // {address="0x0805acf8",func-name="...",offset="25",inst="and $0xe8,%al"}, // {address="0x0805acfa",func-name="...",offset="27",inst="pop %esp"}, - QList<QByteArray> fileContents; + QStringList fileContents; bool fileLoaded = false; - QByteArray ba; - ba.reserve(200 * lines.children().size()); + DisassemblerLines result; // FIXME: Performance? foreach (const GdbMi &child, lines.children()) { @@ -3920,21 +3932,22 @@ QString GdbEngine::parseDisassembler(const GdbMi &lines) fileName = cleanupFullName(fileName); QFile file(fileName); file.open(QIODevice::ReadOnly); - fileContents = file.readAll().split('\n'); + QTextStream ts(&file); + fileContents = ts.readAll().split(QLatin1Char('\n')); fileLoaded = true; } int line = child.findChild("line").data().toInt(); if (line >= 1 && line <= fileContents.size()) - ba += " " + fileContents.at(line - 1) + '\n'; + result.appendComment(fileContents.at(line - 1)); GdbMi insn = child.findChild("line_asm_insn"); - foreach (const GdbMi &line, insn.children()) - ba += parseLine(line); + foreach (const GdbMi &item, insn.children()) + result.appendLine(parseLine(item)); } else { // The non-mixed version. - ba += parseLine(child); + result.appendLine(parseLine(child)); } } - return _(ba); + return result; } void GdbEngine::handleFetchDisassemblerByLine(const GdbResponse &response) @@ -3950,10 +3963,10 @@ void GdbEngine::handleFetchDisassemblerByLine(const GdbResponse &response) && lines.childAt(0).findChild("line").data() == "0") fetchDisassemblerByAddress(ac, true); else { - QString contents = parseDisassembler(lines); - if (ac.agent->contentsCoversAddress(contents)) { + DisassemblerLines dlines = parseDisassembler(lines); + if (dlines.coversAddress(ac.agent->address())) { // All is well. - ac.agent->setContents(contents); + ac.agent->setContents(dlines); } else { // Can happen e.g. for initializer list on symbian/rvct where // we get a file name and line number but where the 'fully @@ -3985,9 +3998,9 @@ void GdbEngine::handleFetchDisassemblerByAddress1(const GdbResponse &response) if (lines.children().isEmpty()) fetchDisassemblerByAddress(ac, false); else { - QString contents = parseDisassembler(lines); - if (ac.agent->contentsCoversAddress(contents)) { - ac.agent->setContents(parseDisassembler(lines)); + DisassemblerLines dlines = parseDisassembler(lines); + if (dlines.coversAddress(ac.agent->address())) { + ac.agent->setContents(dlines); } else { showMessage(_("FALL BACK TO NON-MIXED")); fetchDisassemblerByAddress(ac, false); @@ -4030,11 +4043,11 @@ void GdbEngine::handleFetchDisassemblerByCli(const GdbResponse &response) if (lines.isValid()) { ac.agent->setContents(parseDisassembler(lines)); } else { - const QByteArray someSpace = " "; + const QString someSpace = _(" "); // First line is something like // "Dump of assembler code from 0xb7ff598f to 0xb7ff5a07:" GdbMi output = response.data.findChild("consolestreamoutput"); - QByteArray res; + DisassemblerLines dlines; QByteArray lastFunction; foreach (const QByteArray &line0, output.data().split('\n')) { QByteArray line = line0.trimmed(); @@ -4057,23 +4070,19 @@ void GdbEngine::handleFetchDisassemblerByCli(const GdbResponse &response) if (pos1 < pos2 && pos2 < pos3) { QByteArray function = line.mid(pos1, pos2 - pos1); if (function != lastFunction) { - res.append("\nFunction: "); - res.append(function); - res.append('\n'); + dlines.appendComment(QString()); + dlines.appendComment(_("Function: ") + _(function)); lastFunction = function; } line.replace(pos1, pos2 - pos1, ""); } - res.append(line); - res.append('\n'); + dlines.appendLine(DisassemblerLine(_(line))); continue; } - res.append(someSpace); - res.append(line); - res.append('\n'); + dlines.appendComment(someSpace + _(line)); } - if (res.size() > 1) - ac.agent->setContents(_(res)); + if (dlines.size()) + ac.agent->setContents(dlines); else fetchDisassemblerByAddressCli(ac); } diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index f225c5f89e3..814a43e7c72 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -59,6 +59,7 @@ class GdbMi; class WatchData; class DisassemblerAgentCookie; +class DisassemblerLines; class AttachGdbAdapter; class CoreGdbAdapter; @@ -404,7 +405,7 @@ private: ////////// View & Data Stuff ////////// void handleFetchDisassemblerByLine(const GdbResponse &response); void handleFetchDisassemblerByAddress1(const GdbResponse &response); void handleFetchDisassemblerByAddress0(const GdbResponse &response); - QString parseDisassembler(const GdbMi &lines); + DisassemblerLines parseDisassembler(const GdbMi &lines); // // Source file specific stuff diff --git a/src/plugins/debugger/lldb/ipcenginehost.cpp b/src/plugins/debugger/lldb/ipcenginehost.cpp index 02177850c49..2c0ee3d1994 100644 --- a/src/plugins/debugger/lldb/ipcenginehost.cpp +++ b/src/plugins/debugger/lldb/ipcenginehost.cpp @@ -446,9 +446,9 @@ void IPCEngineHost::rpcCallback(quint64 f, QByteArray payload) QString da; s >> pc; s >> da; - DisassemblerViewAgent *view = m_frameToDisassemblerAgent.take(pc); - if (view) - view->setContents(da); + //DisassemblerViewAgent *view = m_frameToDisassemblerAgent.take(pc); + //if (view) + // view->setContents(da); } break; case IPCEngineGuest::UpdateWatchData: -- GitLab