diff --git a/dist/changes-1.3.0 b/dist/changes-1.3.0 index 25d8e12256c98cb5c2125010f70439fe4588d34f..6f4cbe5b3c97a19d5fa1df90bc314fe9ebc13a81 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 debugger crashes * Improved QObject dumping, print out QRect/QSize, enumerations and flags General: @@ -24,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: @@ -39,3 +42,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/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 8fac72b95edc26ec8cee0e101ffb7ff0d02fdafd..21085093cf5ecaf48ef6c1f73479978bbd841acf 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -1386,6 +1386,12 @@ void CppCodeCompletion::completions(QList<TextEditor::CompletionItem> *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/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index 365252f876a61688189f96c50ae7e09714bc0f40..b914986a0b4194d6b60caa751daeaf48744fe2f5 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<ThreadData> 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<ThreadData> 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<ULONG> 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 23eb56482755ce9ae4cc308d8771464da25b94fe..53e6737343e70cd2d3fcdb7d434b984ef3612fc7 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 f68beb0db3cccc1b114f87a3311be4f9009ce912..8c14d45fff946c8b20bdbdf01e2b2809d24ee95c 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<CdbDumperHelper> SharedPointerCdbDumperHelper; typedef QList<WatchData> 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 5d82835f53dad00e411b14623ca7fd350413df5d..ef854c8b3600af9da676c47e8654a5e11bb91afc 100644 --- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp @@ -33,15 +33,22 @@ #include "watchutils.h" #include <QtCore/QTextStream> +#include <QtCore/QCoreApplication> #include <QtCore/QRegExp> 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<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >" +#define STD_STRING "std::basic_string<char,std::char_traits<char>,std::allocator<char> >" + 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 91ec5fd92400f599b2251d350fa539a2ab8b8dae..24fc355d375c4607f389c23834b31551372ce1fb 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 <class OutputIterator, class RecursionPredicate, class IgnorePredicate> - 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 <class OutputIterator, class RecursionPredicate, class IgnorePredicate> - 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 <class OutputIterator> - 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 <class OutputIterator> + 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<QString, unsigned long> 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 ccaba97ee893f600c8afbe0e8d29717fa338a7fb..561b0ac57b361910892089b020dbc4d134734690 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 <class OutputIterator> -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 <class OutputIterator, class RecursionPredicate, class IgnorePredicate> 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<WatchData> 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 <class OutputIterator, class RecursionPredicate, class IgnorePredicate> -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<WatchData> 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 <class OutputIterator, class RecursionPredicate, class IgnorePredicate> -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 538eef992e61b89387d08be1db9ffbeae4c64a3a..aca6527ce23fa520fdd9b5cac43a839d7ca054aa 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 490fd2a64a89a35c3bbd392eb140a54541570a44..49b4cc02c569b9056066e09d7db0c0a7463f4660 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -567,21 +567,24 @@ QList<WatchData> 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; + } } } } diff --git a/src/plugins/texteditor/completionsupport.cpp b/src/plugins/texteditor/completionsupport.cpp index 2938ed3afeca74f8faba43fc2655cd8c3ee86809..33bfed1e9e15975d9ed008e94468b9d30bb4f0e4 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(); diff --git a/tests/manual/trk/adapter.cpp b/tests/manual/trk/adapter.cpp index 3b184968ed1c5b8142f5fac237f64cd16266c287..8071b537e46e5e31e7822a2b4dcf1acbdcb282b7 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("?")) { @@ -537,7 +538,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"); @@ -641,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); } @@ -882,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) @@ -1059,8 +1075,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/run.sh b/tests/manual/trk/run.sh index de673606ba3d80da53d832410efd9ba070d5942c..a0d14cadeae347928a903ad4d54ede3c58056fbd 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 0000000000000000000000000000000000000000..4b6dd5cb1c7c30e52ca14c685e270a79010bfdf5 --- /dev/null +++ b/tests/manual/trk/swapendian.cpp @@ -0,0 +1,23 @@ + + +#include <QtCore> + +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 0000000000000000000000000000000000000000..acf599089647e888686c75601009488f72f09448 --- /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 7d5f33e4eabf7502a6625ddb12fdb2f2a5bfbbc6..a461bb70566ec03c593cda5c127bc41d37a5f6c8 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 diff --git a/tests/manual/trk/trkserver.cpp b/tests/manual/trk/trkserver.cpp index 8cf11d7133e0936bd257d57f4b37220d257ff431..d5780f28adc49097db1ef7e90e804f4fc5013784 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 811e4c6ebae41a4fe68432fcd5fb04315c633fcd..56d02ddaa0a963874d52365231be7544ee9464f3 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 };