diff --git a/src/libs/qtcreatorcdbext/common.h b/src/libs/qtcreatorcdbext/common.h index 1fd427368fec863cb7cd06858fd6fca968222c81..3263d69351d125bac5f96ff0f4e39a91a0cfc407 100644 --- a/src/libs/qtcreatorcdbext/common.h +++ b/src/libs/qtcreatorcdbext/common.h @@ -46,8 +46,6 @@ #include <wdbgexts.h> #include <dbgeng.h> -static const char creatorOutputPrefixC[] = "QtCreatorExt: "; - typedef IDebugControl CIDebugControl; typedef IDebugSymbols3 CIDebugSymbols; typedef IDebugSymbolGroup2 CIDebugSymbolGroup; diff --git a/src/libs/qtcreatorcdbext/eventcallback.h b/src/libs/qtcreatorcdbext/eventcallback.h index b066923dd25332a6b89f3d34e28b519b03e676e4..d6e9b9daa0f03c2fcd15f60a00eaf9b8198c541e 100644 --- a/src/libs/qtcreatorcdbext/eventcallback.h +++ b/src/libs/qtcreatorcdbext/eventcallback.h @@ -37,8 +37,8 @@ #include "common.h" #include "extensioncontext.h" -/* IDebugEventCallbacks event handler wrapping IDebugEventCallbacks to catch some output */ - +/* IDebugEventCallbacks event handler wrapping the original IDebugEventCallbacks + * to catch and store exceptions (report crashes as stop reasons). */ class EventCallback : public IDebugEventCallbacks { public: diff --git a/src/libs/qtcreatorcdbext/extensioncontext.h b/src/libs/qtcreatorcdbext/extensioncontext.h index 4a7ee97682286f3252b52894058e233cc21ff5ad..309f95e3799be7ce114f47ba32c29ab3c5f5c23e 100644 --- a/src/libs/qtcreatorcdbext/extensioncontext.h +++ b/src/libs/qtcreatorcdbext/extensioncontext.h @@ -85,11 +85,11 @@ public: // register as '.idle_cmd' to notify creator about stop void notifyIdle(); - // Return symbol group for frame (cache as long as frame does not change). + // Return symbol group for frame (cached as long as frame/thread do not change). SymbolGroup *symbolGroup(CIDebugSymbols *symbols, ULONG threadId, int frame, std::string *errorMessage); int symbolGroupFrame() const; - // Stop reason is reported with the next idle notification + // Set a stop reason to be reported with the next idle notification (exception). void setStopReason(const StopReasonMap &, const std::string &reason = std::string()); private: @@ -109,6 +109,7 @@ private: }; // Context for extension commands to be instantiated on stack in a command handler. +// Provides the IDebug objects on demand. class ExtensionCommandContext { ExtensionCommandContext(const ExtensionCommandContext&); diff --git a/src/libs/qtcreatorcdbext/knowntype.h b/src/libs/qtcreatorcdbext/knowntype.h index 34fb12f53058988f28de00265a30a935b943f544..bd173fbecd407e826189299c2695f2f6819e744f 100644 --- a/src/libs/qtcreatorcdbext/knowntype.h +++ b/src/libs/qtcreatorcdbext/knowntype.h @@ -34,10 +34,11 @@ #ifndef KNOWNTYPE_H #define KNOWNTYPE_H -// Helpers for detecting types +// Enumeration describing a type. enum KnownType { KT_Unknown =0, + // Flags to be used in type values. KT_POD_Type = 0x10000, KT_Qt_Type = 0x20000, KT_Qt_PrimitiveType = 0x40000, @@ -46,7 +47,7 @@ enum KnownType KT_ContainerType = 0x200000, KT_HasSimpleDumper = 0x400000, KT_HasComplexDumper = 0x800000, // Non-container complex dumper - // PODs + // Types: PODs KT_Char = KT_POD_Type + 1, KT_UnsignedChar = KT_POD_Type + 2, KT_IntType = KT_POD_Type + 3, // any signed short, long, int @@ -54,7 +55,7 @@ enum KnownType KT_FloatType = KT_POD_Type + 5, // float, double KT_POD_PointerType = KT_POD_Type + 6, // pointer to some POD KT_PointerType = KT_POD_Type + 7, // pointer to class or complex type - // Qt Basic + // Types: Qt Basic KT_QChar = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 1, KT_QByteArray = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 2, KT_QString = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 3, @@ -75,7 +76,7 @@ enum KnownType KT_QAtomicInt = KT_Qt_Type + KT_HasSimpleDumper + 19, KT_QObject = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 20, KT_QWidget = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 21, - // Various QT movable types + // Types: Various QT movable types KT_QPen = KT_Qt_Type + KT_Qt_MovableType + 30, KT_QUrl = KT_Qt_Type + KT_Qt_MovableType + 31, KT_QIcon = KT_Qt_Type + KT_Qt_MovableType + 32, @@ -134,7 +135,7 @@ enum KnownType KT_QPatternist_ItemSequenceCacheCell = KT_Qt_Type + KT_Qt_MovableType + 86, KT_QNetworkHeadersPrivate_RawHeaderPair = KT_Qt_Type + KT_Qt_MovableType + 87, KT_QPatternist_AccelTree_BasicNodeData = KT_Qt_Type + KT_Qt_MovableType + 88, - // Qt primitive types + // Types: Qt primitive types KT_QFixed = KT_Qt_Type + KT_Qt_PrimitiveType + 90, KT_QTextItem = KT_Qt_Type + KT_Qt_PrimitiveType + 91, KT_QFixedSize = KT_Qt_Type + KT_Qt_PrimitiveType + 92, @@ -144,7 +145,7 @@ enum KnownType KT_QTextUndoCommand = KT_Qt_Type + KT_Qt_PrimitiveType + 96, KT_QGlyphJustification = KT_Qt_Type + KT_Qt_PrimitiveType + 97, KT_QPainterPath_Element = KT_Qt_Type + KT_Qt_PrimitiveType + 98, - // Qt Containers + // Types: Qt Containers KT_QStringList = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 1, KT_QList = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 2, KT_QLinkedList = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 3, @@ -156,10 +157,10 @@ enum KnownType KT_QMultiHash = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 9, KT_QMap = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 10, KT_QMultiMap = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 11, - // STL + // Types: STL KT_StdString = KT_STL_Type + KT_HasSimpleDumper + 1, KT_StdWString = KT_STL_Type + KT_HasSimpleDumper + 2, - // STL containers + // Types: STL containers KT_StdVector = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 1, KT_StdList = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 2, KT_StdStack = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 3, diff --git a/src/libs/qtcreatorcdbext/outputcallback.cpp b/src/libs/qtcreatorcdbext/outputcallback.cpp index 5b01ffa46c64aa078e14fee88321e6ce9655aa8d..2e6e273dec6e37f0ce54128110d518fd4c2adfe5 100644 --- a/src/libs/qtcreatorcdbext/outputcallback.cpp +++ b/src/libs/qtcreatorcdbext/outputcallback.cpp @@ -97,6 +97,6 @@ STDMETHODIMP OutputCallback::Output( // Base encode as GDBMI is not really made for wide chars std::ostringstream str; base64Encode(str, reinterpret_cast<const unsigned char *>(text), sizeof(wchar_t) * std::wcslen(text)); - ExtensionContext::instance().report('E', 0, 0, "debuggee_output", str.str().c_str()); + ExtensionContext::instance().reportLong('E', 0, "debuggee_output", str.str().c_str()); return S_OK; } diff --git a/src/libs/qtcreatorcdbext/outputcallback.h b/src/libs/qtcreatorcdbext/outputcallback.h index acab292564b35c4463839933bbd1580ad23dfd95..cad4a663eecc534bcdeec98ac4e306960db14c63 100644 --- a/src/libs/qtcreatorcdbext/outputcallback.h +++ b/src/libs/qtcreatorcdbext/outputcallback.h @@ -36,6 +36,8 @@ #include "common.h" +/* OutputCallback catches DEBUG_OUTPUT_DEBUGGEE and reports it + * base64-encoded back to Qt Creator. */ class OutputCallback : public IDebugOutputCallbacksWide { public: diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp index dab97cb1aa7597937a012818c50d2d42200f1f2c..79ecf83b8a1e3dedd95716b7641c97f97ef8d4ea 100644 --- a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp +++ b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp @@ -44,7 +44,8 @@ #include <list> #include <iterator> -/* QtCreatorCDB ext is an extension loaded into CDB.exe (see cdbengine2.cpp): +/* QtCreatorCDB ext is an extension loaded into CDB.exe (see cdbengine.cpp) + * providing: * - Notification about the state of the debugging session: * + idle: (hooked with .idle_cmd) debuggee stopped * + accessible: Debuggee stopped, cdb.exe accepts commands diff --git a/src/libs/qtcreatorcdbext/stringutils.h b/src/libs/qtcreatorcdbext/stringutils.h index 4bad5b5f427a07130980e5002d0b3bbc415d8775..fc3e4bc815a5990031ac27c3a43c5cd9b4eb17ec 100644 --- a/src/libs/qtcreatorcdbext/stringutils.h +++ b/src/libs/qtcreatorcdbext/stringutils.h @@ -39,11 +39,12 @@ #include <map> #include <functional> -void trimFront(std::string &s); -void trimBack(std::string &s); +void trimFront(std::string &s); // Strip blanks off front +void trimBack(std::string &s); // Strip blanks off back +// Simplify blanks, that is " A \tB " -> "A B". void simplify(std::string &s); -// Split by character separator. +// Split a token sequence in a string by character separator. template <class Iterator> void split(const std::string &s, char sep, Iterator it) { diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.h b/src/libs/qtcreatorcdbext/symbolgroupnode.h index 014ca96252e2c3c4fc2c5f03ce3056b1899c08af..e8ece3a50f77dbd07c30ea83e53a93c188bf56cd 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupnode.h +++ b/src/libs/qtcreatorcdbext/symbolgroupnode.h @@ -50,7 +50,9 @@ class SymbolGroup; struct SymbolGroupValueContext; class SymbolGroupNode; -// All parameters for GDBMI dumping in one struct. +// All parameters for GDBMI dumping of a symbol group in one struct. +// The debugging engine passes maps of type names/inames to special +// integer values indicating hex/dec, etc. struct DumpParameters { typedef std::map<std::string, int> FormatMap; // type or iname to format @@ -75,7 +77,7 @@ struct DumpParameters FormatMap individualFormats; }; -// Base class for a node of SymbolGroup, handling the list of children. +// Abstract base class for a node of SymbolGroup providing the child list interface. class AbstractSymbolGroupNode { AbstractSymbolGroupNode(const AbstractSymbolGroupNode&); @@ -93,7 +95,7 @@ public: // 'iname' used as an internal id. const std::string &iName() const { return m_iname; } // Full iname 'local.x.foo': WARNING: this returns the absolute path not - // taking reference nodes into account. + // taking reference nodes into account by recursing up the parents. std::string absoluteFullIName() const; virtual const AbstractSymbolGroupNodePtrVector &children() const = 0; @@ -169,11 +171,11 @@ private: * consisting of: * - 'Simple' dumping done when running the DumpVisitor. This produces one * line of formatted output shown for the class. These values - * values should are displayed, while still allowing for expansion of the structure + * values are always displayed, while still allowing for expansion of the structure * in the debugger. * It also pre-determines some information for complex dumping (type, container). * - 'Complex' dumping: Obscures the symbol group children by fake children, for - * example container children, run when calling SymbolGroup::dump with an iname. + * example container children, to be run when calling SymbolGroup::dump with an iname. * The fake children are appended to the child list (other children are just marked as * obscured for GDBMI dumping so that SymbolGroupValue expressions still work as before). * The dumping is mostly based on SymbolGroupValue expressions. @@ -270,9 +272,9 @@ private: }; // Artificial node referencing another (real) SymbolGroupNode (added symbol or -// symbol from within a linked list structure. Forwards dumping to referenced node -// using its own name. -class ReferenceSymbolGroupNode : public AbstractSymbolGroupNode +// symbol from within an expanded linked list structure). Forwards the +// dumping to the referenced node using its own name. +class ReferenceSymbolGroupNode : public AbstractSymbolGroupNode { public: explicit ReferenceSymbolGroupNode(const std::string &name, @@ -296,7 +298,8 @@ private: SymbolGroupNode * const m_referencedNode; }; -// Base class for a [fake] map node with a fake array index and key/value entries. +// A [fake] map node with a fake array index and key/value entries consisting +// of ReferenceSymbolGroupNode. class MapNodeSymbolGroupNode : public BaseSymbolGroupNode { private: @@ -329,7 +332,7 @@ private: * or by expanding the whole structure). * visit() is not called for the (invisible) root node, but starting with the * root's children with depth=0. - * Return true from visit() to terminate the recursion. */ + * Return VisitStop from visit() to terminate the recursion. */ class SymbolGroupNodeVisitor { SymbolGroupNodeVisitor(const SymbolGroupNodeVisitor&); @@ -392,7 +395,8 @@ private: const std::string m_filter; }; -// GDBMI dump output visitor. +// GDBMI dump output visitor used to report locals values back to the +// debugging engine. class DumpSymbolGroupNodeVisitor : public SymbolGroupNodeVisitor { public: explicit DumpSymbolGroupNodeVisitor(std::ostream &os, diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.h b/src/libs/qtcreatorcdbext/symbolgroupvalue.h index 2c6d49866846b56ce0eaceff1e14a343f5fd61c5..49672b7b5a79b02338ddd09fa84e251dd29d0579 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.h +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.h @@ -45,7 +45,7 @@ class AbstractSymbolGroupNode; class SymbolGroupNode; class SymbolGroup; -// Structure to pass all IDebug interfaces used for SymbolGroupValue +// Structure to pass all IDebug interfaces required for SymbolGroupValue struct SymbolGroupValueContext { SymbolGroupValueContext(CIDebugDataSpaces *ds, CIDebugSymbols *s) : dataspaces(ds), symbols(s) {} @@ -56,8 +56,14 @@ struct SymbolGroupValueContext }; /* SymbolGroupValue: Flyweight tied to a SymbolGroupNode - * providing a convenient operator[] + value getters for notation of dumpers. - * Inaccesible members return a SymbolGroupValue in state 'invalid'. */ + * providing a convenient operator[] (name, index) and value + * getters for notation of dumpers. + * Inaccessible members return a SymbolGroupValue in state 'invalid'. + * Example: + * SymbolGroupValue container(symbolGroupNode, symbolGroupValueContext); + * if (SymbolGroupValue sizeV = container["d"]["size"]) + * int size = sizeV.intValue() + * etc. */ class SymbolGroupValue { @@ -141,7 +147,8 @@ private: // For debugging purposes std::ostream &operator<<(std::ostream &, const SymbolGroupValue &v); -// Qt Information: Namespace and module. +// Qt Information determined on demand: Namespace, modules and basic class +// names containing the module for fast lookup. struct QtInfo { static const QtInfo &get(const SymbolGroupValueContext &ctx); @@ -196,6 +203,7 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, int *containerSizeIn = 0, void **specialInfoIn = 0); +// Non-container complex dumpers (QObjects/QVariants). std::vector<AbstractSymbolGroupNode *> dumpComplexType(SymbolGroupNode *node, int type, void *specialInfo, const SymbolGroupValueContext &ctx); diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 60c5da7ed18a9c65929dfb5c83237a8d0c564ec0..713e1acc921c39bf79f92571306f2b68c9758aa7 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -95,29 +95,30 @@ enum { debugBreakpoints = 0 }; /* CdbEngine version 2: Run the CDB process on pipes and parse its output. * The engine relies on a CDB extension Qt Creator provides as an extension - * library (32/64bit). It serves to: + * library (32/64bit), which is loaded into cdb.exe. It serves to: * - Notify the engine about the state of the debugging session: - * + idle: (hooked with .idle_cmd) debuggee stopped + * + idle: (hooked up with .idle_cmd) debuggee stopped * + accessible: Debuggee stopped, cdb.exe accepts commands * + inaccessible: Debuggee runs, no way to post commands * + session active/inactive: Lost debuggee, terminating. - * - Hook up with output/event callbacks and produce formatted output + * - Hook up with output/event callbacks and produce formatted output to be able + * to catch application output and exceptions. * - Provide some extension commands that produce output in a standardized (GDBMI) * format that ends up in handleExtensionMessage(). * + pid Return debuggee pid for interrupting. * + locals Print locals from SymbolGroup * + expandLocals Expand locals in symbol group * + registers, modules, threads - * Commands can be posted: - * postCommand: Does not expect a reply - * postBuiltinCommand: Run a builtin-command producing free-format, multiline output - * that is captured by enclosing it in special tokens using the 'echo' command and - * then invokes a callback with a CdbBuiltinCommand structure. - * postExtensionCommand: Run a command provided by the extension producing - * one-line output and invoke a callback with a CdbExtensionCommand structure. */ + * Commands can be posted by calling: + * 1) postCommand(): Does not expect a reply + * 2) postBuiltinCommand(): Run a builtin-command producing free-format, multiline output + * that is captured by enclosing it in special tokens using the 'echo' command and + * then invokes a callback with a CdbBuiltinCommand structure. + * 3) postExtensionCommand(): Run a command provided by the extension producing + * one-line output and invoke a callback with a CdbExtensionCommand structure + * (output is potentially split up in chunks). */ using namespace ProjectExplorer; -using namespace Debugger::Internal; namespace Debugger { namespace Internal { @@ -899,7 +900,9 @@ void CdbEngine::assignValueInDebugger(const WatchData *w, const QString &expr, c ByteArrayInputStream str(cmd); str << m_extensionCommandPrefixBA << "assign " << w->iname << '=' << value.toString(); postCommand(cmd, 0); - updateLocalVariable(w->iname); + // Update all locals in case we change a union or something pointed to + // that affects other variables, too. + updateLocals(); } void CdbEngine::handleThreads(const CdbExtensionCommandPtr &reply) @@ -1034,9 +1037,26 @@ void CdbEngine::activateFrame(int index) } else { assemblerAction->trigger(); // Seems to trigger update } + } else { + gotoLocation(frame); + updateLocals(); + } +} + +void CdbEngine::updateLocals() +{ + const int frameIndex = stackHandler()->currentIndex(); + if (frameIndex < 0) { + watchHandler()->beginCycle(); + watchHandler()->endCycle(); + return; + } + const StackFrame frame = stackHandler()->currentFrame(); + if (!frame.isUsable()) { + watchHandler()->beginCycle(); + watchHandler()->endCycle(); return; } - gotoLocation(frame); // Watchers: Initial expand, get uninitialized and query QByteArray arguments; ByteArrayInputStream str(arguments); @@ -1068,7 +1088,7 @@ void CdbEngine::activateFrame(int index) } } // Required arguments: frame - str << blankSeparator << index; + str << blankSeparator << frameIndex; watchHandler()->beginCycle(); postExtensionCommand("locals", arguments, 0, &CdbEngine::handleLocals); } diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index 6edce64f14533ba01a8bc0d431b35b9001526f50..c11e9c955fc46fa20eb3bdcd7c49b3406faf55a6 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -179,6 +179,7 @@ private: QString normalizeFileName(const QString &f); void updateLocalVariable(const QByteArray &iname); + void updateLocals(); int elapsedLogTime() const; void addLocalsOptions(ByteArrayInputStream &s) const;