forked from qt-creator/qt-creator
Debugger[New CDB]: Pass formatting parameters.
Pass around formatting parameters as structure. Prototypically implement formatting of char *-Pointers as UTF8. Transfer registers and modules only if dock window is visible.
This commit is contained in:
@@ -104,11 +104,14 @@ static const CommandDescription commandDescriptions[] = {
|
|||||||
"iname1-list: Comma-separated list of inames"},
|
"iname1-list: Comma-separated list of inames"},
|
||||||
{"locals",
|
{"locals",
|
||||||
"Prints local variables of symbol group in GDBMI or debug format",
|
"Prints local variables of symbol group in GDBMI or debug format",
|
||||||
"[-t token] [-h] [-d] [-e expand-list] [-u uninitialized-list]\n<frame-number> [iname]\n"
|
"[-t token] [T formats] [-I formats] [-c] [-h] [-d] [-e expand-list] [-u uninitialized-list]\n<frame-number> [iname]\n"
|
||||||
"-h human-readable ouput\n"
|
"-h human-readable ouput\n"
|
||||||
"-d debug output\n"
|
"-d debug output\n"
|
||||||
|
"-c complex dumpers\n"
|
||||||
"-e expand-list Comma-separated list of inames to be expanded beforehand\n"
|
"-e expand-list Comma-separated list of inames to be expanded beforehand\n"
|
||||||
"-u uninitialized-list Comma-separated list of uninitialized inames"},
|
"-u uninitialized-list Comma-separated list of uninitialized inames\n"
|
||||||
|
"-I formatmap map of 'hex-encoded-iname=typecode'\n"
|
||||||
|
"-T formatmap map of 'hex-encoded-type-name=typecode'"},
|
||||||
{"dumplocal", "Dumps local variable using simple dumpers (testing command).",
|
{"dumplocal", "Dumps local variable using simple dumpers (testing command).",
|
||||||
"[-t token] <frame-number> <iname>"},
|
"[-t token] <frame-number> <iname>"},
|
||||||
{"typecast","Performs a type cast on an unexpanded iname of symbol group.",
|
{"typecast","Performs a type cast on an unexpanded iname of symbol group.",
|
||||||
@@ -270,12 +273,11 @@ static std::string commmandLocals(ExtensionCommandContext &exc,PCSTR args, int *
|
|||||||
{
|
{
|
||||||
// Parse the command
|
// Parse the command
|
||||||
unsigned debugOutput = 0;
|
unsigned debugOutput = 0;
|
||||||
bool humanReadableGdbmi = false;
|
|
||||||
std::string iname;
|
std::string iname;
|
||||||
|
|
||||||
StringList tokens = commandTokens<StringList>(args, token);
|
StringList tokens = commandTokens<StringList>(args, token);
|
||||||
StringVector expandedInames;
|
StringVector expandedInames;
|
||||||
StringVector uninitializedInames;
|
StringVector uninitializedInames;
|
||||||
|
DumpParameters parameters;
|
||||||
// Parse away options
|
// Parse away options
|
||||||
while (!tokens.empty() && tokens.front().size() == 2 && tokens.front().at(0) == '-') {
|
while (!tokens.empty() && tokens.front().size() == 2 && tokens.front().at(0) == '-') {
|
||||||
const char option = tokens.front().at(1);
|
const char option = tokens.front().at(1);
|
||||||
@@ -285,7 +287,10 @@ static std::string commmandLocals(ExtensionCommandContext &exc,PCSTR args, int *
|
|||||||
debugOutput++;
|
debugOutput++;
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
humanReadableGdbmi = true;
|
parameters.dumpFlags |= DumpParameters::DumpHumanReadable;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
parameters.dumpFlags |= DumpParameters::DumpComplexDumpers;
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
if (tokens.empty()) {
|
if (tokens.empty()) {
|
||||||
@@ -303,8 +308,25 @@ static std::string commmandLocals(ExtensionCommandContext &exc,PCSTR args, int *
|
|||||||
split(tokens.front(), ',', std::back_inserter(expandedInames));
|
split(tokens.front(), ',', std::back_inserter(expandedInames));
|
||||||
tokens.pop_front();
|
tokens.pop_front();
|
||||||
break;
|
break;
|
||||||
|
case 'T': // typeformats: 'hex'ed name = formatnumber,...'
|
||||||
|
if (tokens.empty()) {
|
||||||
|
*errorMessage = singleLineUsage(commandDescriptions[CmdLocals]);
|
||||||
|
return std::string();
|
||||||
}
|
}
|
||||||
|
parameters.typeFormats = DumpParameters::decodeFormatArgument(tokens.front());
|
||||||
|
tokens.pop_front();
|
||||||
|
break;
|
||||||
|
case 'I': // individual formats: 'hex'ed name = formatnumber,...'
|
||||||
|
if (tokens.empty()) {
|
||||||
|
*errorMessage = singleLineUsage(commandDescriptions[CmdLocals]);
|
||||||
|
return std::string();
|
||||||
}
|
}
|
||||||
|
parameters.individualFormats = DumpParameters::decodeFormatArgument(tokens.front());
|
||||||
|
tokens.pop_front();
|
||||||
|
break;
|
||||||
|
} // case option
|
||||||
|
} // for options
|
||||||
|
|
||||||
// Frame and iname
|
// Frame and iname
|
||||||
unsigned frame;
|
unsigned frame;
|
||||||
if (tokens.empty() || !integerFromString(tokens.front(), &frame)) {
|
if (tokens.empty() || !integerFromString(tokens.front(), &frame)) {
|
||||||
@@ -329,8 +351,8 @@ static std::string commmandLocals(ExtensionCommandContext &exc,PCSTR args, int *
|
|||||||
|
|
||||||
const SymbolGroupValueContext dumpContext(exc.dataSpaces());
|
const SymbolGroupValueContext dumpContext(exc.dataSpaces());
|
||||||
return iname.empty() ?
|
return iname.empty() ?
|
||||||
symGroup->dump(dumpContext, humanReadableGdbmi) :
|
symGroup->dump(dumpContext, parameters) :
|
||||||
symGroup->dump(iname, dumpContext, humanReadableGdbmi, errorMessage);
|
symGroup->dump(iname, dumpContext, parameters, errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" HRESULT CALLBACK locals(CIDebugClient *client, PCSTR args)
|
extern "C" HRESULT CALLBACK locals(CIDebugClient *client, PCSTR args)
|
||||||
|
|||||||
@@ -185,6 +185,55 @@ std::wstring stringToWString(const std::string &w)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert an ASCII hex digit to its value 'A'->10
|
||||||
|
inline unsigned hexDigit(char c)
|
||||||
|
{
|
||||||
|
if (c <= '9')
|
||||||
|
return c - '0';
|
||||||
|
if (c <= 'F')
|
||||||
|
return c - 'A' + 10;
|
||||||
|
return c - 'a' + 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert an ASCII hex digit to its value 'A'->10
|
||||||
|
inline char toHexDigit(unsigned v)
|
||||||
|
{
|
||||||
|
if (v < 10)
|
||||||
|
return char(v) + '0';
|
||||||
|
return char(v - 10) + 'a';
|
||||||
|
}
|
||||||
|
|
||||||
|
// String from hex "414A" -> "AJ".
|
||||||
|
std::string stringFromHex(const char *p, const char *end)
|
||||||
|
{
|
||||||
|
if (p == end)
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
std::string rc;
|
||||||
|
rc.reserve((end - p) / 2);
|
||||||
|
for ( ; p < end; p++) {
|
||||||
|
unsigned c = 16 * hexDigit(*p);
|
||||||
|
c += hexDigit(*++p);
|
||||||
|
rc.push_back(char(c));
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring dataToHexW(const unsigned char *p, const unsigned char *end)
|
||||||
|
{
|
||||||
|
if (p == end)
|
||||||
|
return std::wstring();
|
||||||
|
|
||||||
|
std::wstring rc;
|
||||||
|
rc.reserve(2 * (end - p));
|
||||||
|
for ( ; p < end ; p++) {
|
||||||
|
const unsigned c = *p;
|
||||||
|
rc.push_back(toHexDigit(c / 16));
|
||||||
|
rc.push_back(toHexDigit(c &0xF));
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
// Format a map as a GDBMI hash {key="value",..}
|
// Format a map as a GDBMI hash {key="value",..}
|
||||||
void formatGdbmiHash(std::ostream &os, const std::map<std::string, std::string> &m)
|
void formatGdbmiHash(std::ostream &os, const std::map<std::string, std::string> &m)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -86,6 +86,18 @@ bool integerFromString(const std::string &s, Integer *v)
|
|||||||
return !str.fail();
|
return !str.fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read an integer from a wstring as '10' or '0xA'
|
||||||
|
template <class Integer>
|
||||||
|
bool integerFromWString(const std::wstring &s, Integer *v)
|
||||||
|
{
|
||||||
|
const bool isHex = s.compare(0, 2, L"0x") == 0;
|
||||||
|
std::wistringstream str(isHex ? s.substr(2, s.size() - 2) : s);
|
||||||
|
if (isHex)
|
||||||
|
str >> std::hex;
|
||||||
|
str >> *v;
|
||||||
|
return !str.fail();
|
||||||
|
}
|
||||||
|
|
||||||
void replace(std::wstring &s, wchar_t before, wchar_t after);
|
void replace(std::wstring &s, wchar_t before, wchar_t after);
|
||||||
|
|
||||||
// Stream a string onto a char stream doing backslash & octal escaping
|
// Stream a string onto a char stream doing backslash & octal escaping
|
||||||
@@ -128,6 +140,10 @@ std::string wStringToGdbmiString(const std::wstring &w);
|
|||||||
std::string wStringToString(const std::wstring &w);
|
std::string wStringToString(const std::wstring &w);
|
||||||
std::wstring stringToWString(const std::string &w);
|
std::wstring stringToWString(const std::string &w);
|
||||||
|
|
||||||
|
// String from hex "414A" -> "AJ".
|
||||||
|
std::string stringFromHex(const char *begin, const char *end);
|
||||||
|
std::wstring dataToHexW(const unsigned char *begin, const unsigned char *end);
|
||||||
|
|
||||||
// Format a map as a GDBMI hash {key="value",..}
|
// Format a map as a GDBMI hash {key="value",..}
|
||||||
void formatGdbmiHash(std::ostream &os, const std::map<std::string, std::string> &);
|
void formatGdbmiHash(std::ostream &os, const std::map<std::string, std::string> &);
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,128 @@ std::ostream &operator<<(std::ostream &str, const DEBUG_SYMBOL_PARAMETERS ¶m
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --------------- DumpParameters
|
||||||
|
DumpParameters::DumpParameters() : dumpFlags(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// typeformats: decode hex-encoded name, value pairs:
|
||||||
|
// '414A=2,...' -> map of "AB:2".
|
||||||
|
DumpParameters::FormatMap DumpParameters::decodeFormatArgument(const std::string &f)
|
||||||
|
{
|
||||||
|
FormatMap rc;
|
||||||
|
const std::string::size_type size = f.size();
|
||||||
|
// Split 'hexname=4,'
|
||||||
|
for (std::string::size_type pos = 0; pos < size ; ) {
|
||||||
|
// Cut out key
|
||||||
|
const std::string::size_type equalsPos = f.find('=', pos);
|
||||||
|
if (equalsPos == std::string::npos)
|
||||||
|
return rc;
|
||||||
|
const std::string name = stringFromHex(f.c_str() + pos, f.c_str() + equalsPos);
|
||||||
|
// Search for number
|
||||||
|
const std::string::size_type numberPos = equalsPos + 1;
|
||||||
|
std::string::size_type nextPos = f.find(',', numberPos);
|
||||||
|
if (nextPos == std::string::npos)
|
||||||
|
nextPos = size;
|
||||||
|
int format;
|
||||||
|
if (!integerFromString(f.substr(numberPos, nextPos - numberPos), &format))
|
||||||
|
return rc;
|
||||||
|
rc.insert(FormatMap::value_type(name, format));
|
||||||
|
pos = nextPos + 1;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DumpParameters::format(const std::string &type, const std::string &iname) const
|
||||||
|
{
|
||||||
|
if (!individualFormats.empty()) {
|
||||||
|
const FormatMap::const_iterator iit = individualFormats.find(iname);
|
||||||
|
if (iit != individualFormats.end())
|
||||||
|
return iit->second;
|
||||||
|
}
|
||||||
|
if (!typeFormats.empty()) {
|
||||||
|
const FormatMap::const_iterator tit = typeFormats.find(type);
|
||||||
|
if (tit != typeFormats.end())
|
||||||
|
return tit->second;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PointerFormats // Watch data pointer format requests
|
||||||
|
{
|
||||||
|
FormatRawPointer = 0,
|
||||||
|
FormatLatin1String = 1,
|
||||||
|
FormatUtf8String = 2,
|
||||||
|
FormatUtf16String = 3,
|
||||||
|
FormatUcs4String = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
enum DumpEncoding // WatchData encoding of GDBMI values
|
||||||
|
{
|
||||||
|
DumpEncodingAscii = 0,
|
||||||
|
DumpEncodingBase64 = 1,
|
||||||
|
DumpEncodingBase64_Utf16 = 2,
|
||||||
|
DumpEncodingBase64_Ucs4 = 3,
|
||||||
|
DumpEncodingHex_Latin1 = 6,
|
||||||
|
DumpEncodingHex_Utf161 = 7,
|
||||||
|
DumpEncodingHex_Ucs4_LittleEndian = 8,
|
||||||
|
DumpEncodingHex_Utf8_LittleEndian = 9,
|
||||||
|
DumpEncodingHex_Ucs4_BigEndian = 10,
|
||||||
|
DumpEncodingHex_Utf16_BigEndian = 11,
|
||||||
|
DumpEncodingHex_Utf16_LittleEndian = 12
|
||||||
|
};
|
||||||
|
|
||||||
|
bool DumpParameters::recode(const std::string &type,
|
||||||
|
const std::string &iname,
|
||||||
|
const SymbolGroupValueContext &ctx,
|
||||||
|
std::wstring *value, int *encoding) const
|
||||||
|
{
|
||||||
|
// We basically handle char formats for 'char *', '0x834478 "hallo.."'
|
||||||
|
// Determine address and length from the pointer value output,
|
||||||
|
// read the raw memory and recode if that is possible.
|
||||||
|
const int newFormat = format(type, iname);
|
||||||
|
if (newFormat < 2)
|
||||||
|
return false;
|
||||||
|
if (value->compare(0, 2, L"0x"))
|
||||||
|
return false;
|
||||||
|
const std::wstring::size_type quote1 = value->find(L'"', 2);
|
||||||
|
if (quote1 == std::wstring::npos)
|
||||||
|
return false;
|
||||||
|
const std::wstring::size_type quote2 = value->find(L'"', quote1 + 1);
|
||||||
|
if (quote2 == std::wstring::npos)
|
||||||
|
return false;
|
||||||
|
const std::wstring::size_type length = quote2 - quote1 - 1;
|
||||||
|
if (!length)
|
||||||
|
return false;
|
||||||
|
ULONG64 address = 0;
|
||||||
|
if (!integerFromWString(value->substr(0, quote1 - 1), &address) || !address)
|
||||||
|
return false;
|
||||||
|
// Allocate real length + 4 bytes ('\0') for largest format.
|
||||||
|
// '\0' is not listed in the CDB output.
|
||||||
|
const std::wstring::size_type allocLength = length + 4;
|
||||||
|
unsigned char *buffer = new unsigned char[allocLength];
|
||||||
|
std::fill(buffer, buffer + allocLength, 0);
|
||||||
|
ULONG obtained = 0;
|
||||||
|
if (FAILED(ctx.dataspaces->ReadVirtual(address, buffer, ULONG(length), &obtained))) {
|
||||||
|
delete [] buffer;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Recode raw memory
|
||||||
|
switch (newFormat) {
|
||||||
|
case FormatUtf8String:
|
||||||
|
*value = dataToHexW(buffer, buffer + length + 1); // UTF8 + 0
|
||||||
|
*encoding = DumpEncodingHex_Utf8_LittleEndian;
|
||||||
|
break;
|
||||||
|
case FormatUtf16String:
|
||||||
|
break;
|
||||||
|
case FormatUcs4String:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
delete [] buffer;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------- SymbolGroup
|
||||||
SymbolGroup::SymbolGroup(IDebugSymbolGroup2 *sg,
|
SymbolGroup::SymbolGroup(IDebugSymbolGroup2 *sg,
|
||||||
const SymbolParameterVector &vec,
|
const SymbolParameterVector &vec,
|
||||||
ULONG threadId,
|
ULONG threadId,
|
||||||
@@ -579,7 +701,9 @@ static inline void indentStream(std::ostream &str, unsigned depth)
|
|||||||
str << " ";
|
str << " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
void SymbolGroupNode::dump(std::ostream &str, const SymbolGroupValueContext &ctx)
|
void SymbolGroupNode::dump(std::ostream &str,
|
||||||
|
const DumpParameters &p,
|
||||||
|
const SymbolGroupValueContext &ctx)
|
||||||
{
|
{
|
||||||
const std::string iname = fullIName();
|
const std::string iname = fullIName();
|
||||||
const std::string t = type();
|
const std::string t = type();
|
||||||
@@ -595,16 +719,22 @@ void SymbolGroupNode::dump(std::ostream &str, const SymbolGroupValueContext &ctx
|
|||||||
bool valueEditable = !uninitialized;
|
bool valueEditable = !uninitialized;
|
||||||
bool valueEnabled = !uninitialized;
|
bool valueEnabled = !uninitialized;
|
||||||
|
|
||||||
const std::wstring value = displayValue(ctx);
|
// Shall it be recoded?
|
||||||
// ASCII or base64?
|
std::wstring value = displayValue(ctx);
|
||||||
|
int encoding = 0;
|
||||||
|
if (p.recode(t, iname, ctx, &value, &encoding)) {
|
||||||
|
str << ",valueencoded=\"" << encoding
|
||||||
|
<< "\",value=\"" << gdbmiWStringFormat(value) <<'"';
|
||||||
|
} else { // As is: ASCII or base64?
|
||||||
if (isSevenBitClean(value.c_str(), value.size())) {
|
if (isSevenBitClean(value.c_str(), value.size())) {
|
||||||
str << ",valueencoded=\"0\",value=\"" << gdbmiWStringFormat(value) << '"';
|
str << ",valueencoded=\"" << DumpEncodingAscii << "\",value=\""
|
||||||
|
<< gdbmiWStringFormat(value) << '"';
|
||||||
} else {
|
} else {
|
||||||
str << ",valueencoded=\"2\",value=\"";
|
str << ",valueencoded=\"" << DumpEncodingBase64_Utf16 << "\",value=\"";
|
||||||
base64Encode(str, reinterpret_cast<const unsigned char *>(value.c_str()), value.size() * sizeof(wchar_t));
|
base64Encode(str, reinterpret_cast<const unsigned char *>(value.c_str()), value.size() * sizeof(wchar_t));
|
||||||
str << '"';
|
str << '"';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Children: Dump all known or subelements (guess).
|
// Children: Dump all known or subelements (guess).
|
||||||
const VectorIndexType childCountGuess = uninitialized ? 0 :
|
const VectorIndexType childCountGuess = uninitialized ? 0 :
|
||||||
(m_children.empty() ? m_parameters.SubElements : m_children.size());
|
(m_children.empty() ? m_parameters.SubElements : m_children.size());
|
||||||
@@ -792,11 +922,12 @@ static inline std::string msgNotFound(const std::string &nodeName)
|
|||||||
return str.str();
|
return str.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SymbolGroup::dump(const SymbolGroupValueContext &ctx, bool humanReadable) const
|
std::string SymbolGroup::dump(const SymbolGroupValueContext &ctx,
|
||||||
|
const DumpParameters &p) const
|
||||||
{
|
{
|
||||||
std::ostringstream str;
|
std::ostringstream str;
|
||||||
DumpSymbolGroupNodeVisitor visitor(str, ctx, humanReadable);
|
DumpSymbolGroupNodeVisitor visitor(str, ctx, p);
|
||||||
if (humanReadable)
|
if (p.humanReadable())
|
||||||
str << '\n';
|
str << '\n';
|
||||||
str << '[';
|
str << '[';
|
||||||
accept(visitor);
|
accept(visitor);
|
||||||
@@ -805,7 +936,10 @@ std::string SymbolGroup::dump(const SymbolGroupValueContext &ctx, bool humanRead
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Dump a node, potentially expand
|
// Dump a node, potentially expand
|
||||||
std::string SymbolGroup::dump(const std::string &iname, const SymbolGroupValueContext &ctx, bool humanReadable, std::string *errorMessage)
|
std::string SymbolGroup::dump(const std::string &iname,
|
||||||
|
const SymbolGroupValueContext &ctx,
|
||||||
|
const DumpParameters &p,
|
||||||
|
std::string *errorMessage)
|
||||||
{
|
{
|
||||||
SymbolGroupNode *const node = find(iname);
|
SymbolGroupNode *const node = find(iname);
|
||||||
if (node == 0) {
|
if (node == 0) {
|
||||||
@@ -819,9 +953,9 @@ std::string SymbolGroup::dump(const std::string &iname, const SymbolGroupValueCo
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
std::ostringstream str;
|
std::ostringstream str;
|
||||||
if (humanReadable)
|
if (p.humanReadable())
|
||||||
str << '\n';
|
str << '\n';
|
||||||
DumpSymbolGroupNodeVisitor visitor(str, ctx, humanReadable);
|
DumpSymbolGroupNodeVisitor visitor(str, ctx, p);
|
||||||
str << '[';
|
str << '[';
|
||||||
node->accept(visitor, 0, 0);
|
node->accept(visitor, 0, 0);
|
||||||
str << ']';
|
str << ']';
|
||||||
@@ -1056,8 +1190,9 @@ SymbolGroupNodeVisitor::VisitResult
|
|||||||
// --------------------- DumpSymbolGroupNodeVisitor
|
// --------------------- DumpSymbolGroupNodeVisitor
|
||||||
DumpSymbolGroupNodeVisitor::DumpSymbolGroupNodeVisitor(std::ostream &os,
|
DumpSymbolGroupNodeVisitor::DumpSymbolGroupNodeVisitor(std::ostream &os,
|
||||||
const SymbolGroupValueContext &context,
|
const SymbolGroupValueContext &context,
|
||||||
bool humanReadable) :
|
const DumpParameters ¶meters) :
|
||||||
m_os(os), m_humanReadable(humanReadable),m_context(context), m_visitChildren(false)
|
m_os(os), m_context(context), m_parameters(parameters),
|
||||||
|
m_visitChildren(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1073,18 +1208,18 @@ SymbolGroupNodeVisitor::VisitResult
|
|||||||
// Do not recurse into children unless the node was expanded by the watch model
|
// Do not recurse into children unless the node was expanded by the watch model
|
||||||
if (child)
|
if (child)
|
||||||
m_os << ','; // Separator in parents list
|
m_os << ','; // Separator in parents list
|
||||||
if (m_humanReadable) {
|
if (m_parameters.humanReadable()) {
|
||||||
m_os << '\n';
|
m_os << '\n';
|
||||||
indentStream(m_os, depth * 2);
|
indentStream(m_os, depth * 2);
|
||||||
}
|
}
|
||||||
m_os << '{';
|
m_os << '{';
|
||||||
node->dump(m_os, m_context);
|
node->dump(m_os, m_parameters, m_context);
|
||||||
if (m_visitChildren) { // open children array
|
if (m_visitChildren) { // open children array
|
||||||
m_os << ",children=[";
|
m_os << ",children=[";
|
||||||
} else { // No children, close array.
|
} else { // No children, close array.
|
||||||
m_os << '}';
|
m_os << '}';
|
||||||
}
|
}
|
||||||
if (m_humanReadable)
|
if (m_parameters.humanReadable())
|
||||||
m_os << '\n';
|
m_os << '\n';
|
||||||
return m_visitChildren ? VisitContinue : VisitSkipChildren;
|
return m_visitChildren ? VisitContinue : VisitSkipChildren;
|
||||||
}
|
}
|
||||||
@@ -1092,6 +1227,6 @@ SymbolGroupNodeVisitor::VisitResult
|
|||||||
void DumpSymbolGroupNodeVisitor::childrenVisited(const SymbolGroupNode *, unsigned)
|
void DumpSymbolGroupNodeVisitor::childrenVisited(const SymbolGroupNode *, unsigned)
|
||||||
{
|
{
|
||||||
m_os << "]}"; // Close children array and self
|
m_os << "]}"; // Close children array and self
|
||||||
if (m_humanReadable)
|
if (m_parameters.humanReadable())
|
||||||
m_os << '\n';
|
m_os << '\n';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &, const DEBUG_SYMBOL_PARAMETERS&p);
|
std::ostream &operator<<(std::ostream &, const DEBUG_SYMBOL_PARAMETERS&p);
|
||||||
@@ -42,6 +43,31 @@ class SymbolGroupNodeVisitor;
|
|||||||
class SymbolGroup;
|
class SymbolGroup;
|
||||||
struct SymbolGroupValueContext;
|
struct SymbolGroupValueContext;
|
||||||
|
|
||||||
|
// All parameters for dumping in one struct.
|
||||||
|
struct DumpParameters
|
||||||
|
{
|
||||||
|
typedef std::map<std::string, int> FormatMap; // type or iname to format
|
||||||
|
enum DumpFlags
|
||||||
|
{
|
||||||
|
DumpHumanReadable = 0x1,
|
||||||
|
DumpComplexDumpers = 0x2
|
||||||
|
};
|
||||||
|
|
||||||
|
DumpParameters();
|
||||||
|
bool humanReadable() const { return dumpFlags & DumpHumanReadable; }
|
||||||
|
// Helper to decode format option arguments.
|
||||||
|
static FormatMap decodeFormatArgument(const std::string &f);
|
||||||
|
|
||||||
|
bool recode(const std::string &type, const std::string &iname,
|
||||||
|
const SymbolGroupValueContext &ctx,
|
||||||
|
std::wstring *value, int *encoding) const;
|
||||||
|
int format(const std::string &type, const std::string &iname) const;
|
||||||
|
|
||||||
|
unsigned dumpFlags;
|
||||||
|
FormatMap typeFormats;
|
||||||
|
FormatMap individualFormats;
|
||||||
|
};
|
||||||
|
|
||||||
// Thin wrapper around a symbol group entry. Provides accessors for fixed-up
|
// Thin wrapper around a symbol group entry. Provides accessors for fixed-up
|
||||||
// symbol group value and a dumping facility triggered by dump()/displayValue()
|
// symbol group value and a dumping facility triggered by dump()/displayValue()
|
||||||
// calling dumpSimpleType() based on SymbolGroupValue expressions. These values
|
// calling dumpSimpleType() based on SymbolGroupValue expressions. These values
|
||||||
@@ -70,6 +96,7 @@ public:
|
|||||||
ExpandedByDumper = 0x10,
|
ExpandedByDumper = 0x10,
|
||||||
AdditionalSymbol = 0x20 // Introduced by addSymbol, should not be visible
|
AdditionalSymbol = 0x20 // Introduced by addSymbol, should not be visible
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<DEBUG_SYMBOL_PARAMETERS> SymbolParameterVector;
|
typedef std::vector<DEBUG_SYMBOL_PARAMETERS> SymbolParameterVector;
|
||||||
typedef std::vector<SymbolGroupNode *> SymbolGroupNodePtrVector;
|
typedef std::vector<SymbolGroupNode *> SymbolGroupNodePtrVector;
|
||||||
typedef SymbolGroupNodePtrVector::iterator SymbolGroupNodePtrVectorIterator;
|
typedef SymbolGroupNodePtrVector::iterator SymbolGroupNodePtrVectorIterator;
|
||||||
@@ -102,7 +129,7 @@ public:
|
|||||||
SymbolGroup *symbolGroup() const { return m_symbolGroup; }
|
SymbolGroup *symbolGroup() const { return m_symbolGroup; }
|
||||||
|
|
||||||
// I/O: Gdbmi dump for Visitors
|
// I/O: Gdbmi dump for Visitors
|
||||||
void dump(std::ostream &str, const SymbolGroupValueContext &ctx);
|
void dump(std::ostream &str, const DumpParameters &p, const SymbolGroupValueContext &ctx);
|
||||||
// I/O: debug for Visitors
|
// I/O: debug for Visitors
|
||||||
void debug(std::ostream &os, unsigned verbosity, unsigned depth) const;
|
void debug(std::ostream &os, unsigned verbosity, unsigned depth) const;
|
||||||
|
|
||||||
@@ -202,10 +229,11 @@ public:
|
|||||||
~SymbolGroup();
|
~SymbolGroup();
|
||||||
|
|
||||||
// Dump all
|
// Dump all
|
||||||
std::string dump(const SymbolGroupValueContext &ctx, bool humanReadable = false) const;
|
std::string dump(const SymbolGroupValueContext &ctx,
|
||||||
|
const DumpParameters &p = DumpParameters()) const;
|
||||||
// Expand node and dump
|
// Expand node and dump
|
||||||
std::string dump(const std::string &iname, const SymbolGroupValueContext &ctx,
|
std::string dump(const std::string &iname, const SymbolGroupValueContext &ctx,
|
||||||
bool humanReadable, std::string *errorMessage);
|
const DumpParameters &p, std::string *errorMessage);
|
||||||
std::string debug(const std::string &iname = std::string(), unsigned verbosity = 0) const;
|
std::string debug(const std::string &iname = std::string(), unsigned verbosity = 0) const;
|
||||||
|
|
||||||
unsigned frame() const { return m_frame; }
|
unsigned frame() const { return m_frame; }
|
||||||
@@ -274,15 +302,15 @@ class DumpSymbolGroupNodeVisitor : public SymbolGroupNodeVisitor {
|
|||||||
public:
|
public:
|
||||||
explicit DumpSymbolGroupNodeVisitor(std::ostream &os,
|
explicit DumpSymbolGroupNodeVisitor(std::ostream &os,
|
||||||
const SymbolGroupValueContext &context,
|
const SymbolGroupValueContext &context,
|
||||||
bool humanReadable);
|
const DumpParameters ¶meters = DumpParameters());
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual VisitResult visit(SymbolGroupNode *node, unsigned child, unsigned depth);
|
virtual VisitResult visit(SymbolGroupNode *node, unsigned child, unsigned depth);
|
||||||
virtual void childrenVisited(const SymbolGroupNode * node, unsigned depth);
|
virtual void childrenVisited(const SymbolGroupNode * node, unsigned depth);
|
||||||
|
|
||||||
std::ostream &m_os;
|
std::ostream &m_os;
|
||||||
const bool m_humanReadable;
|
|
||||||
const SymbolGroupValueContext &m_context;
|
const SymbolGroupValueContext &m_context;
|
||||||
|
const DumpParameters &m_parameters;
|
||||||
bool m_visitChildren;
|
bool m_visitChildren;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -653,13 +653,26 @@ void CdbEngine::updateWatchData(const Debugger::Internal::WatchData &dataIn,
|
|||||||
updateLocalVariable(dataIn.iname);
|
updateLocalVariable(dataIn.iname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CdbEngine::addLocalsOptions(ByteArrayInputStream &str) const
|
||||||
|
{
|
||||||
|
if (debuggerCore()->boolSetting(UseDebuggingHelpers))
|
||||||
|
str << blankSeparator << "-c";
|
||||||
|
const QByteArray typeFormats = watchHandler()->typeFormatRequests();
|
||||||
|
if (!typeFormats.isEmpty())
|
||||||
|
str << blankSeparator << "-T " << typeFormats;
|
||||||
|
const QByteArray individualFormats = watchHandler()->individualFormatRequests();
|
||||||
|
if (!individualFormats.isEmpty())
|
||||||
|
str << blankSeparator << "-I " << individualFormats;
|
||||||
|
}
|
||||||
|
|
||||||
void CdbEngine::updateLocalVariable(const QByteArray &iname)
|
void CdbEngine::updateLocalVariable(const QByteArray &iname)
|
||||||
{
|
{
|
||||||
const int stackFrame = stackHandler()->currentIndex();
|
const int stackFrame = stackHandler()->currentIndex();
|
||||||
if (stackFrame >= 0) {
|
if (stackFrame >= 0) {
|
||||||
QByteArray localsArguments;
|
QByteArray localsArguments;
|
||||||
ByteArrayInputStream str(localsArguments);
|
ByteArrayInputStream str(localsArguments);
|
||||||
str << stackFrame << ' ' << iname;
|
addLocalsOptions(str);
|
||||||
|
str << blankSeparator << stackFrame << ' ' << iname;
|
||||||
postExtensionCommand("locals", localsArguments, 0, &CdbEngine::handleLocals);
|
postExtensionCommand("locals", localsArguments, 0, &CdbEngine::handleLocals);
|
||||||
} else {
|
} else {
|
||||||
qWarning("Internal error; no stack frame in updateLocalVariable");
|
qWarning("Internal error; no stack frame in updateLocalVariable");
|
||||||
@@ -973,6 +986,7 @@ void CdbEngine::activateFrame(int index)
|
|||||||
str << e;
|
str << e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
addLocalsOptions(str);
|
||||||
// Uninitialized variables if desired
|
// Uninitialized variables if desired
|
||||||
if (debuggerCore()->boolSetting(UseCodeModel)) {
|
if (debuggerCore()->boolSetting(UseCodeModel)) {
|
||||||
QStringList uninitializedVariables;
|
QStringList uninitializedVariables;
|
||||||
@@ -1299,8 +1313,10 @@ void CdbEngine::handleSessionIdle(const QByteArray &message)
|
|||||||
notifyInferiorSpontaneousStop();
|
notifyInferiorSpontaneousStop();
|
||||||
}
|
}
|
||||||
// Start sequence to get all relevant data. Hack: Avoid module reload?
|
// Start sequence to get all relevant data. Hack: Avoid module reload?
|
||||||
unsigned sequence = CommandListStack|CommandListRegisters|CommandListThreads;
|
unsigned sequence = CommandListStack;
|
||||||
if (modulesHandler()->modules().size() == 0)
|
if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_REGISTER)))
|
||||||
|
sequence |= CommandListRegisters;
|
||||||
|
if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_MODULES)))
|
||||||
sequence |= CommandListModules;
|
sequence |= CommandListModules;
|
||||||
postCommandSequence(sequence);
|
postCommandSequence(sequence);
|
||||||
// Report stop reason (GDBMI)
|
// Report stop reason (GDBMI)
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class DisassemblerViewAgent;
|
|||||||
struct CdbBuiltinCommand;
|
struct CdbBuiltinCommand;
|
||||||
struct CdbExtensionCommand;
|
struct CdbExtensionCommand;
|
||||||
struct CdbOptions;
|
struct CdbOptions;
|
||||||
|
class ByteArrayInputStream;
|
||||||
|
|
||||||
class CdbEngine : public Debugger::DebuggerEngine
|
class CdbEngine : public Debugger::DebuggerEngine
|
||||||
{
|
{
|
||||||
@@ -174,6 +175,7 @@ private:
|
|||||||
QString normalizeFileName(const QString &f);
|
QString normalizeFileName(const QString &f);
|
||||||
void updateLocalVariable(const QByteArray &iname);
|
void updateLocalVariable(const QByteArray &iname);
|
||||||
int elapsedLogTime() const;
|
int elapsedLogTime() const;
|
||||||
|
void addLocalsOptions(ByteArrayInputStream &s) const;
|
||||||
|
|
||||||
const QByteArray m_creatorExtPrefix;
|
const QByteArray m_creatorExtPrefix;
|
||||||
const QByteArray m_tokenPrefix;
|
const QByteArray m_tokenPrefix;
|
||||||
|
|||||||
Reference in New Issue
Block a user