OSDN Git Service

debugger: make debugger view data store more structured
authorhjk <qtc-committer@nokia.com>
Wed, 24 Nov 2010 14:55:09 +0000 (15:55 +0100)
committerhjk <qtc-committer@nokia.com>
Wed, 24 Nov 2010 14:55:45 +0000 (15:55 +0100)
src/plugins/debugger/cdb2/cdbparsehelpers.cpp
src/plugins/debugger/cdb2/cdbparsehelpers.h
src/plugins/debugger/debuggeragents.cpp
src/plugins/debugger/debuggeragents.h
src/plugins/debugger/gdb/gdbengine.cpp
src/plugins/debugger/gdb/gdbengine.h
src/plugins/debugger/lldb/ipcenginehost.cpp

index c2a9bf3..1a1ad80 100644 (file)
@@ -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'
index 6ee8b03..5ada861 100644 (file)
@@ -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);
index e161784..aa4247b 100644 (file)
 
 #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
@@ -417,19 +402,53 @@ 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
index 3db8900..7cbcdae 100644 (file)
@@ -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;
 };
index 4e93dfb..92235c1 100644 (file)
@@ -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);
         }
index f225c5f..814a43e 100644 (file)
@@ -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
index 0217785..2c0ee3d 100644 (file)
@@ -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: