From 7d72445bc03c7a57abf02770990a0cceba15d308 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 17 Jan 2011 14:50:49 +0100 Subject: [PATCH] Debugger[New CDB]: Qualify types in watch expressions by module. ... to make them faster. Check for watch expressions of the form '*(Type *)0xaddr' and insert module for non-PODs. Add testing command. --- src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp | 33 +++-- src/libs/qtcreatorcdbext/symbolgroup.cpp | 158 ++++++++++++++++++++- src/libs/qtcreatorcdbext/symbolgroup.h | 15 +- src/libs/qtcreatorcdbext/symbolgroupnode.cpp | 7 +- src/libs/qtcreatorcdbext/symbolgroupnode.h | 1 + 5 files changed, 194 insertions(+), 20 deletions(-) diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp index 8088081bec..706bb055ac 100644 --- a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp +++ b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp @@ -155,7 +155,7 @@ static const CommandDescription commandDescriptions[] = { {"stack","Prints stack in GDBMI format.","[-t token] [max-frames]"}, {"shutdownex","Unhooks output callbacks.\nNeeds to be called explicitly only in case of remote debugging.",""}, {"addwatch","Add watch expression"," "}, -{"test","Testing command","-T type"} +{"test","Testing command","-T type | -w watch-expression"} }; typedef std::vector StringVector; @@ -484,7 +484,7 @@ static std::string commmandLocals(ExtensionCommandContext &commandExtCtx,PCSTR a } else { // Force group into existence watchesSymbolGroup = extCtx.watchesSymbolGroup(commandExtCtx.symbols(), errorMessage); - if (!watchesSymbolGroup || !watchesSymbolGroup->synchronize(watcherInameExpressionMap, errorMessage)) + if (!watchesSymbolGroup || !watchesSymbolGroup->synchronize(commandExtCtx.symbols(), watcherInameExpressionMap, errorMessage)) return std::string(); } } @@ -732,7 +732,7 @@ extern "C" HRESULT CALLBACK addwatch(CIDebugClient *client, PCSTR argsIn) WatchesSymbolGroup *watchesSymGroup = ExtensionContext::instance().watchesSymbolGroup(exc.symbols(), &errorMessage); if (!watchesSymGroup) break; - success = watchesSymGroup->addWatch(iname, watchExpression, &errorMessage); + success = watchesSymGroup->addWatch(exc.symbols(), iname, watchExpression, &errorMessage); } while (false); if (success) { @@ -945,7 +945,7 @@ extern "C" HRESULT CALLBACK shutdownex(CIDebugClient *, PCSTR) extern "C" HRESULT CALLBACK test(CIDebugClient *client, PCSTR argsIn) { - enum Mode { Invalid, TestType }; + enum Mode { Invalid, TestType, TestFixWatchExpression }; ExtensionCommandContext exc(client); std::string testType; @@ -964,6 +964,13 @@ extern "C" HRESULT CALLBACK test(CIDebugClient *client, PCSTR argsIn) tokens.pop_front(); } break; + case 'w': + mode = TestFixWatchExpression; + if (!tokens.empty()) { + testType = tokens.front(); + tokens.pop_front(); + } + break; } // case option } // for options @@ -971,11 +978,21 @@ extern "C" HRESULT CALLBACK test(CIDebugClient *client, PCSTR argsIn) if (mode == Invalid || testType.empty()) { ExtensionContext::instance().report('N', token, 0, "test", singleLineUsage(commandDescriptions[CmdTest]).c_str()); } else { - const KnownType kt = knownType(testType, 0); std::ostringstream str; - str << testType << ' ' << kt << " ["; - formatKnownTypeFlags(str, kt); - str << ']'; + switch (mode) { + case Invalid: + break; + case TestType: { + const KnownType kt = knownType(testType, 0); + str << testType << ' ' << kt << " ["; + formatKnownTypeFlags(str, kt); + str << ']'; + } + break; + case TestFixWatchExpression: + str << testType << " -> " << WatchesSymbolGroup::fixWatchExpression(exc.symbols(), testType); + break; + } ExtensionContext::instance().reportLong('R', token, "test", str.str()); } return S_OK; diff --git a/src/libs/qtcreatorcdbext/symbolgroup.cpp b/src/libs/qtcreatorcdbext/symbolgroup.cpp index e6fb0a8e7b..1b5de07e55 100644 --- a/src/libs/qtcreatorcdbext/symbolgroup.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroup.cpp @@ -40,6 +40,7 @@ #include #include #include +#include typedef std::vector::size_type VectorIndexType; typedef std::vector StringVector; @@ -399,9 +400,19 @@ bool SymbolGroup::typeCast(const std::string &iname, const std::string &desiredT return node->typeCast(desiredType, errorMessage); } -SymbolGroupNode *SymbolGroup::addSymbol(const std::string &module, const std::string &name, const std::string &iname, std::string *errorMessage) +SymbolGroupNode *SymbolGroup::addSymbol(const std::string &module, + const std::string &name, + const std::string &displayName, + const std::string &iname, + std::string *errorMessage) { - return m_root->addSymbolByName(module, name, iname, errorMessage); + return m_root->addSymbolByName(module, name, displayName, iname, errorMessage); +} + +SymbolGroupNode *SymbolGroup::addSymbol(const std::string &module, const std::string &name, + const std::string &iname, std::string *errorMessage) +{ + return addSymbol(module, name, std::string(), iname, errorMessage); } // Mark uninitialized (top level only) @@ -606,7 +617,138 @@ WatchesSymbolGroup::WatchesSymbolGroup(CIDebugSymbolGroup *sg) : { } -bool WatchesSymbolGroup::addWatch(std::string iname, const std::string &expression, std::string *errorMessage) +/* Helpers for parsing a watch expression of the form "*([ ]*[*])0xaddress" + * (like '*(Foo*)0x47b' that is created by our dumpers or for the case the users + * inputs something similar. The position of the data type is determined so that + * it can be qualified by the module to make the expressions faster ('*(MyModule!Foo*)0x47b'). + * The checking should be somewhat strict since the user can input arbitrary stuff. + * Lacking regular expression support, use a small state machine. */ + +enum WatchExpressionParseState +{ + WEPS_Error, + WEPS_WithinType, + WEPS_WithinBlanksAfterType, + WEPS_WithinAsterisksAfterType, + WEPS_AtParenthesisAfterType, + WEPS_WithinAddress +}; + +static inline WatchExpressionParseState + nextWatchExpressionParseState(WatchExpressionParseState s, char c, unsigned *templateLevel) +{ + switch (s) { + case WEPS_Error: + break; + case WEPS_WithinType: + switch (c) { + case '<': + (*templateLevel)++; + return WEPS_WithinType; + case '>': + (*templateLevel)--; + return WEPS_WithinType; + case ' ': + return *templateLevel ? WEPS_WithinType : WEPS_WithinBlanksAfterType; + case '*': + return WEPS_WithinAsterisksAfterType; + case ',': + return *templateLevel ? WEPS_WithinType : WEPS_Error; + case ':': + case '_': + return WEPS_WithinType; + default: + if (std::isalnum(c)) + return WEPS_WithinType; + break; + } + break; + case WEPS_WithinBlanksAfterType: + if (c == ' ') + return WEPS_WithinBlanksAfterType; + if (c == '*') + return WEPS_WithinAsterisksAfterType; + break; + case WEPS_WithinAsterisksAfterType: + if (c == '*') + return WEPS_WithinAsterisksAfterType; + if (c == ')') + return WEPS_AtParenthesisAfterType; + break; + case WEPS_AtParenthesisAfterType: + if (c == '0') + return WEPS_WithinAddress; + break; + case WEPS_WithinAddress: + if (std::isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || c == 'x') + return WEPS_WithinAddress; + break; + } + return WEPS_Error; +} + +static bool parseWatchExpression(const std::string &expression, + std::string::size_type *typeStart, std::string::size_type *typeEnd) +{ + *typeStart = *typeEnd = std::string::npos; + if (expression.size() < 3 || expression.compare(0, 2, "*(") || expression.find("*)0x") == std::string::npos) + return false; + unsigned templateLevel = 0; + const std::string::size_type size = expression.size(); + WatchExpressionParseState state = WEPS_WithinType; + std::string::size_type pos = 2; + *typeStart = pos; + for ( ; pos < size ; pos++) { + const char c = expression.at(pos); + const WatchExpressionParseState nextState = nextWatchExpressionParseState(state, c, &templateLevel); + DebugPrint() << c << ' ' << pos << ' ' << state << ' ' << nextState << ' ' << templateLevel; + if (nextState == WEPS_Error) + return false; + if (nextState != state && state == WEPS_WithinType) + *typeEnd = pos; + state = nextState; + } + return state == WEPS_WithinAddress; +} + +std::string WatchesSymbolGroup::fixWatchExpressionI(CIDebugSymbols *s, const std::string &expression) +{ + // Fix a symbol of the form "*([ ]*[*])0xaddress" + // to be qualified by the module "*(module![ ]*[*])0xaddress" + if (expression.find('!') != std::string::npos) + return expression; + // Check if it matches the form + std::string::size_type typeStartPos; + std::string::size_type typeEndPos; + if (!parseWatchExpression(expression, &typeStartPos, &typeEndPos)) + return expression; + std::string type = expression.substr(typeStartPos, typeEndPos - typeStartPos); + trimFront(type); + trimBack(type); + // Do not qualify POD types + const KnownType kt = knownType(type, 0); + if (kt & KT_POD_Type) + return expression; + SymbolGroupValueContext ctx; + ctx.symbols = s; + const std::string resolved = SymbolGroupValue::resolveType(type, ctx); + if (resolved.empty() || resolved == type) + return expression; + std::string fixed = expression; + fixed.replace(typeStartPos, typeEndPos - typeStartPos, resolved); + return fixed; +} + +// Wrapper with debug output. +std::string WatchesSymbolGroup::fixWatchExpression(CIDebugSymbols *s, const std::string &expression) +{ + const std::string fixed = fixWatchExpressionI(s, expression); + if (SymbolGroupValue::verbose) + DebugPrint() << ">WatchesSymbolGroup::fixWatchExpression " << expression << " -> " << fixed; + return fixed; +} + +bool WatchesSymbolGroup::addWatch(CIDebugSymbols *s, std::string iname, const std::string &expression, std::string *errorMessage) { // "watch.0" -> "0" const size_t prefLen = std::strlen(WatchesSymbolGroup::watchInamePrefix); @@ -615,8 +757,10 @@ bool WatchesSymbolGroup::addWatch(std::string iname, const std::string &expressi // Already in? if (root()->childByIName(iname.c_str())) return true; - // TODO: Figure out module - SymbolGroupNode *node = addSymbol(std::string(), expression, iname, errorMessage); + // Resolve the expressions, but still display the original name obtained to + // avoid cycles re-adding symbols + SymbolGroupNode *node = addSymbol(std::string(), fixWatchExpression(s, expression), + expression, iname, errorMessage); if (!node) return false; node->addFlags(SymbolGroupNode::WatchNode); @@ -637,7 +781,7 @@ WatchesSymbolGroup::InameExpressionMap } // Synchronize watches passing on a map of '0' -> '*(int *)(0xA0)' -bool WatchesSymbolGroup::synchronize(const InameExpressionMap &newInameExpMap, std::string *errorMessage) +bool WatchesSymbolGroup::synchronize(CIDebugSymbols *s, const InameExpressionMap &newInameExpMap, std::string *errorMessage) { typedef std::set StringSet; typedef InameExpressionMap::const_iterator InameExpressionMapConstIt; @@ -684,7 +828,7 @@ bool WatchesSymbolGroup::synchronize(const InameExpressionMap &newInameExpMap, s if (!addMap.empty()) { const InameExpressionMapConstIt acend = addMap.end(); for (InameExpressionMapConstIt it = addMap.begin(); it != acend; ++it) { - const bool success = addWatch(it->first, it->second, errorMessage); + const bool success = addWatch(s, it->first, it->second, errorMessage); if (SymbolGroupValue::verbose) DebugPrint() << " Adding " << it->first << ',' << it->second << ",success=" << success; if (!success) diff --git a/src/libs/qtcreatorcdbext/symbolgroup.h b/src/libs/qtcreatorcdbext/symbolgroup.h index fa598c1cdb..768b574b29 100644 --- a/src/libs/qtcreatorcdbext/symbolgroup.h +++ b/src/libs/qtcreatorcdbext/symbolgroup.h @@ -98,9 +98,15 @@ public: bool typeCast(const std::string &iname, const std::string &desiredType, std::string *errorMessage); // Add a symbol by name expression SymbolGroupNode *addSymbol(const std::string &module, - const std::string &name, // Expression like 'myarray[1]' + const std::string &name, // Expression like 'myarray[1]' + const std::string &displayName, // Name to be displayed, defaults to name const std::string &iname, // Desired iname, defaults to name std::string *errorMessage); + // Convenience overload for name==displayName + SymbolGroupNode *addSymbol(const std::string &module, + const std::string &name, // Expression like 'myarray[1]' + const std::string &iname, + std::string *errorMessage); bool accept(SymbolGroupNodeVisitor &visitor) const; @@ -166,16 +172,19 @@ public: static const char *watchInamePrefix; // Add a symbol as 'watch.0' or '0' with expression - bool addWatch(std::string iname, const std::string &expression, std::string *errorMessage); + bool addWatch(CIDebugSymbols *s, std::string iname, const std::string &expression, std::string *errorMessage); // Synchronize watches passing on a map of '0' -> '*(int *)(0xA0)' - bool synchronize(const InameExpressionMap &m, std::string *errorMessage); + bool synchronize(CIDebugSymbols *s, const InameExpressionMap &m, std::string *errorMessage); static WatchesSymbolGroup *create(CIDebugSymbols *, std::string *errorMessage); + static inline std::string fixWatchExpression(CIDebugSymbols *s, const std::string &ex); + private: explicit WatchesSymbolGroup(CIDebugSymbolGroup *); InameExpressionMap currentInameExpressionMap() const; inline SymbolGroupNode *rootChildByIname(const std::string &iname) const; + static inline std::string fixWatchExpressionI(CIDebugSymbols *s, const std::string &ex); }; #endif // SYMBOLGROUP_H diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp index d1fb2ca394..a1ac1cc47c 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp @@ -961,7 +961,7 @@ int SymbolGroupNode::dumpNode(std::ostream &str, } } // No children..suppose we are editable and enabled - if (childCountGuess != 0) + if (childCountGuess != 0 || (m_parameters.Flags & DEBUG_SYMBOL_READ_ONLY) != 0) valueEditable = false; str << ",valueenabled=\"" << (valueEnabled ? "true" : "false") << '"' << ",valueeditable=\"" << (valueEditable ? "true" : "false") << '"'; @@ -1164,6 +1164,7 @@ static inline std::string msgCannotAddSymbol(const std::string &name, const std: // For root nodes, only: Add a new symbol by name SymbolGroupNode *SymbolGroupNode::addSymbolByName(const std::string &module, const std::string &name, + const std::string &displayName, const std::string &iname, std::string *errorMessage) { @@ -1194,7 +1195,9 @@ SymbolGroupNode *SymbolGroupNode::addSymbolByName(const std::string &module, return 0; } SymbolGroupNode *node = new SymbolGroupNode(m_symbolGroup, index, - module, name, iname.empty() ? name : iname); + module, + displayName.empty() ? name : displayName, + iname.empty() ? name : iname); node->parseParameters(0, 0, parameters); node->addFlags(AdditionalSymbol); addChild(node); diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.h b/src/libs/qtcreatorcdbext/symbolgroupnode.h index 284b8c8c2d..e1d9072a88 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupnode.h +++ b/src/libs/qtcreatorcdbext/symbolgroupnode.h @@ -230,6 +230,7 @@ public: // For root nodes, only: Add a new symbol by name SymbolGroupNode *addSymbolByName(const std::string &module, const std::string &name, // Expression like 'myarray[1]' + const std::string &displayName, // Name to be displayed, defaults to name const std::string &iname, // Desired iname, defaults to name std::string *errorMessage); -- 2.11.0