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"},
|
||||
{"locals",
|
||||
"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"
|
||||
"-d debug output\n"
|
||||
"-c complex dumpers\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).",
|
||||
"[-t token] <frame-number> <iname>"},
|
||||
{"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
|
||||
unsigned debugOutput = 0;
|
||||
bool humanReadableGdbmi = false;
|
||||
std::string iname;
|
||||
|
||||
StringList tokens = commandTokens<StringList>(args, token);
|
||||
StringVector expandedInames;
|
||||
StringVector uninitializedInames;
|
||||
DumpParameters parameters;
|
||||
// Parse away options
|
||||
while (!tokens.empty() && tokens.front().size() == 2 && tokens.front().at(0) == '-') {
|
||||
const char option = tokens.front().at(1);
|
||||
@@ -285,7 +287,10 @@ static std::string commmandLocals(ExtensionCommandContext &exc,PCSTR args, int *
|
||||
debugOutput++;
|
||||
break;
|
||||
case 'h':
|
||||
humanReadableGdbmi = true;
|
||||
parameters.dumpFlags |= DumpParameters::DumpHumanReadable;
|
||||
break;
|
||||
case 'c':
|
||||
parameters.dumpFlags |= DumpParameters::DumpComplexDumpers;
|
||||
break;
|
||||
case 'u':
|
||||
if (tokens.empty()) {
|
||||
@@ -303,8 +308,25 @@ static std::string commmandLocals(ExtensionCommandContext &exc,PCSTR args, int *
|
||||
split(tokens.front(), ',', std::back_inserter(expandedInames));
|
||||
tokens.pop_front();
|
||||
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
|
||||
unsigned 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());
|
||||
return iname.empty() ?
|
||||
symGroup->dump(dumpContext, humanReadableGdbmi) :
|
||||
symGroup->dump(iname, dumpContext, humanReadableGdbmi, errorMessage);
|
||||
symGroup->dump(dumpContext, parameters) :
|
||||
symGroup->dump(iname, dumpContext, parameters, errorMessage);
|
||||
}
|
||||
|
||||
extern "C" HRESULT CALLBACK locals(CIDebugClient *client, PCSTR args)
|
||||
|
||||
@@ -185,6 +185,55 @@ std::wstring stringToWString(const std::string &w)
|
||||
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",..}
|
||||
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();
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// 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::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",..}
|
||||
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;
|
||||
}
|
||||
|
||||
// --------------- 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,
|
||||
const SymbolParameterVector &vec,
|
||||
ULONG threadId,
|
||||
@@ -579,7 +701,9 @@ static inline void indentStream(std::ostream &str, unsigned depth)
|
||||
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 t = type();
|
||||
@@ -595,16 +719,22 @@ void SymbolGroupNode::dump(std::ostream &str, const SymbolGroupValueContext &ctx
|
||||
bool valueEditable = !uninitialized;
|
||||
bool valueEnabled = !uninitialized;
|
||||
|
||||
const std::wstring value = displayValue(ctx);
|
||||
// ASCII or base64?
|
||||
if (isSevenBitClean(value.c_str(), value.size())) {
|
||||
str << ",valueencoded=\"0\",value=\"" << gdbmiWStringFormat(value) << '"';
|
||||
} else {
|
||||
str << ",valueencoded=\"2\",value=\"";
|
||||
base64Encode(str, reinterpret_cast<const unsigned char *>(value.c_str()), value.size() * sizeof(wchar_t));
|
||||
str << '"';
|
||||
// Shall it be recoded?
|
||||
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())) {
|
||||
str << ",valueencoded=\"" << DumpEncodingAscii << "\",value=\""
|
||||
<< gdbmiWStringFormat(value) << '"';
|
||||
} else {
|
||||
str << ",valueencoded=\"" << DumpEncodingBase64_Utf16 << "\",value=\"";
|
||||
base64Encode(str, reinterpret_cast<const unsigned char *>(value.c_str()), value.size() * sizeof(wchar_t));
|
||||
str << '"';
|
||||
}
|
||||
}
|
||||
|
||||
// Children: Dump all known or subelements (guess).
|
||||
const VectorIndexType childCountGuess = uninitialized ? 0 :
|
||||
(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();
|
||||
}
|
||||
|
||||
std::string SymbolGroup::dump(const SymbolGroupValueContext &ctx, bool humanReadable) const
|
||||
std::string SymbolGroup::dump(const SymbolGroupValueContext &ctx,
|
||||
const DumpParameters &p) const
|
||||
{
|
||||
std::ostringstream str;
|
||||
DumpSymbolGroupNodeVisitor visitor(str, ctx, humanReadable);
|
||||
if (humanReadable)
|
||||
DumpSymbolGroupNodeVisitor visitor(str, ctx, p);
|
||||
if (p.humanReadable())
|
||||
str << '\n';
|
||||
str << '[';
|
||||
accept(visitor);
|
||||
@@ -805,7 +936,10 @@ std::string SymbolGroup::dump(const SymbolGroupValueContext &ctx, bool humanRead
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (node == 0) {
|
||||
@@ -819,9 +953,9 @@ std::string SymbolGroup::dump(const std::string &iname, const SymbolGroupValueCo
|
||||
return false;
|
||||
}
|
||||
std::ostringstream str;
|
||||
if (humanReadable)
|
||||
if (p.humanReadable())
|
||||
str << '\n';
|
||||
DumpSymbolGroupNodeVisitor visitor(str, ctx, humanReadable);
|
||||
DumpSymbolGroupNodeVisitor visitor(str, ctx, p);
|
||||
str << '[';
|
||||
node->accept(visitor, 0, 0);
|
||||
str << ']';
|
||||
@@ -1056,8 +1190,9 @@ SymbolGroupNodeVisitor::VisitResult
|
||||
// --------------------- DumpSymbolGroupNodeVisitor
|
||||
DumpSymbolGroupNodeVisitor::DumpSymbolGroupNodeVisitor(std::ostream &os,
|
||||
const SymbolGroupValueContext &context,
|
||||
bool humanReadable) :
|
||||
m_os(os), m_humanReadable(humanReadable),m_context(context), m_visitChildren(false)
|
||||
const DumpParameters ¶meters) :
|
||||
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
|
||||
if (child)
|
||||
m_os << ','; // Separator in parents list
|
||||
if (m_humanReadable) {
|
||||
if (m_parameters.humanReadable()) {
|
||||
m_os << '\n';
|
||||
indentStream(m_os, depth * 2);
|
||||
}
|
||||
m_os << '{';
|
||||
node->dump(m_os, m_context);
|
||||
node->dump(m_os, m_parameters, m_context);
|
||||
if (m_visitChildren) { // open children array
|
||||
m_os << ",children=[";
|
||||
} else { // No children, close array.
|
||||
m_os << '}';
|
||||
}
|
||||
if (m_humanReadable)
|
||||
if (m_parameters.humanReadable())
|
||||
m_os << '\n';
|
||||
return m_visitChildren ? VisitContinue : VisitSkipChildren;
|
||||
}
|
||||
@@ -1092,6 +1227,6 @@ SymbolGroupNodeVisitor::VisitResult
|
||||
void DumpSymbolGroupNodeVisitor::childrenVisited(const SymbolGroupNode *, unsigned)
|
||||
{
|
||||
m_os << "]}"; // Close children array and self
|
||||
if (m_humanReadable)
|
||||
if (m_parameters.humanReadable())
|
||||
m_os << '\n';
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <iosfwd>
|
||||
|
||||
std::ostream &operator<<(std::ostream &, const DEBUG_SYMBOL_PARAMETERS&p);
|
||||
@@ -42,6 +43,31 @@ class SymbolGroupNodeVisitor;
|
||||
class SymbolGroup;
|
||||
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
|
||||
// symbol group value and a dumping facility triggered by dump()/displayValue()
|
||||
// calling dumpSimpleType() based on SymbolGroupValue expressions. These values
|
||||
@@ -70,6 +96,7 @@ public:
|
||||
ExpandedByDumper = 0x10,
|
||||
AdditionalSymbol = 0x20 // Introduced by addSymbol, should not be visible
|
||||
};
|
||||
|
||||
typedef std::vector<DEBUG_SYMBOL_PARAMETERS> SymbolParameterVector;
|
||||
typedef std::vector<SymbolGroupNode *> SymbolGroupNodePtrVector;
|
||||
typedef SymbolGroupNodePtrVector::iterator SymbolGroupNodePtrVectorIterator;
|
||||
@@ -102,7 +129,7 @@ public:
|
||||
SymbolGroup *symbolGroup() const { return m_symbolGroup; }
|
||||
|
||||
// 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
|
||||
void debug(std::ostream &os, unsigned verbosity, unsigned depth) const;
|
||||
|
||||
@@ -202,10 +229,11 @@ public:
|
||||
~SymbolGroup();
|
||||
|
||||
// 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
|
||||
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;
|
||||
|
||||
unsigned frame() const { return m_frame; }
|
||||
@@ -274,15 +302,15 @@ class DumpSymbolGroupNodeVisitor : public SymbolGroupNodeVisitor {
|
||||
public:
|
||||
explicit DumpSymbolGroupNodeVisitor(std::ostream &os,
|
||||
const SymbolGroupValueContext &context,
|
||||
bool humanReadable);
|
||||
const DumpParameters ¶meters = DumpParameters());
|
||||
|
||||
private:
|
||||
virtual VisitResult visit(SymbolGroupNode *node, unsigned child, unsigned depth);
|
||||
virtual void childrenVisited(const SymbolGroupNode * node, unsigned depth);
|
||||
|
||||
std::ostream &m_os;
|
||||
const bool m_humanReadable;
|
||||
const SymbolGroupValueContext &m_context;
|
||||
const DumpParameters &m_parameters;
|
||||
bool m_visitChildren;
|
||||
};
|
||||
|
||||
|
||||
@@ -653,13 +653,26 @@ void CdbEngine::updateWatchData(const Debugger::Internal::WatchData &dataIn,
|
||||
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)
|
||||
{
|
||||
const int stackFrame = stackHandler()->currentIndex();
|
||||
if (stackFrame >= 0) {
|
||||
QByteArray localsArguments;
|
||||
ByteArrayInputStream str(localsArguments);
|
||||
str << stackFrame << ' ' << iname;
|
||||
addLocalsOptions(str);
|
||||
str << blankSeparator << stackFrame << ' ' << iname;
|
||||
postExtensionCommand("locals", localsArguments, 0, &CdbEngine::handleLocals);
|
||||
} else {
|
||||
qWarning("Internal error; no stack frame in updateLocalVariable");
|
||||
@@ -973,6 +986,7 @@ void CdbEngine::activateFrame(int index)
|
||||
str << e;
|
||||
}
|
||||
}
|
||||
addLocalsOptions(str);
|
||||
// Uninitialized variables if desired
|
||||
if (debuggerCore()->boolSetting(UseCodeModel)) {
|
||||
QStringList uninitializedVariables;
|
||||
@@ -1299,8 +1313,10 @@ void CdbEngine::handleSessionIdle(const QByteArray &message)
|
||||
notifyInferiorSpontaneousStop();
|
||||
}
|
||||
// Start sequence to get all relevant data. Hack: Avoid module reload?
|
||||
unsigned sequence = CommandListStack|CommandListRegisters|CommandListThreads;
|
||||
if (modulesHandler()->modules().size() == 0)
|
||||
unsigned sequence = CommandListStack;
|
||||
if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_REGISTER)))
|
||||
sequence |= CommandListRegisters;
|
||||
if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_MODULES)))
|
||||
sequence |= CommandListModules;
|
||||
postCommandSequence(sequence);
|
||||
// Report stop reason (GDBMI)
|
||||
|
||||
@@ -45,6 +45,7 @@ class DisassemblerViewAgent;
|
||||
struct CdbBuiltinCommand;
|
||||
struct CdbExtensionCommand;
|
||||
struct CdbOptions;
|
||||
class ByteArrayInputStream;
|
||||
|
||||
class CdbEngine : public Debugger::DebuggerEngine
|
||||
{
|
||||
@@ -174,6 +175,7 @@ private:
|
||||
QString normalizeFileName(const QString &f);
|
||||
void updateLocalVariable(const QByteArray &iname);
|
||||
int elapsedLogTime() const;
|
||||
void addLocalsOptions(ByteArrayInputStream &s) const;
|
||||
|
||||
const QByteArray m_creatorExtPrefix;
|
||||
const QByteArray m_tokenPrefix;
|
||||
|
||||
Reference in New Issue
Block a user