Commit 7d72445b authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

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.
parent dea74862
......@@ -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","<iname> <expression>"},
{"test","Testing command","-T type"}
{"test","Testing command","-T type | -w watch-expression"}
};
typedef std::vector<std::string> 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;
......
......@@ -40,6 +40,7 @@
#include <algorithm>
#include <iterator>
#include <memory>
#include <cctype>
typedef std::vector<int>::size_type VectorIndexType;
typedef std::vector<std::string> 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 "*(<type>[ ]*[*])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 "*(<type>[ ]*[*])0xaddress"
// to be qualified by the module "*(module!<type>[ ]*[*])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<std::string> 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)
......
......@@ -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
......@@ -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);
......
......@@ -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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment