From 9412b138b6e3fc29e7d1a8c378d83ffaf40b026b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Fri, 24 Jul 2009 14:32:39 +0200 Subject: [PATCH 1/5] Made trailing slash trigger the next include completion The completion for the directory wasn't triggered because one of the items matched the typed string, so the list of completion wasn't empty and no new trigger was allowed. By not matching items when a trailing slash is typed, the list is allowed to trigger again from the new location. Reviewed-by: Daniel Molkentin --- src/plugins/cpptools/cppcodecompletion.cpp | 6 ++++++ src/plugins/texteditor/completionsupport.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 8fac72b95ed..21085093cf5 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -1386,6 +1386,12 @@ void CppCodeCompletion::completions(QList *completio else if (length > 0) { const QString key = m_editor->textAt(m_startPosition, length); + /* Close on the trailing slash for include completion, to enable the slash to + * trigger a new completion list. */ + if ((m_completionOperator == T_STRING_LITERAL || + m_completionOperator == T_ANGLE_STRING_LITERAL) && key.endsWith(QLatin1Char('/'))) + return; + if (m_completionOperator != T_LPAREN) { /* * This code builds a regular expression in order to more intelligently match diff --git a/src/plugins/texteditor/completionsupport.cpp b/src/plugins/texteditor/completionsupport.cpp index 2938ed3afec..33bfed1e9e1 100644 --- a/src/plugins/texteditor/completionsupport.cpp +++ b/src/plugins/texteditor/completionsupport.cpp @@ -129,7 +129,7 @@ void CompletionSupport::autoComplete_helper(ITextEditable *editor, bool forced, m_startPosition = m_completionCollector->startCompletion(editor); completionItems = getCompletions(); - QTC_ASSERT(m_startPosition != -1 || completionItems.size() == 0, return); + QTC_ASSERT(!(m_startPosition == -1 && completionItems.size() > 0), return); if (completionItems.isEmpty()) { cleanupCompletions(); From c2ea5e7b3f71450a16de05b9b4fae1833d23644e Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 24 Jul 2009 09:50:31 +0200 Subject: [PATCH 2/5] debugger: fix off-by-one error when accessing registers via trk --- tests/manual/trk/adapter.cpp | 10 ++++++++-- tests/manual/trk/trkserver.cpp | 8 +++----- tests/manual/trk/trkutils.h | 5 ++++- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/tests/manual/trk/adapter.cpp b/tests/manual/trk/adapter.cpp index 3b184968ed1..b382d0d53d8 100644 --- a/tests/manual/trk/adapter.cpp +++ b/tests/manual/trk/adapter.cpp @@ -537,7 +537,11 @@ void Adapter::handleGdbResponse(const QByteArray &response) #endif bool ok = false; uint registerNumber = response.mid(1).toInt(&ok, 16); - if (registerNumber < RegisterCount) { + if (registerNumber == RegisterPSGdb) { + QByteArray ba; + appendInt(&ba, m_snapshot.registers[RegisterPSTrk]); + sendGdbMessage(ba.toHex(), "read processor status register"); + } else if (registerNumber < RegisterCount) { QByteArray ba; appendInt(&ba, m_snapshot.registers[registerNumber]); sendGdbMessage(ba.toHex(), "read single known register"); @@ -1059,8 +1063,10 @@ void Adapter::handleAndReportReadRegisters(const TrkResult &result) // [80 0B 00 00 00 00 00 C9 24 FF BC 00 00 00 00 00 // 60 00 00 00 00 00 00 78 67 79 70 00 00 00 00 00...] const char *data = result.data.data(); - for (int i = 0; i < RegisterCount; ++i) + for (int i = 0; i < RegisterCount; ++i) { m_snapshot.registers[i] = extractInt(data + 4 * i); + //qDebug() << i << hexNumber(m_snapshot.registers[i], 8); + } //QByteArray ba = result.data.toHex(); QByteArray ba; diff --git a/tests/manual/trk/trkserver.cpp b/tests/manual/trk/trkserver.cpp index 8cf11d7133e..d5780f28adc 100644 --- a/tests/manual/trk/trkserver.cpp +++ b/tests/manual/trk/trkserver.cpp @@ -88,13 +88,13 @@ Inferior::Inferior() registers[7] = 0x00000000; registers[8] = 0x00000012; registers[9] = 0x00000040; - registers[10] = 0xC82AF210; + registers[10] = 0xC82AF210; registers[11] = 0x00000000; registers[12] = 0xC8000548; registers[13] = 0x00403ED0; registers[14] = 0x786A6BD8; registers[15] = 0x786A4CC8; - //registers[25] = 0x68000010; + registers[16] = 0x68000010; // that's reg 25 on chip? } class TrkServer : public QObject @@ -238,9 +238,7 @@ void TrkServer::handleAdapterMessage(const TrkResult &result) break; } case 0x12: { // Read Registers - appendByte(&data, 0x00); - appendByte(&data, 0x00); - appendByte(&data, 0x00); + data.clear(); for (int i = 0; i < RegisterCount; ++i) appendInt(&data, m_inferior.registers[i], BigEndian); writeToAdapter(0x80, result.token, data); diff --git a/tests/manual/trk/trkutils.h b/tests/manual/trk/trkutils.h index 811e4c6ebae..56d02ddaa0a 100644 --- a/tests/manual/trk/trkutils.h +++ b/tests/manual/trk/trkutils.h @@ -72,8 +72,11 @@ enum CodeMode enum TargetConstants { - RegisterCount = 16, + RegisterCount = 17, RegisterPC = 15, // Program counter + RegisterPSGdb = 25, // gdb's view of the world + RegisterPSTrk = 16, // gdb's view of the world + MemoryChunkSize = 256 }; From 403c344c4b1d59b0ba12c7cbe54f6f1f630e4c8d Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 24 Jul 2009 15:50:30 +0200 Subject: [PATCH 3/5] debugger: add a 'swapendian' 'tool' to convert endianness of memory dumps --- tests/manual/trk/adapter.cpp | 16 ++++++++++++++-- tests/manual/trk/run.sh | 1 + tests/manual/trk/swapendian.cpp | 23 +++++++++++++++++++++++ tests/manual/trk/swapendian.pro | 9 +++++++++ tests/manual/trk/trk.pro | 3 ++- 5 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 tests/manual/trk/swapendian.cpp create mode 100644 tests/manual/trk/swapendian.pro diff --git a/tests/manual/trk/adapter.cpp b/tests/manual/trk/adapter.cpp index b382d0d53d8..8071b537e46 100644 --- a/tests/manual/trk/adapter.cpp +++ b/tests/manual/trk/adapter.cpp @@ -396,7 +396,8 @@ void Adapter::handleGdbResponse(const QByteArray &response) else if (response == "!") { sendGdbAckMessage(); - sendGdbMessage("OK", "extended mode enabled"); + sendGdbMessage("", "extended mode not enabled"); + //sendGdbMessage("OK", "extended mode enabled"); } else if (response.startsWith("?")) { @@ -645,6 +646,16 @@ void Adapter::handleGdbResponse(const QByteArray &response) // // vCont[;action[:thread-id]]...' //} + else if (response.startsWith("vKill")) { + // kill + sendGdbAckMessage(); + QByteArray ba; + appendByte(&ba, 0); // Sub-command: Delete Process + appendInt(&ba, m_session.pid); + sendTrkMessage(0x41, 0, ba, "Delete process"); // Delete Item + sendGdbMessageAfterSync("", "process killed"); + } + else { logMessage("FIXME unknown: " + response); } @@ -886,7 +897,8 @@ void Adapter::handleResult(const TrkResult &result) // uint tid = extractInt(data + 8); // ThreadID: 4 bytes //logMessage(prefix << " ADDR: " << addr << " PID: " << pid << " TID: " << tid); sendTrkAck(result.token); - sendGdbMessage("S11", "Target stopped"); + //sendGdbMessage("S11", "Target stopped"); + sendGdbMessage("S05", "Target stopped"); break; } case 0x91: { // Notify Exception (obsolete) diff --git a/tests/manual/trk/run.sh b/tests/manual/trk/run.sh index de673606ba3..a0d14cadeae 100755 --- a/tests/manual/trk/run.sh +++ b/tests/manual/trk/run.sh @@ -10,6 +10,7 @@ trkservername="TRKSERVER-${userid}"; gdbserverip=127.0.0.1 gdbserverport=$[2222 + ${userid}] memorydump=TrkDump-78-6a-40-00.bin +memorydump=TrkDump-78-6a-40-00-BigEndian.bin fuser -n tcp -k ${gdbserverport} rm /tmp/${trkservername} diff --git a/tests/manual/trk/swapendian.cpp b/tests/manual/trk/swapendian.cpp new file mode 100644 index 00000000000..4b6dd5cb1c7 --- /dev/null +++ b/tests/manual/trk/swapendian.cpp @@ -0,0 +1,23 @@ + + +#include + +int main(int argc, char *argv[]) +{ + QFile file1(argv[1]); + file1.open(QIODevice::ReadOnly); + + QByteArray ba = file1.readAll(); + file1.close(); + + for (int i = 0; i < ba.size(); i += 4) { + char c = ba[i]; ba[i] = ba[i + 3]; ba[i + 3] = c; + c = ba[i + 1]; ba[i + 1] = ba[i + 2]; ba[i + 2] = c; + } + + QFile file2(argv[2]); + file2.open(QIODevice::WriteOnly); + file2.write(ba); + file2.close(); +} + diff --git a/tests/manual/trk/swapendian.pro b/tests/manual/trk/swapendian.pro new file mode 100644 index 00000000000..acf59908964 --- /dev/null +++ b/tests/manual/trk/swapendian.pro @@ -0,0 +1,9 @@ + +TEMPLATE = app + +QT = core + +HEADERS += \ + +SOURCES += \ + swapendian.cpp diff --git a/tests/manual/trk/trk.pro b/tests/manual/trk/trk.pro index 7d5f33e4eab..a461bb70566 100644 --- a/tests/manual/trk/trk.pro +++ b/tests/manual/trk/trk.pro @@ -1,7 +1,8 @@ TEMPLATE = subdirs -SUBDIRS = trkserver adapter +SUBDIRS = trkserver adapter swapendian trkserver.file = trkserver.pro adapter.file = adapter.pro +swapendian.file = swapendian.pro From 8b8bf42fbb94311804d6a2f6361ec691467b6e41 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 24 Jul 2009 16:05:46 +0200 Subject: [PATCH 4/5] CDB: Fixed thread handling, added dumping of string types in case of crashes. --- dist/changes-1.3.0 | 3 + src/plugins/debugger/cdb/cdbdebugengine.cpp | 59 +++-- src/plugins/debugger/cdb/cdbdebugengine_p.h | 2 +- .../debugger/cdb/cdbstackframecontext.cpp | 20 +- .../debugger/cdb/cdbsymbolgroupcontext.cpp | 208 ++++++++++++++++++ .../debugger/cdb/cdbsymbolgroupcontext.h | 40 +++- .../debugger/cdb/cdbsymbolgroupcontext_tpl.h | 46 ++-- src/plugins/debugger/stackhandler.h | 1 + src/plugins/debugger/watchutils.cpp | 25 ++- 9 files changed, 348 insertions(+), 56 deletions(-) diff --git a/dist/changes-1.3.0 b/dist/changes-1.3.0 index 25d8e12256c..0c1fa497ed5 100644 --- a/dist/changes-1.3.0 +++ b/dist/changes-1.3.0 @@ -15,6 +15,8 @@ Debugging * CDB: Added more types to the dumpers (QSharedPointer, QVector, common * QMap/QSet types), dereference reference parameters * CDB: Simplified display of STL types in the locals window + * CDB: Fixed thread handling + * CDB: Added internal dumpers for string types for debuggee crashes * Improved QObject dumping, print out QRect/QSize, enumerations and flags General: @@ -39,3 +41,4 @@ Wizards * Added version control checkout wizards * Added a license header template setting * Added a wizard for Qt Designer custom widgets + * Added a gitorious clone wizard diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index 365252f876a..b914986a0b4 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -1177,8 +1177,11 @@ void CdbDebugEngine::selectThread(int index) ThreadsHandler *threadsHandler = m_d->m_debuggerManagerAccess->threadsHandler(); threadsHandler->setCurrentThread(index); - m_d->m_currentThreadId = index; - m_d->updateStackTrace(); + const int newThreadId = threadsHandler->threads().at(index).id; + if (newThreadId != m_d->m_currentThreadId) { + m_d->m_currentThreadId = threadsHandler->threads().at(index).id; + m_d->updateStackTrace(); + } } void CdbDebugEngine::attemptBreakpointSynchronization() @@ -1223,7 +1226,7 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa m_cif.debugSymbols, m_debuggerManagerAccess->breakHandler(), errorMessage, &warnings); - if (const int warningsCount = warnings.size()) + if (const int warningsCount = warnings.size()) for (int w = 0; w < warningsCount; w++) m_engine->warning(warnings.at(w)); return ok; @@ -1390,6 +1393,16 @@ void CdbDebugEnginePrivate::notifyCrashed() m_dumper->disable(); } +static int threadIndexById(const ThreadsHandler *threadsHandler, int id) +{ + const QList threads = threadsHandler->threads(); + const int count = threads.count(); + for (int i = 0; i < count; i++) + if (threads.at(i).id == id) + return i; + return -1; +} + void CdbDebugEnginePrivate::handleDebugEvent() { if (debugCDB) @@ -1401,10 +1414,15 @@ void CdbDebugEnginePrivate::handleDebugEvent() m_breakEventMode = BreakEventHandle; switch (mode) { - case BreakEventHandle: + case BreakEventHandle: { m_debuggerManagerAccess->notifyInferiorStopped(); - updateThreadList(); + m_currentThreadId = updateThreadList(); + ThreadsHandler *threadsHandler = m_debuggerManagerAccess->threadsHandler(); + const int threadIndex = threadIndexById(threadsHandler, m_currentThreadId); + if (threadIndex != -1) + threadsHandler->setCurrentThread(threadIndex); updateStackTrace(); + } break; case BreakEventIgnoreOnce: m_engine->startWatchTimer(); @@ -1430,7 +1448,7 @@ void CdbDebugEnginePrivate::setDebuggeeHandles(HANDLE hDebuggeeProcess, HANDLE m_hDebuggeeThread = hDebuggeeThread; } -void CdbDebugEnginePrivate::updateThreadList() +ULONG CdbDebugEnginePrivate::updateThreadList() { if (debugCDB) qDebug() << Q_FUNC_INFO << m_hDebuggeeProcess; @@ -1439,25 +1457,25 @@ void CdbDebugEnginePrivate::updateThreadList() QList threads; bool success = false; QString errorMessage; + ULONG currentThreadId = 0; do { - ULONG numberOfThreads; - HRESULT hr= m_cif.debugSystemObjects->GetNumberThreads(&numberOfThreads); + ULONG threadCount; + HRESULT hr= m_cif.debugSystemObjects->GetNumberThreads(&threadCount); if (FAILED(hr)) { errorMessage= msgComFailed("GetNumberThreads", hr); break; } - const ULONG maxThreadIds = 256; - ULONG threadIds[maxThreadIds]; - ULONG biggestThreadId = qMin(maxThreadIds, numberOfThreads - 1); - hr = m_cif.debugSystemObjects->GetThreadIdsByIndex(0, biggestThreadId, threadIds, 0); - if (FAILED(hr)) { - errorMessage= msgComFailed("GetThreadIdsByIndex", hr); - break; - } - for (ULONG threadId = 0; threadId <= biggestThreadId; ++threadId) { - ThreadData thread; - thread.id = threadId; - threads.append(thread); + // Get ids and index of current + if (threadCount) { + m_cif.debugSystemObjects->GetCurrentThreadId(¤tThreadId); + QVector threadIds(threadCount); + hr = m_cif.debugSystemObjects->GetThreadIdsByIndex(0, threadCount, &(*threadIds.begin()), 0); + if (FAILED(hr)) { + errorMessage= msgComFailed("GetThreadIdsByIndex", hr); + break; + } + for (ULONG i = 0; i < threadCount; i++) + threads.push_back(ThreadData(threadIds.at(i))); } th->setThreads(threads); @@ -1465,6 +1483,7 @@ void CdbDebugEnginePrivate::updateThreadList() } while (false); if (!success) m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage)); + return currentThreadId; } void CdbDebugEnginePrivate::updateStackTrace() diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h index 23eb5648275..53e6737343e 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine_p.h +++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h @@ -115,7 +115,7 @@ struct CdbDebugEnginePrivate bool isDebuggeeRunning() const { return m_watchTimer != -1; } void handleDebugEvent(); - void updateThreadList(); + ULONG updateThreadList(); void updateStackTrace(); void updateModules(); diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp index f68beb0db3c..8c14d45fff9 100644 --- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp @@ -40,7 +40,7 @@ namespace Debugger { namespace Internal { -enum { OwnerNewItem, OwnerSymbolGroup, OwnerDumper }; +enum { OwnerNewItem, OwnerSymbolGroup, OwnerSymbolGroupDumper , OwnerDumper }; typedef QSharedPointer SharedPointerCdbDumperHelper; typedef QList WatchDataList; @@ -216,6 +216,12 @@ WatchHandleDumperInserter &WatchHandleDumperInserter::operator=(WatchData &wd) wd.source = OwnerDumper; return *this; } + // Expanded by internal dumper? : ok + if (wd.source == OwnerSymbolGroupDumper) { + m_wh->insertData(wd); + return *this; + } + // Try library dumpers. switch (m_dumper->dumpType(wd, true, OwnerDumper, &m_dumperResult, &errorMessage)) { case CdbDumperHelper::DumpOk: if (debugCDBWatchHandling) @@ -258,13 +264,15 @@ bool CdbStackFrameContext::populateModelInitially(WatchHandler *wh, QString *err qDebug() << "populateModelInitially dumpers=" << m_useDumpers; // Recurse down items that are initially expanded in the view, stop processing for // dumper items. + const CdbSymbolGroupRecursionContext rctx(m_symbolContext, OwnerSymbolGroupDumper, + m_dumper->comInterfaces()->debugDataSpaces); const bool rc = m_useDumpers ? - CdbSymbolGroupContext::populateModelInitially(m_symbolContext, + CdbSymbolGroupContext::populateModelInitially(rctx, WatchHandleDumperInserter(wh, m_dumper), WatchHandlerExpandedPredicate(wh), isDumperPredicate, errorMessage) : - CdbSymbolGroupContext::populateModelInitially(m_symbolContext, + CdbSymbolGroupContext::populateModelInitially(rctx, WatchHandlerModelInserter(wh), WatchHandlerExpandedPredicate(wh), falsePredicate, @@ -279,9 +287,11 @@ bool CdbStackFrameContext::completeData(const WatchData &incompleteLocal, if (debugCDBWatchHandling) qDebug() << ">completeData src=" << incompleteLocal.source << incompleteLocal.toString(); + const CdbSymbolGroupRecursionContext rctx(m_symbolContext, OwnerSymbolGroupDumper, + m_dumper->comInterfaces()->debugDataSpaces); // Expand symbol group items, recurse one level from desired item if (!m_useDumpers) { - return CdbSymbolGroupContext::completeData(m_symbolContext, incompleteLocal, + return CdbSymbolGroupContext::completeData(rctx, incompleteLocal, WatchHandlerModelInserter(wh), MatchINamePredicate(incompleteLocal.iname), falsePredicate, @@ -311,7 +321,7 @@ bool CdbStackFrameContext::completeData(const WatchData &incompleteLocal, } // Expand symbol group items, recurse one level from desired item - return CdbSymbolGroupContext::completeData(m_symbolContext, incompleteLocal, + return CdbSymbolGroupContext::completeData(rctx, incompleteLocal, WatchHandleDumperInserter(wh, m_dumper), MatchINamePredicate(incompleteLocal.iname), isDumperPredicate, diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp index 5d82835f53d..ef854c8b360 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp @@ -33,15 +33,22 @@ #include "watchutils.h" #include +#include #include enum { debug = 0 }; +enum { debugInternalDumpers = 0 }; static inline QString msgSymbolNotFound(const QString &s) { return QString::fromLatin1("The symbol '%1' could not be found.").arg(s); } +static inline QString msgOutOfScope() +{ + return QCoreApplication::translate("SymbolGroup", "Out of scope"); +} + static inline bool isTopLevelSymbol(const DEBUG_SYMBOL_PARAMETERS &p) { return p.ParentSymbol == DEBUG_ANY_ID; @@ -102,6 +109,16 @@ static inline QString getSymbolString(IDebugSymbolGroup2 *sg, namespace Debugger { namespace Internal { + +CdbSymbolGroupRecursionContext::CdbSymbolGroupRecursionContext(CdbSymbolGroupContext *ctx, + int ido, + CIDebugDataSpaces *ds) : + context(ctx), + internalDumperOwner(ido), + dataspaces(ds) +{ +} + static inline CdbSymbolGroupContext::SymbolState getSymbolState(const DEBUG_SYMBOL_PARAMETERS &p) { if (p.SubElements == 0u) @@ -419,6 +436,13 @@ WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const return wd; } +WatchData CdbSymbolGroupContext::dumpSymbolAt(CIDebugDataSpaces *ds, unsigned long index) +{ + WatchData rc = symbolAt(index); + dump(ds, &rc); + return rc; +} + bool CdbSymbolGroupContext::assignValue(const QString &iname, const QString &value, QString *newValue, QString *errorMessage) { @@ -561,5 +585,189 @@ bool CdbSymbolGroupContext::debugValueToInteger(const DEBUG_VALUE &dv, qint64 *v return false; } +/* The special type dumpers have an integer return code meaning: + * 0: ok + * 1: Dereferencing or retrieving memory failed, this is out of scope, + * do not try to query further. + * > 1: A structural error was encountered, that is, the implementation + * of the class changed (Qt or say, a different STL implementation). + * Visibly warn about it. + * To add further types, have a look at the toString() output of the + * symbol group. */ + +static QString msgStructuralError(const QString &type, int code) +{ + return QString::fromLatin1("Warning: Internal dumper for '%1' failed with %2.").arg(type).arg(code); +} + +static inline bool isStdStringOrPointer(const QString &type) +{ +#define STD_WSTRING "std::basic_string,std::allocator >" +#define STD_STRING "std::basic_string,std::allocator >" + return type.endsWith(QLatin1String(STD_STRING)) + || type.endsWith(QLatin1String(STD_STRING" *")) + || type.endsWith(QLatin1String(STD_WSTRING)) + || type.endsWith(QLatin1String(STD_WSTRING" *")); +#undef STD_WSTRING +#undef STD_STRING +} + +CdbSymbolGroupContext::DumperResult + CdbSymbolGroupContext::dump(CIDebugDataSpaces *ds, WatchData *wd) +{ + DumperResult rc = DumperNotHandled; + do { + // Is this a previously detected Null-Pointer? + if (wd->isHasChildrenKnown() && !wd->hasChildren) + break; + // QString + if (wd->type.endsWith(QLatin1String("QString")) || wd->type.endsWith(QLatin1String("QString *"))) { + const int drc = dumpQString(ds, wd); + switch (drc) { + case 0: + rc = DumperOk; + break; + case 1: + rc = DumperError; + break; + default: + qWarning("%s\n", qPrintable(msgStructuralError(wd->type, drc))); + rc = DumperNotHandled; + break; + } + } + // StdString + if (isStdStringOrPointer(wd->type)) { + const int drc = dumpStdString(wd); + switch (drc) { + case 0: + rc = DumperOk; + break; + case 1: + rc = DumperError; + break; + default: + qWarning("%s\n", qPrintable(msgStructuralError(wd->type, drc))); + rc = DumperNotHandled; + break; + } + + } + } while (false); + if (debugInternalDumpers) + qDebug() << "CdbSymbolGroupContext::dump" << rc << wd->toString(); + return rc; +} + +// Get integer value of symbol group +static inline bool getIntValue(CIDebugSymbolGroup *sg, int index, int *value) +{ + const QString valueS = getSymbolString(sg, &IDebugSymbolGroup2::GetSymbolValueTextWide, index); + bool ok; + *value = valueS.toInt(&ok); + return ok; +} + +// Get pointer value of symbol group ("0xAAB") +static inline bool getPointerValue(CIDebugSymbolGroup *sg, int index, quint64 *value) +{ + *value = 0; + QString valueS = getSymbolString(sg, &IDebugSymbolGroup2::GetSymbolValueTextWide, index); + if (!valueS.startsWith(QLatin1String("0x"))) + return false; + valueS.remove(0, 2); + bool ok; + *value = valueS.toULongLong(&ok, 16); + return ok; +} + +int CdbSymbolGroupContext::dumpQString(CIDebugDataSpaces *ds, WatchData *wd) +{ + const int maxLength = 40; + QString errorMessage; + unsigned long stringIndex; + if (!lookupPrefix(wd->iname, &stringIndex)) + return 1; + + // Expand string and it's "d" (step over 'static null') + if (!expandSymbol(wd->iname, stringIndex, &errorMessage)) + return 2; + const unsigned long dIndex = stringIndex + 4; + if (!expandSymbol(wd->iname, dIndex, &errorMessage)) + return 3; + const unsigned long sizeIndex = dIndex + 3; + const unsigned long arrayIndex = dIndex + 4; + // Get size and pointer + int size; + if (!getIntValue(m_symbolGroup, sizeIndex, &size)) + return 4; + quint64 array; + if (!getPointerValue(m_symbolGroup, arrayIndex, &array)) + return 5; + // Fetch + const bool truncated = size > maxLength; + if (truncated) + size = maxLength; + const QChar doubleQuote = QLatin1Char('"'); + QString value(doubleQuote); + if (size) { + // Should this ever be a remote debugger, need to check byte order. + unsigned short *buf = new unsigned short[size + 1]; + unsigned long bytesRead; + const HRESULT hr = ds->ReadVirtual(array, buf, size * sizeof(unsigned short), &bytesRead); + if (FAILED(hr)) { + delete [] buf; + return 1; + } + buf[bytesRead / sizeof(unsigned short)] = 0; + value += QString::fromUtf16(buf); + delete [] buf; + if (truncated) + value += QLatin1String("..."); + } + value += doubleQuote; + wd->setValue(value); + wd->setHasChildren(false); + return 0; +} + +int CdbSymbolGroupContext::dumpStdString(WatchData *wd) +{ + const int maxLength = 40; + QString errorMessage; + unsigned long stringIndex; + if (!lookupPrefix(wd->iname, &stringIndex)) + return 1; + + // Expand string ->string_val->_bx. + if (!expandSymbol(wd->iname, stringIndex, &errorMessage)) + return 1; + const unsigned long bxIndex = stringIndex + 3; + if (!expandSymbol(wd->iname, bxIndex, &errorMessage)) + return 2; + // Check if size is something sane + const int sizeIndex = stringIndex + 6; + int size; + if (!getIntValue(m_symbolGroup, sizeIndex, &size)) + return 3; + if (size < 0) + return 1; + // Just copy over the value of the buf[]-array, which should be the string + const QChar doubleQuote = QLatin1Char('"'); + const int bufIndex = stringIndex + 4; + QString bufValue = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, bufIndex); + const int quotePos = bufValue.indexOf(doubleQuote); + if (quotePos == -1) + return 1; + bufValue.remove(0, quotePos); + if (bufValue.size() > maxLength) { + bufValue.truncate(maxLength); + bufValue += QLatin1String("...\""); + } + wd->setValue(bufValue); + wd->setHasChildren(false); + return 0; +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h index 91ec5fd9240..24fc355d375 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h @@ -46,6 +46,7 @@ namespace Internal { class WatchData; class WatchHandler; +struct CdbSymbolGroupRecursionContext; /* A thin wrapper around the IDebugSymbolGroup2 interface which represents * a flat list of symbols using an index (for example, belonging to a stack @@ -73,7 +74,7 @@ class CdbSymbolGroupContext public: ~CdbSymbolGroupContext(); static CdbSymbolGroupContext *create(const QString &prefix, - CIDebugSymbolGroup *symbolGroup, + CIDebugSymbolGroup *symbolGroup, QString *errorMessage); QString prefix() const { return m_prefix; } @@ -87,7 +88,7 @@ public: // to terminate processing after insertion of an item (if the calling // routine wants to insert another subtree). template - static bool populateModelInitially(CdbSymbolGroupContext *sg, + static bool populateModelInitially(const CdbSymbolGroupRecursionContext &ctx, OutputIterator it, RecursionPredicate recursionPredicate, IgnorePredicate ignorePredicate, @@ -99,7 +100,7 @@ public: // to terminate processing after insertion of an item (if the calling // routine wants to insert another subtree). template - static bool completeData (CdbSymbolGroupContext *sg, + static bool completeData (const CdbSymbolGroupRecursionContext &ctx, WatchData incompleteLocal, OutputIterator it, RecursionPredicate recursionPredicate, @@ -108,9 +109,19 @@ public: // Retrieve child symbols of prefix as a sequence of WatchData. template - bool getChildSymbols(const QString &prefix, OutputIterator it, QString *errorMessage); + bool getChildSymbols(const QString &prefix, OutputIterator it, QString *errorMessage) + { return getDumpChildSymbols(0, prefix, 0, it, errorMessage); } + // Retrieve child symbols of prefix as a sequence of WatchData. + // Is CIDebugDataSpaces is != 0, try internal dumper and set owner + template + bool getDumpChildSymbols(CIDebugDataSpaces *ds, const QString &prefix, + int dumpedOwner, + OutputIterator it, QString *errorMessage); WatchData symbolAt(unsigned long index) const; + // Run the internal dumpers on the symbol + WatchData dumpSymbolAt(CIDebugDataSpaces *ds, unsigned long index); + bool lookupPrefix(const QString &prefix, unsigned long *index) const; enum SymbolState { LeafSymbol, ExpandedSymbol, CollapsedSymbol }; @@ -127,6 +138,10 @@ public: // format an array of unsigned longs as "0x323, 0x2322, ..." static QString hexFormatArray(const unsigned short *array, int size); + // Dump + enum DumperResult { DumperOk, DumperError, DumperNotHandled }; + DumperResult dump(CIDebugDataSpaces *ds, WatchData *wd); + private: typedef QMap NameIndexMap; @@ -140,8 +155,11 @@ private: unsigned long *parentId, QString *errorMessage); bool expandSymbol(const QString &prefix, unsigned long index, QString *errorMessage); - void populateINameIndexMap(const QString &prefix, unsigned long parentId, unsigned long start, unsigned long count); - QString symbolINameAt(unsigned long index) const; + void populateINameIndexMap(const QString &prefix, unsigned long parentId, unsigned long start, unsigned long count); + QString symbolINameAt(unsigned long index) const; + + int dumpQString(CIDebugDataSpaces *ds, WatchData *wd); + int dumpStdString(WatchData *wd); inline DEBUG_SYMBOL_PARAMETERS *symbolParameters() { return &(*m_symbolParameters.begin()); } inline const DEBUG_SYMBOL_PARAMETERS *symbolParameters() const { return &(*m_symbolParameters.constBegin()); } @@ -155,6 +173,16 @@ private: int m_unnamedSymbolNumber; }; + +// A convenience struct to save parameters for the model recursion. +struct CdbSymbolGroupRecursionContext { + explicit CdbSymbolGroupRecursionContext(CdbSymbolGroupContext *ctx, int internalDumperOwner, CIDebugDataSpaces *ds); + + CdbSymbolGroupContext *context; + int internalDumperOwner; + CIDebugDataSpaces *dataspaces; +}; + // Helper to a sequence of WatchData into a list. class WatchDataBackInserter { diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h index ccaba97ee89..561b0ac57b3 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h @@ -48,18 +48,32 @@ enum { debugSgRecursion = 0 }; } template -bool CdbSymbolGroupContext::getChildSymbols(const QString &prefix, OutputIterator it, QString *errorMessage) +bool CdbSymbolGroupContext::getDumpChildSymbols(CIDebugDataSpaces *ds, const QString &prefix, + int dumpedOwner, + OutputIterator it, QString *errorMessage) { unsigned long start; unsigned long parentId; if (!getChildSymbolsPosition(prefix, &start, &parentId, errorMessage)) return false; - // Skip over expanded children - const unsigned long end = m_symbolParameters.size(); - for (unsigned long s = start; s < end; ++s) { + // Skip over expanded children. Internal dumping might expand + // children, so, re-evaluate size in end condition. + for (int s = start; s < m_symbolParameters.size(); ++s) { const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(s); if (p.ParentSymbol == parentId && isSymbolDisplayable(p)) { - *it = symbolAt(s); + WatchData wd = symbolAt(s); + // Run internal dumper, mark ownership + if (ds) { + switch (dump(ds, &wd)) { + case DumperOk: + case DumperError: // Not initialized yet, do not run other dumpers + wd.source = dumpedOwner; + break; + case DumperNotHandled: + break; + } + } + *it = wd; ++it; } } @@ -73,7 +87,7 @@ bool CdbSymbolGroupContext::getChildSymbols(const QString &prefix, OutputIterato // (expand icon), though (ignore for simplicity). template bool insertSymbolRecursion(WatchData wd, - CdbSymbolGroupContext *sg, + const CdbSymbolGroupRecursionContext &ctx, OutputIterator it, RecursionPredicate recursionPredicate, IgnorePredicate ignorePredicate, @@ -110,13 +124,16 @@ bool insertSymbolRecursion(WatchData wd, return true; QList watchList; // This implicitly enforces expansion - if (!sg->getChildSymbols(wd.iname, WatchDataBackInserter(watchList), errorMessage)) + if (!ctx.context->getDumpChildSymbols(ctx.dataspaces, + wd.iname, + ctx.internalDumperOwner, + WatchDataBackInserter(watchList), errorMessage)) return false; const int childCount = watchList.size(); for (int c = 0; c < childCount; c++) { const WatchData &cwd = watchList.at(c); if (wd.isValid()) { // We sometimes get empty names for deeply nested data - if (!insertSymbolRecursion(cwd, sg, it, recursionPredicate, ignorePredicate, errorMessage)) + if (!insertSymbolRecursion(cwd, ctx, it, recursionPredicate, ignorePredicate, errorMessage)) return false; } else { const QString msg = QString::fromLatin1("WARNING: Skipping invalid child symbol #%2 (type %3) of '%4'."). @@ -128,7 +145,7 @@ bool insertSymbolRecursion(WatchData wd, } template -bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg, +bool CdbSymbolGroupContext::populateModelInitially(const CdbSymbolGroupRecursionContext &ctx, OutputIterator it, RecursionPredicate recursionPredicate, IgnorePredicate ignorePredicate, @@ -139,17 +156,20 @@ bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg, // Insert root items QList watchList; - if (!sg->getChildSymbols(sg->prefix(), WatchDataBackInserter(watchList), errorMessage)) + CdbSymbolGroupContext *sg = ctx.context; + if (!sg->getDumpChildSymbols(ctx.dataspaces, sg->prefix(), + ctx.internalDumperOwner, + WatchDataBackInserter(watchList), errorMessage)) return false; // Insert data foreach(const WatchData &wd, watchList) - if (!insertSymbolRecursion(wd, sg, it, recursionPredicate, ignorePredicate, errorMessage)) + if (!insertSymbolRecursion(wd, ctx, it, recursionPredicate, ignorePredicate, errorMessage)) return false; return true; } template -bool CdbSymbolGroupContext::completeData(CdbSymbolGroupContext *sg, +bool CdbSymbolGroupContext::completeData(const CdbSymbolGroupRecursionContext &ctx, WatchData incompleteLocal, OutputIterator it, RecursionPredicate recursionPredicate, @@ -160,7 +180,7 @@ bool CdbSymbolGroupContext::completeData(CdbSymbolGroupContext *sg, qDebug().nospace() << "###>CdbSymbolGroupContext::completeData" << ' ' << incompleteLocal.iname << '\n'; // If the symbols are already expanded in the context, they will be re-inserted, // which is not handled for simplicity. - if (!insertSymbolRecursion(incompleteLocal, sg, it, recursionPredicate, ignorePredicate, errorMessage)) + if (!insertSymbolRecursion(incompleteLocal, ctx, it, recursionPredicate, ignorePredicate, errorMessage)) return false; return true; } diff --git a/src/plugins/debugger/stackhandler.h b/src/plugins/debugger/stackhandler.h index 538eef992e6..aca6527ce23 100644 --- a/src/plugins/debugger/stackhandler.h +++ b/src/plugins/debugger/stackhandler.h @@ -103,6 +103,7 @@ private: struct ThreadData { + ThreadData(int threadId = 0) : id(threadId) {} int id; }; diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 490fd2a64a8..49b4cc02c56 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -567,21 +567,24 @@ QList QtDumperResult::toWatchData(int source) const wchild.valuedisabled = dchild.valuedisabled; wchild.setValue(decodeData(dchild.value, dchild.valueEncoded)); } - wchild.setType(dchild.type.isEmpty() ? childType : dchild.type); wchild.setAddress(dchild.address); - // Child overrides. - const int effectiveChildChildCount = dchild.childCount == -1 ? childChildCount : dchild.childCount; - switch (effectiveChildChildCount) { + // The type setter sets hasChildren for known types. + wchild.setType(dchild.type.isEmpty() ? childType : dchild.type); + if (wchild.isHasChildrenNeeded()) { + // Child overrides. + const int effectiveChildChildCount = dchild.childCount == -1 ? childChildCount : dchild.childCount; + switch (effectiveChildChildCount) { case -1: - wchild.setChildrenNeeded(); - wchild.setHasChildrenNeeded(); - break; + wchild.setChildrenNeeded(); + wchild.setHasChildrenNeeded(); + break; case 0: - wchild.setHasChildren(false); - break; + wchild.setHasChildren(false); + break; default: - wchild.setHasChildren(true); - break; + wchild.setHasChildren(true); + break; + } } } } From 2e19e70a8378f26b960ee5ed51f2d03a9074397d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Fri, 24 Jul 2009 16:17:58 +0200 Subject: [PATCH 5/5] Updated changes file with completion of include directives --- dist/changes-1.3.0 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dist/changes-1.3.0 b/dist/changes-1.3.0 index 0c1fa497ed5..6f4cbe5b3c9 100644 --- a/dist/changes-1.3.0 +++ b/dist/changes-1.3.0 @@ -16,7 +16,7 @@ Debugging * QMap/QSet types), dereference reference parameters * CDB: Simplified display of STL types in the locals window * CDB: Fixed thread handling - * CDB: Added internal dumpers for string types for debuggee crashes + * CDB: Added internal dumpers for string types for debugger crashes * Improved QObject dumping, print out QRect/QSize, enumerations and flags General: @@ -26,6 +26,7 @@ General: Editing: * Added support for text editor color schemes * Added highlighting of uses of the symbol under the cursor + * Added completion of include directives * Added the option to turn off marking of text changes Project support: