forked from qt-creator/qt-creator
Debugger[New CDB]: Refine type detection, dump nested containers.
Introduce test commands.
This commit is contained in:
@@ -16,5 +16,6 @@ idle
|
||||
help
|
||||
memory
|
||||
shutdownex
|
||||
test
|
||||
stack
|
||||
KnownStructOutput
|
||||
|
||||
@@ -96,7 +96,8 @@ enum Command {
|
||||
CmdHelp,
|
||||
CmdMemory,
|
||||
CmdStack,
|
||||
CmdShutdownex
|
||||
CmdShutdownex,
|
||||
CmdTest
|
||||
};
|
||||
|
||||
static const CommandDescription commandDescriptions[] = {
|
||||
@@ -136,7 +137,8 @@ static const CommandDescription commandDescriptions[] = {
|
||||
{"help","Prints help.",""},
|
||||
{"memory","Prints memory contents in Base64 encoding.","[-t token] <address> <length>"},
|
||||
{"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.",""}
|
||||
{"shutdownex","Unhooks output callbacks.\nNeeds to be called explicitly only in case of remote debugging.",""},
|
||||
{"test","Testing command","-T type"}
|
||||
};
|
||||
|
||||
typedef std::vector<std::string> StringVector;
|
||||
@@ -725,6 +727,45 @@ extern "C" HRESULT CALLBACK shutdownex(CIDebugClient *, PCSTR)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
extern "C" HRESULT CALLBACK test(CIDebugClient *client, PCSTR argsIn)
|
||||
{
|
||||
enum Mode { Invalid, TestType };
|
||||
ExtensionCommandContext exc(client);
|
||||
|
||||
std::string testType;
|
||||
Mode mode = Invalid;
|
||||
int token = 0;
|
||||
StringList tokens = commandTokens<StringList>(argsIn, &token);
|
||||
// Parse away options
|
||||
while (!tokens.empty() && tokens.front().size() == 2 && tokens.front().at(0) == '-') {
|
||||
const char option = tokens.front().at(1);
|
||||
tokens.pop_front();
|
||||
switch (option) {
|
||||
case 'T':
|
||||
mode = TestType;
|
||||
if (!tokens.empty()) {
|
||||
testType = tokens.front();
|
||||
tokens.pop_front();
|
||||
}
|
||||
break;
|
||||
} // case option
|
||||
} // for options
|
||||
|
||||
// Frame and iname
|
||||
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 << ']';
|
||||
ExtensionContext::instance().reportLong('R', token, "test", str.str());
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
// Hook for dumping Known Structs. Not currently used.
|
||||
// Shows up in 'dv' as well as IDebugSymbolGroup::GetValueText.
|
||||
|
||||
|
||||
@@ -251,6 +251,8 @@ std::string SymbolGroup::dump(const std::string &iname,
|
||||
// After expansion, run the complex dumpers
|
||||
if (p.dumpFlags & DumpParameters::DumpComplexDumpers)
|
||||
node->runComplexDumpers(ctx);
|
||||
if (symbolGroupDebug)
|
||||
DebugPrint() << "SymbolGroup::dump(" << iname << ") ran complex dumpers 0x" << std::hex << node->flags();
|
||||
}
|
||||
|
||||
std::ostringstream str;
|
||||
@@ -262,7 +264,7 @@ std::string SymbolGroup::dump(const std::string &iname,
|
||||
str << ']';
|
||||
QTC_TRACE_OUT
|
||||
if (symbolGroupDebug)
|
||||
DebugPrint() << "<SymbolGroup::dump(" << iname << ")";
|
||||
DebugPrint() << "<SymbolGroup::dump(" << iname << ')';
|
||||
return str.str();
|
||||
}
|
||||
|
||||
|
||||
@@ -759,7 +759,7 @@ void SymbolGroupNode::runComplexDumpers(const SymbolGroupValueContext &ctx)
|
||||
{
|
||||
if (symbolGroupDebug)
|
||||
DebugPrint() << "SymbolGroupNode::runComplexDumpers " << name() << '/'
|
||||
<< absoluteFullIName() << ' ' << m_index << DebugNodeFlags(flags());
|
||||
<< absoluteFullIName() << ' ' << m_index << ' ' << DebugNodeFlags(flags());
|
||||
|
||||
if (m_dumperContainerSize <= 0 || (testFlags(ComplexDumperOk) || !testFlags(SimpleDumperOk)))
|
||||
return;
|
||||
@@ -786,7 +786,7 @@ void SymbolGroupNode::runComplexDumpers(const SymbolGroupValueContext &ctx)
|
||||
bool SymbolGroupNode::runSimpleDumpers(const SymbolGroupValueContext &ctx)
|
||||
{
|
||||
if (symbolGroupDebug)
|
||||
DebugPrint() << "SymbolGroupNode::runSimpleDumpers " << name() << '/'
|
||||
DebugPrint() << ">SymbolGroupNode::runSimpleDumpers " << name() << '/'
|
||||
<< absoluteFullIName() << ' ' << m_index << DebugNodeFlags(flags());
|
||||
if (testFlags(Uninitialized))
|
||||
return false;
|
||||
@@ -797,7 +797,8 @@ bool SymbolGroupNode::runSimpleDumpers(const SymbolGroupValueContext &ctx)
|
||||
addFlags(dumpSimpleType(this , ctx, &m_dumperValue,
|
||||
&m_dumperType, &m_dumperContainerSize));
|
||||
if (symbolGroupDebug)
|
||||
DebugPrint() << "-> '" << wStringToString(m_dumperValue) << "' Type="
|
||||
DebugPrint() << "<SymbolGroupNode::runSimpleDumpers " << name() << " '"
|
||||
<< wStringToString(m_dumperValue) << "' Type="
|
||||
<< m_dumperType << ' ' << DebugNodeFlags(flags());
|
||||
return testFlags(SimpleDumperOk);
|
||||
}
|
||||
@@ -1194,9 +1195,9 @@ SymbolGroupNodeVisitor::VisitResult
|
||||
const std::string &fullIname,
|
||||
unsigned /* child */, unsigned depth)
|
||||
{
|
||||
// Show container children only, no additional symbol below root.
|
||||
// Show container children only, no additional symbol below root. Also, skip expanded by dumper
|
||||
const unsigned flags = node->flags();
|
||||
if (flags & (SymbolGroupNode::Obscured|SymbolGroupNode::AdditionalSymbol))
|
||||
if (flags & (SymbolGroupNode::Obscured|SymbolGroupNode::AdditionalSymbol|SymbolGroupNode::ExpandedByDumper))
|
||||
return VisitSkipChildren;
|
||||
// Recurse to children only if expanded by explicit watchmodel request
|
||||
// and initialized.
|
||||
|
||||
@@ -659,37 +659,53 @@ static KnownType knownPODTypeHelper(const std::string &type, std::string::size_t
|
||||
{
|
||||
if (type.empty() || !endPos)
|
||||
return KT_Unknown;
|
||||
// Strip pointer types.
|
||||
const bool isPointer = type.at(endPos - 1) == '*';
|
||||
if (isPointer) {
|
||||
endPos--;
|
||||
if (endPos > 0 && type.at(endPos - 1) == ' ')
|
||||
endPos--;
|
||||
}
|
||||
switch (type.at(0)) {
|
||||
case 'c':
|
||||
if (!type.compare(0, endPos, "char"))
|
||||
if (endPos == 4 && !type.compare(0, endPos, "char"))
|
||||
return isPointer ? KT_POD_PointerType : KT_Char;
|
||||
break;
|
||||
case 'd':
|
||||
if (!type.compare(0, endPos, "double"))
|
||||
if (endPos == 6 && !type.compare(0, endPos, "double"))
|
||||
return isPointer ? KT_POD_PointerType : KT_FloatType;
|
||||
break;
|
||||
case 'f':
|
||||
if (!type.compare(0, endPos, "float"))
|
||||
if (endPos == 5 && !type.compare(0, endPos, "float"))
|
||||
return isPointer ? KT_POD_PointerType : KT_FloatType;
|
||||
break;
|
||||
case 'l':
|
||||
if (!type.compare(0, 4, "long"))
|
||||
if (endPos >= 4 && !type.compare(0, 4, "long"))
|
||||
if (endPos == 4 || type.at(4) == ' ')
|
||||
return isPointer ? KT_POD_PointerType : KT_IntType;
|
||||
break;
|
||||
case 'i':
|
||||
if (!type.compare(0, 3, "int"))
|
||||
// 'int' 'int64'
|
||||
if (endPos >= 3 && !type.compare(0, 3, "int"))
|
||||
if (endPos == 3 || type.at(3) == ' ' || type.at(3) == '6')
|
||||
return isPointer ? KT_POD_PointerType : KT_IntType;
|
||||
break;
|
||||
case 's':
|
||||
if (!type.compare(0, 5, "short"))
|
||||
if (endPos == 5 && !type.compare(0, 5, "short"))
|
||||
return isPointer ? KT_POD_PointerType : KT_IntType;
|
||||
if (endPos >= 6 && !type.compare(0, 6, "signed"))
|
||||
if (endPos == 6 || type.at(6) == ' ')
|
||||
return isPointer ? KT_POD_PointerType : KT_IntType;
|
||||
break;
|
||||
case 'u':
|
||||
if (!type.compare(0, 8, "unsigned")) {
|
||||
if (endPos >= 8 && !type.compare(0, 8, "unsigned")) {
|
||||
if (endPos == 8 || type.at(8) == ' ') {
|
||||
if (isPointer)
|
||||
return KT_POD_PointerType;
|
||||
return type == "unsigned char" ? KT_UnsignedChar : KT_UnsignedIntType;
|
||||
return type.compare(0, 13, "unsigned char") ?
|
||||
KT_UnsignedIntType :
|
||||
KT_UnsignedChar;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user