Debugger[New CDDB]: Dump strings and simple Qt types.

Add infrastructure for simple dumpers in Symbol group.
Fix display of class values.
This commit is contained in:
Friedemann Kleint
2010-11-26 15:51:56 +01:00
parent 640a9c32c0
commit 30e74df0ba
8 changed files with 421 additions and 169 deletions

View File

@@ -204,11 +204,14 @@ static std::string commmandLocals(ExtensionCommandContext &exc,PCSTR args, int *
symGroup->expandList(expandedInames, errorMessage);
if (!uninitializedInames.empty())
symGroup->markUninitialized(uninitializedInames);
// Complete dump
if (iname.empty())
return debugOutput ? symGroup->debug(debugOutput - 1) : symGroup->dump(humanReadableGdbmi);
// Look up iname
return symGroup->dump(iname, humanReadableGdbmi, errorMessage);
if (debugOutput)
return symGroup->debug(iname, debugOutput - 1);
const SymbolGroupValueContext dumpContext(exc.dataSpaces());
return iname.empty() ?
symGroup->dump(dumpContext, humanReadableGdbmi) :
symGroup->dump(iname, dumpContext, humanReadableGdbmi, errorMessage);
}
extern "C" HRESULT CALLBACK locals(CIDebugClient *client, PCSTR args)

View File

@@ -28,6 +28,7 @@
**************************************************************************/
#include "symbolgroup.h"
#include "symbolgroupvalue.h"
#include "stringutils.h"
#include "base64.h"
@@ -443,10 +444,18 @@ static void fixValue(const std::string &type, std::wstring *value)
value->erase(0, 2);
return;
}
// Fix long class names on std containers 'class std::tree<...>' -> 'class std::tree<>'
if (value->compare(0, 6, L"class ") == 0) {
const std::string::size_type openTemplate = value->find(L'<');
if (openTemplate != std::string::npos) {
value->erase(openTemplate + 1, value->size() - openTemplate - 2);
return;
}
}
}
// Check for ASCII-encode-able stuff. Plain characters + tabs at the most, no newline.
static bool isSevenBitClean(const wchar_t *buf, ULONG size)
static bool isSevenBitClean(const wchar_t *buf, size_t size)
{
const wchar_t *bufEnd = buf + size;
for (const wchar_t *bufPtr = buf; bufPtr < bufEnd; bufPtr++) {
@@ -464,29 +473,6 @@ std::string SymbolGroupNode::type() const
return SUCCEEDED(hr) ? std::string(buf) : std::string();
}
wchar_t *SymbolGroupNode::getValue(ULONG *obtainedSizeIn /* = 0 */) const
{
// Determine size and return allocated buffer
if (obtainedSizeIn)
*obtainedSizeIn = 0;
const ULONG maxValueSize = 262144;
ULONG obtainedSize = 0;
HRESULT hr = m_symbolGroup->debugSymbolGroup()->GetSymbolValueTextWide(m_index, NULL, maxValueSize, &obtainedSize);
if (FAILED(hr))
return 0;
if (obtainedSize > maxValueSize)
obtainedSize = maxValueSize;
wchar_t *buffer = new wchar_t[obtainedSize];
hr = m_symbolGroup->debugSymbolGroup()->GetSymbolValueTextWide(m_index, buffer, obtainedSize, &obtainedSize);
if (FAILED(hr)) { // Whoops, should not happen
delete [] buffer;
return 0;
}
if (obtainedSizeIn)
*obtainedSizeIn = obtainedSize;
return buffer;
}
ULONG64 SymbolGroupNode::address() const
{
ULONG64 address = 0;
@@ -496,34 +482,63 @@ ULONG64 SymbolGroupNode::address() const
return 0;
}
std::wstring SymbolGroupNode::rawValue() const
std::wstring SymbolGroupNode::symbolGroupRawValue() const
{
std::wstring rc;
if (const wchar_t *wbuf = getValue()) {
rc = wbuf;
delete[] wbuf;
}
// Determine size and return allocated buffer
const ULONG maxValueSize = 262144;
ULONG obtainedSize = 0;
HRESULT hr = m_symbolGroup->debugSymbolGroup()->GetSymbolValueTextWide(m_index, NULL, maxValueSize, &obtainedSize);
if (FAILED(hr))
return std::wstring();
if (obtainedSize > maxValueSize)
obtainedSize = maxValueSize;
wchar_t *buffer = new wchar_t[obtainedSize];
hr = m_symbolGroup->debugSymbolGroup()->GetSymbolValueTextWide(m_index, buffer, obtainedSize, &obtainedSize);
if (FAILED(hr)) // Whoops, should not happen
buffer[0] = 0;
const std::wstring rc(buffer);
delete [] buffer;
return rc;
}
std::wstring SymbolGroupNode::fixedValue() const
std::wstring SymbolGroupNode::symbolGroupFixedValue() const
{
std::wstring value = rawValue();
std::wstring value = symbolGroupRawValue();
fixValue(type(), &value);
return value;
}
// Value to be reported to debugger
std::wstring SymbolGroupNode::displayValue(const SymbolGroupValueContext &ctx)
{
if (m_flags & Uninitialized)
return L"<not in scope>";
if ((m_flags & DumperMask) == 0)
m_flags |= dumpSimpleType(this , ctx, &m_dumperValue);
if (m_flags & DumperOk)
return m_dumperValue;
return symbolGroupFixedValue();
}
SymbolGroupNode *SymbolGroupNode::childAt(unsigned i) const
{
return i < m_children.size() ? m_children.at(i) : static_cast<SymbolGroupNode *>(0);
}
unsigned SymbolGroupNode::indexByIName(const char *n) const
{
const VectorIndexType size = m_children.size();
for (VectorIndexType i = 0; i < size; i++)
if ( m_children.at(i)->iName() == n )
return unsigned(i);
return unsigned(-1);
}
SymbolGroupNode *SymbolGroupNode::childByIName(const char *n) const
{
const SymbolGroupNodePtrVector::const_iterator childrenEnd = m_children.end();
for (SymbolGroupNodePtrVector::const_iterator it = m_children.begin(); it != childrenEnd; ++it)
if ( (*it)->iName() == n )
return *it;
const unsigned index = indexByIName(n);
if (index != unsigned(-1))
return m_children.at(index);
return 0;
}
@@ -533,51 +548,32 @@ static inline void indentStream(std::ostream &str, unsigned depth)
str << " ";
}
void SymbolGroupNode::dump(std::ostream &str, unsigned child, unsigned depth,
bool humanReadable) const
void SymbolGroupNode::dump(std::ostream &str, const SymbolGroupValueContext &ctx)
{
const std::string iname = fullIName();
const std::string t = type();
if (child) { // Separate list of children
str << ',';
if (humanReadable)
str << '\n';
}
if (humanReadable)
indentStream(str, depth);
str << "{iname=\"" << iname << "\",exp=\"" << iname << "\",name=\"" << m_name
str << "iname=\"" << iname << "\",exp=\"" << iname << "\",name=\"" << m_name
<< "\",type=\"" << t << '"';
if (const ULONG64 addr = address())
str << ",addr=\"" << std::hex << std::showbase << addr << std::noshowbase << std::dec
<< '"';
bool valueEditable = true;
bool valueEnabled = true;
const bool uninitialized = m_flags & Uninitialized;
if (uninitialized) {
valueEditable = valueEnabled = false;
str << ",valueencoded=\"0\",value=\"<not in scope>\"";
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 {
ULONG obtainedSize = 0;
if (const wchar_t *wbuf = getValue(&obtainedSize)) {
const ULONG valueSize = obtainedSize - 1;
// ASCII or base64?
if (isSevenBitClean(wbuf, valueSize)) {
std::wstring value = wbuf;
fixValue(t, &value);
str << ",valueencoded=\"0\",value=\"" << gdbmiWStringFormat(value) << '"';
} else {
str << ",valueencoded=\"2\",value=\"";
base64Encode(str, reinterpret_cast<const unsigned char *>(wbuf), valueSize * sizeof(wchar_t));
str << '"';
}
delete [] wbuf;
}
str << ",valueencoded=\"2\",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());
@@ -587,39 +583,32 @@ void SymbolGroupNode::dump(std::ostream &str, unsigned child, unsigned depth,
str << ",valueenabled=\"" << (valueEnabled ? "true" : "false") << '"'
<< ",valueeditable=\"" << (valueEditable ? "true" : "false") << '"'
<< ",numchild=\"" << childCountGuess << '"';
if (!uninitialized && !m_children.empty()) {
str << ",children=[";
if (humanReadable)
str << '\n';
}
}
void SymbolGroupNode::dumpChildrenVisited(std::ostream &str, bool humanReadable) const
{
if (!m_children.empty())
str << ']';
str << '}';
if (humanReadable)
str << '\n';
}
bool SymbolGroupNode::accept(SymbolGroupNodeVisitor &visitor, unsigned child, unsigned depth) const
bool SymbolGroupNode::accept(SymbolGroupNodeVisitor &visitor, unsigned child, unsigned depth)
{
// If we happen to be the root node, just skip over
const bool invisibleRoot = m_index == DEBUG_ANY_ID;
const unsigned childDepth = invisibleRoot ? 0 : depth + 1;
if (!invisibleRoot) { // Visit us and move index forward.
if (visitor.visit(this, child, depth))
return true;
const SymbolGroupNodeVisitor::VisitResult vr =
invisibleRoot ? SymbolGroupNodeVisitor::VisitContinue :
visitor.visit(this, child, depth);
switch (vr) {
case SymbolGroupNodeVisitor::VisitStop:
return true;
case SymbolGroupNodeVisitor::VisitSkipChildren:
break;
case SymbolGroupNodeVisitor::VisitContinue: {
const unsigned childCount = unsigned(m_children.size());
for (unsigned c = 0; c < childCount; c++)
if (m_children.at(c)->accept(visitor, c, childDepth))
return true;
if (!invisibleRoot)
visitor.childrenVisited(this, depth);
}
break;
}
const unsigned childCount = unsigned(m_children.size());
for (unsigned c = 0; c < childCount; c++)
if (m_children.at(c)->accept(visitor, c, childDepth))
return true;
if (!invisibleRoot)
visitor.childrenVisited(this, depth);
return false;
}
@@ -630,13 +619,25 @@ void SymbolGroupNode::debug(std::ostream &str, unsigned verbosity, unsigned dept
if (const VectorIndexType childCount = m_children.size())
str << ", Children=" << childCount;
str << ' ' << m_parameters;
if (m_flags)
if (m_flags) {
str << " node-flags=" << m_flags;
if (m_flags & Uninitialized)
str << " UNINITIALIZED";
if (m_flags & DumperNotApplicable)
str << " DumperNotApplicable";
if (m_flags & DumperOk)
str << " DumperOk";
if (m_flags & DumperFailed)
str << " DumperFailed";
if (m_flags & ExpandedByDumper)
str << " ExpandedByDumper";
str << ' ';
}
if (verbosity) {
str << ",name=\"" << m_name << "\", Address=0x" << std::hex << address() << std::dec
<< " Type=\"" << type() << '"';
if (!(m_flags & Uninitialized))
str << "\" Value=\"" << gdbmiWStringFormat(rawValue()) << '"';
str << "\" Value=\"" << gdbmiWStringFormat(symbolGroupRawValue()) << '"';
}
str << '\n';
}
@@ -646,9 +647,12 @@ bool SymbolGroupNode::expand(std::string *errorMessage)
{
if (::debug > 1)
DebugPrint() << "SymbolGroupNode::expand " << m_name << ' ' << m_index;
if (!m_children.empty())
if (isExpanded()) {
// Clear the flag indication dumper expansion on a second, explicit request
clearFlags(ExpandedByDumper);
return true;
if (m_parameters.SubElements == 0) {
}
if (!canExpand()) {
*errorMessage = "No subelements to expand in node: " + fullIName();
return false;
}
@@ -684,10 +688,10 @@ static inline std::string msgNotFound(const std::string &nodeName)
return str.str();
}
std::string SymbolGroup::dump(bool humanReadable) const
std::string SymbolGroup::dump(const SymbolGroupValueContext &ctx, bool humanReadable) const
{
std::ostringstream str;
DumpSymbolGroupNodeVisitor visitor(str, humanReadable);
DumpSymbolGroupNodeVisitor visitor(str, ctx, humanReadable);
if (humanReadable)
str << '\n';
str << '[';
@@ -697,33 +701,43 @@ std::string SymbolGroup::dump(bool humanReadable) const
}
// Dump a node, potentially expand
std::string SymbolGroup::dump(const std::string &name, bool humanReadable, std::string *errorMessage)
std::string SymbolGroup::dump(const std::string &iname, const SymbolGroupValueContext &ctx, bool humanReadable, std::string *errorMessage)
{
SymbolGroupNode *const node = find(name);
SymbolGroupNode *const node = find(iname);
if (node == 0) {
*errorMessage = msgNotFound(name);
*errorMessage = msgNotFound(iname);
return std::string();
}
if (node->subElements() && node->children().empty()) {
if (!expand(name, errorMessage))
if (node->isExpanded()) { // Mark expand request by watch model
node->clearFlags(SymbolGroupNode::ExpandedByDumper);
} else {
if (node->canExpand() && !node->expand(errorMessage))
return false;
}
std::ostringstream str;
if (humanReadable)
str << '\n';
DumpSymbolGroupNodeVisitor visitor(str, humanReadable);
DumpSymbolGroupNodeVisitor visitor(str, ctx, humanReadable);
str << '[';
node->accept(visitor, 0, 0);
str << ']';
return str.str();
}
std::string SymbolGroup::debug(unsigned verbosity) const
std::string SymbolGroup::debug(const std::string &iname, unsigned verbosity) const
{
std::ostringstream str;
str << '\n';
DebugSymbolGroupNodeVisitor visitor(str, verbosity);
accept(visitor);
if (iname.empty()) {
accept(visitor);
} else {
if (SymbolGroupNode *const node = find(iname)) {
node->accept(visitor, 0, 0);
} else {
str << msgNotFound(iname);
}
}
return str.str();
}
@@ -807,7 +821,7 @@ void SymbolGroup::markUninitialized(const std::vector<std::string> &uniniNodes)
const SymbolGroupNodePtrVector::const_iterator childrenEnd = m_root->children().end();
for (SymbolGroupNodePtrVector::const_iterator it = m_root->children().begin(); it != childrenEnd; ++it) {
if (std::find(unIniNodesBegin, unIniNodesEnd, (*it)->fullIName()) != unIniNodesEnd)
(*it)->setFlags((*it)->flags() | SymbolGroupNode::Uninitialized);
(*it)->addFlags(SymbolGroupNode::Uninitialized);
}
}
}
@@ -907,27 +921,53 @@ DebugSymbolGroupNodeVisitor::DebugSymbolGroupNodeVisitor(std::ostream &os, unsig
{
}
bool DebugSymbolGroupNodeVisitor::visit(const SymbolGroupNode *node,
unsigned /* child */, unsigned depth)
SymbolGroupNodeVisitor::VisitResult
DebugSymbolGroupNodeVisitor::visit(SymbolGroupNode *node,
unsigned /* child */, unsigned depth)
{
node->debug(m_os, m_verbosity, depth);
return false;
return VisitContinue;
}
// --------------------- DumpSymbolGroupNodeVisitor
DumpSymbolGroupNodeVisitor::DumpSymbolGroupNodeVisitor(std::ostream &os,
const SymbolGroupValueContext &context,
bool humanReadable) :
m_os(os), m_humanReadable(humanReadable)
m_os(os), m_humanReadable(humanReadable),m_context(context), m_visitChildren(false)
{
}
bool DumpSymbolGroupNodeVisitor::visit(const SymbolGroupNode *node, unsigned child, unsigned depth)
SymbolGroupNodeVisitor::VisitResult
DumpSymbolGroupNodeVisitor::visit(SymbolGroupNode *node, unsigned child, unsigned depth)
{
node->dump(m_os, child, depth, m_humanReadable);
return false;
// Recurse to children if expanded by explicit watchmodel request
// and initialized.
const unsigned flags = node->flags();
m_visitChildren = node->isExpanded()
&& (flags & (SymbolGroupNode::Uninitialized|SymbolGroupNode::ExpandedByDumper)) == 0;
// 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) {
m_os << '\n';
indentStream(m_os, depth * 2);
}
m_os << '{';
node->dump(m_os, m_context);
if (m_visitChildren) { // open children array
m_os << ",children=[";
} else { // No children, close array.
m_os << '}';
}
if (m_humanReadable)
m_os << '\n';
return m_visitChildren ? VisitContinue : VisitSkipChildren;
}
void DumpSymbolGroupNodeVisitor::childrenVisited(const SymbolGroupNode *node, unsigned)
void DumpSymbolGroupNodeVisitor::childrenVisited(const SymbolGroupNode *, unsigned)
{
node->dumpChildrenVisited(m_os, m_humanReadable);
m_os << "]}"; // Close children array and self
if (m_humanReadable)
m_os << '\n';
}

View File

@@ -40,14 +40,27 @@ std::ostream &operator<<(std::ostream &, const DEBUG_SYMBOL_PARAMETERS&p);
class SymbolGroupNodeVisitor;
class SymbolGroup;
struct SymbolGroupValueContext;
// 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
// values should be displayed, still allowing for expansion of the structure
// in the debugger. Evaluating the dumpers might expand symbol nodes, which are
// then marked as 'ExpandedByDumper'. This stops the dump recursion to prevent
// outputting data that were not explicitly expanded by the watch handler.
// Thin wrapper around a symbol group entry.
class SymbolGroupNode {
SymbolGroupNode(const SymbolGroupNode&);
SymbolGroupNode& operator=(const SymbolGroupNode&);
public:
enum Flags {
Uninitialized = 0x1
Uninitialized = 0x1,
DumperNotApplicable = 0x2, // No dumper available for type
DumperOk = 0x4, // Internal dumper ran, value set
DumperFailed = 0x8, // Internal dumper failed
DumperMask = DumperNotApplicable|DumperOk|DumperFailed,
ExpandedByDumper = 0x10
};
typedef std::vector<DEBUG_SYMBOL_PARAMETERS> SymbolParameterVector;
typedef std::vector<SymbolGroupNode *> SymbolGroupNodePtrVector;
@@ -75,35 +88,39 @@ public:
const SymbolGroupNodePtrVector &children() const { return m_children; }
SymbolGroupNode *childAt(unsigned) const;
unsigned indexByIName(const char *) const; // (unsigned(-1) on failure
SymbolGroupNode *childByIName(const char *) const;
const SymbolGroupNode *parent() const { return m_parent; }
// I/O: Gdbmi dump for Visitors
void dump(std::ostream &str, unsigned child, unsigned depth,
bool humanReadable) const;
void dumpChildrenVisited(std::ostream &str, bool humanReadable) const;
void dump(std::ostream &str, const SymbolGroupValueContext &ctx);
// I/O: debug for Visitors
void debug(std::ostream &os, unsigned verbosity, unsigned depth) const;
std::wstring rawValue() const;
std::wstring fixedValue() const;
std::wstring symbolGroupRawValue() const;
std::wstring symbolGroupFixedValue() const;
std::wstring displayValue(const SymbolGroupValueContext &ctx);
std::string type() const;
ULONG64 address() const;
bool accept(SymbolGroupNodeVisitor &visitor, unsigned child, unsigned depth) const;
bool accept(SymbolGroupNodeVisitor &visitor, unsigned child, unsigned depth);
bool expand(std::string *errorMessage);
bool isExpanded() const { return !m_children.empty(); }
bool canExpand() const { return m_parameters.SubElements > 0; }
ULONG subElements() const { return m_parameters.SubElements; }
ULONG index() const { return m_index; }
unsigned flags() const { return m_flags; }
void setFlags(unsigned f) { m_flags = f; }
void addFlags(unsigned f) { m_flags |= f; }
void clearFlags(unsigned f) { m_flags &= ~f; }
private:
// Return allocated wide string array of value
wchar_t *getValue(ULONG *obtainedSize = 0) const;
bool isArrayElement() const;
// Notify about expansion of a node, shift indexes
bool notifyExpanded(ULONG index, ULONG insertedCount);
@@ -116,6 +133,7 @@ private:
const std::string m_name;
const std::string m_iname;
unsigned m_flags;
std::wstring m_dumperValue;
};
/* Visitor that takes care of iterating over the nodes
@@ -133,8 +151,15 @@ protected:
public:
virtual ~SymbolGroupNodeVisitor() {}
protected:
enum VisitResult {
VisitContinue,
VisitSkipChildren,
VisitStop
};
private:
virtual bool visit(const SymbolGroupNode *node, unsigned child, unsigned depth) = 0;
virtual VisitResult visit(SymbolGroupNode *node, unsigned child, unsigned depth) = 0;
// Helper for formatting output.
virtual void childrenVisited(const SymbolGroupNode * /* node */, unsigned /* depth */) {}
};
@@ -167,10 +192,11 @@ public:
~SymbolGroup();
// Dump all
std::string dump(bool humanReadable = false) const;
std::string dump(const SymbolGroupValueContext &ctx, bool humanReadable = false) const;
// Expand node and dump
std::string dump(const std::string &name, bool humanReadable, std::string *errorMessage);
std::string debug(unsigned verbosity = 0) const;
std::string dump(const std::string &iname, const SymbolGroupValueContext &ctx,
bool humanReadable, std::string *errorMessage);
std::string debug(const std::string &iname = std::string(), unsigned verbosity = 0) const;
unsigned frame() const { return m_frame; }
ULONG threadId() const { return m_threadId; }
@@ -221,7 +247,7 @@ public:
explicit DebugSymbolGroupNodeVisitor(std::ostream &os, unsigned verbosity = 0);
private:
virtual bool visit(const SymbolGroupNode *node, unsigned child, unsigned depth);
virtual VisitResult visit(SymbolGroupNode *node, unsigned child, unsigned depth);
std::ostream &m_os;
const unsigned m_verbosity;
@@ -230,14 +256,18 @@ private:
// Gdbmi dump output visitor.
class DumpSymbolGroupNodeVisitor : public SymbolGroupNodeVisitor {
public:
explicit DumpSymbolGroupNodeVisitor(std::ostream &os, bool humanReadable);
explicit DumpSymbolGroupNodeVisitor(std::ostream &os,
const SymbolGroupValueContext &context,
bool humanReadable);
private:
virtual bool visit(const SymbolGroupNode *node, unsigned child, unsigned depth);
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;
bool m_visitChildren;
};
#endif // SYMBOLGROUP_H

View File

@@ -31,15 +31,6 @@
#include "symbolgroup.h"
#include "stringutils.h"
SymbolGroupValueContext::SymbolGroupValueContext(CIDebugDataSpaces *ds)
: dataspaces(ds)
{
}
SymbolGroupValueContext::SymbolGroupValueContext() : dataspaces(0)
{
}
SymbolGroupValue::SymbolGroupValue(SymbolGroupNode *node,
const SymbolGroupValueContext &ctx) :
m_node(node), m_context(ctx)
@@ -56,9 +47,34 @@ bool SymbolGroupValue::isValid() const
return m_node != 0 && m_context.dataspaces != 0;
}
SymbolGroupValue SymbolGroupValue::operator[](unsigned index) const
{
if (ensureExpanded())
if (index < m_node->children().size())
return SymbolGroupValue(m_node->children().at(index), m_context);
return SymbolGroupValue();
}
bool SymbolGroupValue::ensureExpanded() const
{
if (!isValid() || !m_node->canExpand())
return false;
if (m_node->isExpanded())
return true;
// Set a flag indicating the node was expanded by SymbolGroupValue
// and not by an explicit request from the watch model.
if (m_node->expand(&m_errorMessage)) {
m_node->addFlags(SymbolGroupNode::ExpandedByDumper);
return true;
}
return false;
}
SymbolGroupValue SymbolGroupValue::operator[](const char *name) const
{
if (isValid() && m_node->expand(&m_errorMessage))
if (ensureExpanded())
if (SymbolGroupNode *child = m_node->childByIName(name))
return SymbolGroupValue(child, m_context);
return SymbolGroupValue();
@@ -71,7 +87,19 @@ std::string SymbolGroupValue::type() const
std::wstring SymbolGroupValue::value() const
{
return isValid() ? m_node->fixedValue() : std::wstring();
return isValid() ? m_node->symbolGroupFixedValue() : std::wstring();
}
double SymbolGroupValue::floatValue(double defaultValue) const
{
double f = defaultValue;
if (isValid()) {
std::wistringstream str(value());
str >> f;
if (str.fail())
f = defaultValue;
}
return f;
}
int SymbolGroupValue::intValue(int defaultValue) const
@@ -136,26 +164,138 @@ std::string SymbolGroupValue::error() const
return m_errorMessage;
}
static const char stdStringTypeC[] = "class std::basic_string<char,std::char_traits<char>,std::allocator<char> >";
static const char stdWStringTypeC[] = "class std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >";
// Dump a QString.
static bool dumpQString(const SymbolGroupValue &v, std::wstring *s)
static unsigned dumpQString(const std::string &type, const SymbolGroupValue &v, std::wstring *s)
{
if (endsWith(v.type(), "QString")) {
if (SymbolGroupValue d = v["d"]) {
if (SymbolGroupValue sizeValue = d["size"]) {
const int size = sizeValue.intValue();
if (size >= 0) {
*s = d["data"].wcharPointerData(size);
return true;
}
if (!endsWith(type, "QString")) // namespaced Qt?
return SymbolGroupNode::DumperNotApplicable;
if (SymbolGroupValue d = v["d"]) {
if (SymbolGroupValue sizeValue = d["size"]) {
const int size = sizeValue.intValue();
if (size >= 0) {
*s = d["data"].wcharPointerData(size);
return SymbolGroupNode::DumperOk;
}
}
}
return false;
return SymbolGroupNode::DumperFailed;
}
// Dump a QByteArray
static unsigned dumpQByteArray(const std::string &type, const SymbolGroupValue &v, std::wstring *s)
{
if (!endsWith(type, "QByteArray")) // namespaced Qt?
return SymbolGroupNode::DumperNotApplicable;
// TODO: More sophisticated dumping of binary data?
if (SymbolGroupValue data = v["d"]["data"]) {
*s = data.value();
return SymbolGroupNode::DumperOk;
}
return SymbolGroupNode::DumperFailed;
}
// Dump a rectangle in X11 syntax
template <class T>
inline void dumpRect(std::wostringstream &str, T x, T y, T width, T height)
{
str << width << 'x' << height;
if (x >= 0)
str << '+';
str << x;
if (y >= 0)
str << '+';
str << y;
}
template <class T>
inline void dumpRectPoints(std::wostringstream &str, T x1, T y1, T x2, T y2)
{
dumpRect(str, x1, y1, (x2 - x1), (y2 - y1));
}
// Dump Qt's simple geometrical types
static unsigned dumpQtGeometryTypes(const std::string &type, const SymbolGroupValue &v, std::wstring *s)
{
if (endsWith(type, "QSize") || endsWith(type, "QSizeF")) { // namespaced Qt?
std::wostringstream str;
str << '(' << v["wd"].value() << ", " << v["ht"].value() << ')';
*s = str.str();
return SymbolGroupNode::DumperOk;
}
if (endsWith(type, "QPoint") || endsWith(type, "QPointF")) { // namespaced Qt?
std::wostringstream str;
str << '(' << v["xp"].value() << ", " << v["yp"].value() << ')';
*s = str.str();
return SymbolGroupNode::DumperOk;
}
if (endsWith(type, "QLine") || endsWith(type, "QLineF")) { // namespaced Qt?
const SymbolGroupValue p1 = v["pt1"];
const SymbolGroupValue p2 = v["pt2"];
if (p1 && p2) {
std::wostringstream str;
str << '(' << p1["xp"].value() << ", " << p1["yp"].value() << ") ("
<< p2["xp"].value() << ", " << p2["yp"].value() << ')';
*s = str.str();
return SymbolGroupNode::DumperOk;
}
return SymbolGroupNode::DumperFailed;
}
if (endsWith(type, "QRect")) {
std::wostringstream str;
dumpRectPoints(str, v["x1"].intValue(), v["y1"].intValue(), v["x2"].intValue(), v["y2"].intValue());
*s = str.str();
return SymbolGroupNode::DumperOk;
}
if (endsWith(type, "QRectF")) {
std::wostringstream str;
dumpRect(str, v["xp"].floatValue(), v["yp"].floatValue(), v["w"].floatValue(), v["h"].floatValue());
*s = str.str();
return SymbolGroupNode::DumperOk;
}
return SymbolGroupNode::DumperNotApplicable;
}
// Dump a std::string.
static unsigned dumpStdString(const std::string &type, const SymbolGroupValue &v, std::wstring *s)
{
if (type != stdStringTypeC && type != stdWStringTypeC)
return SymbolGroupNode::DumperNotApplicable;
// MSVC 2010: Access Bx/_Buf in base class
SymbolGroupValue buf = v[unsigned(0)]["_Bx"]["_Buf"];
if (!buf) // MSVC2008: Bx/Buf are members
buf = v["_Bx"]["_Buf"];
if (buf) {
*s = buf.value();
return SymbolGroupNode::DumperOk;
}
return SymbolGroupNode::DumperFailed;
}
// Dump builtin simple types using SymbolGroupValue expressions.
bool dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, std::wstring *s)
unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, std::wstring *s)
{
// Check for class types and strip pointer types (references appear as pointers as well)
std::string type = n->type();
if (type.compare(0, 6, "class ") != 0)
return SymbolGroupNode::DumperNotApplicable;
if (endsWith(type, " *"))
type.erase(type.size() - 2, 2);
const SymbolGroupValue v(n, ctx);
return dumpQString(v, s);
unsigned rc = dumpQString(type, v, s);
if (rc != SymbolGroupNode::DumperNotApplicable)
return rc;
rc = dumpQByteArray(type, v, s);
if (rc != SymbolGroupNode::DumperNotApplicable)
return rc;
rc = dumpStdString(type, v, s);
if (rc != SymbolGroupNode::DumperNotApplicable)
return rc;
rc = dumpQtGeometryTypes(type, v, s);
if (rc != SymbolGroupNode::DumperNotApplicable)
return rc;
return rc;
}

View File

@@ -39,8 +39,8 @@ class SymbolGroupNode;
// Structure to pass all IDebug interfaces used for SymbolGroupValue
struct SymbolGroupValueContext
{
SymbolGroupValueContext(CIDebugDataSpaces *ds);
SymbolGroupValueContext();
SymbolGroupValueContext(CIDebugDataSpaces *ds) : dataspaces(ds) {}
SymbolGroupValueContext::SymbolGroupValueContext() : dataspaces(0) {}
CIDebugDataSpaces *dataspaces;
};
@@ -58,11 +58,14 @@ public:
operator bool() const { return isValid(); }
bool isValid() const;
// Access children by name or index (0-based)
SymbolGroupValue operator[](const char *name) const;
SymbolGroupValue operator[](unsigned) const;
std::string type() const;
std::wstring value() const;
int intValue(int defaultValue = -1) const;
double floatValue(double defaultValue = -999) const;
ULONG64 pointerValue(ULONG64 defaultValue = 0) const;
// Return allocated array of data pointed to
unsigned char *pointerData(unsigned length) const;
@@ -72,12 +75,15 @@ public:
std::string error() const;
private:
bool ensureExpanded() const;
SymbolGroupNode *m_node;
SymbolGroupValueContext m_context;
mutable std::string m_errorMessage;
};
// Dump builtin simple types using SymbolGroupValue expressions.
bool dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, std::wstring *s);
// Dump builtin simple types using SymbolGroupValue expressions,
// returning SymbolGroupNode dumper flags.
unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, std::wstring *s);
#endif // SYMBOLGROUPVALUE_H

View File

@@ -33,9 +33,17 @@
#define _USE_MATH_DEFINES
#include <math.h>
#include <QDebug>
#include <QRect>
#include <QRectF>
#include <QLine>
#include <QLineF>
#include <QPoint>
#include <QPointF>
#include <QSize>
#include <QSizeF>
#include <QThread>
#include <string>
#include <list>
#include <set>
#include <QLibrary>
#include <QLibraryInfo>
@@ -78,7 +86,7 @@ void MainWindow::simpleBP(int inc, const QString &inx)
{
int array[2] = {1,2};
m_w++;
QString x = "h\"allo";
QString x = QLatin1String("h\344all\366");
QString *xp = &x;
qDebug() << inc << inx << *xp;
Q_UNUSED(array)
@@ -379,3 +387,20 @@ void Foo::MainWindow::on_actionStdTypes_triggered()
std::vector<std::string> stringVector(1, "bla");
std::vector<std::wstring> wStringVector(1, L"bla");
}
void Foo::MainWindow::on_actionVariousQtTypes_triggered()
{
const QByteArray ba = "hallo\t";
QSize size = QSize(42, 43);
QSizeF sizeF(size);
QPoint p1 = QPoint(42, 43);
QPoint p2 = QPoint(100, 100);
QLine line(p1, p2);
QPointF p1f(p1);
QPointF p2f(p2);
QLineF linef(p1f, p2f);
QRect rect(p1, p2);
QRectF rectf(rect);
qDebug() << sizeF << linef << rectf;
}

View File

@@ -71,6 +71,8 @@ private slots:
void on_actionStdTypes_triggered();
void on_actionVariousQtTypes_triggered();
private:
void terminateThread();
int m_w;

View File

@@ -20,7 +20,7 @@
<x>0</x>
<y>0</y>
<width>600</width>
<height>27</height>
<height>26</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@@ -47,6 +47,7 @@
<addaction name="actionScopes"/>
<addaction name="actionLongString"/>
<addaction name="actionStdTypes"/>
<addaction name="actionVariousQtTypes"/>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<widget class="QToolBar" name="toolBar">
@@ -157,6 +158,11 @@
<string>stdTypes</string>
</property>
</action>
<action name="actionVariousQtTypes">
<property name="text">
<string>variousQtTypes</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>