summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>2010-11-23 13:36:39 +0100
committerFriedemann Kleint <Friedemann.Kleint@nokia.com>2010-11-23 13:36:39 +0100
commit191b7e0b0055c7781be4c729536e7f7ba5c723f7 (patch)
tree18cc65b40cf3fa24893b13d8601f25bd10c8d290 /src
parent40548df8f8b12ec7b4145a268872cf1ceb41e698 (diff)
downloadqt-creator-191b7e0b0055c7781be4c729536e7f7ba5c723f7.tar.gz
Debugger[new CDB]: Work on locals.
Add optional code model scope checking. Remove need to call to 'expandlocals' command by giving 'locals' options for expanded and uninitialized variables, saving one roundtrip. Handle shadowed variables and __formal parameters. Differentiate between name and iname in SymbolGroup.
Diffstat (limited to 'src')
-rw-r--r--src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp37
-rw-r--r--src/libs/qtcreatorcdbext/symbolgroup.cpp179
-rw-r--r--src/libs/qtcreatorcdbext/symbolgroup.h13
-rw-r--r--src/plugins/debugger/cdb2/bytearrayinputstream.cpp11
-rw-r--r--src/plugins/debugger/cdb2/bytearrayinputstream.h3
-rw-r--r--src/plugins/debugger/cdb2/cdbengine2.cpp61
-rw-r--r--src/plugins/debugger/watchutils.cpp75
7 files changed, 280 insertions, 99 deletions
diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
index 387d386c6a..a46ecd075b 100644
--- a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
+++ b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
@@ -134,7 +134,11 @@ extern "C" HRESULT CALLBACK expandlocals(CIDebugClient *client, PCSTR args)
static inline std::string msgLocalsUsage(PCSTR args)
{
std::ostringstream str;
- str << "Invalid parameter: '" << args << "' (usage: locals [-d] <frame> [iname]).";
+ str << "Invalid parameter: '" << args
+ << "'\nUsage: locals [-t token] [-h] [-d] [-e expandset] [-u uninitializedset] <frame> [iname]).\n"
+ "-h human-readable ouput\n"
+ "-d debug output\n-e expandset Comma-separated list of expanded inames\n"
+ "-u uninitializedset Comma-separated list of uninitialized inames\n";
return str.str();
}
@@ -150,18 +154,38 @@ static std::string commmandLocals(ExtensionCommandContext &exc,PCSTR args, int *
std::string iname;
StringList tokens = commandTokens<StringList>(args, token);
+ StringVector expandedInames;
+ StringVector uninitializedInames;
+ // Parse away options
while (!tokens.empty() && tokens.front().size() == 2 && tokens.front().at(0) == '-') {
- // Parse options -d (debug)/- humanreadable GDBMI
- switch (tokens.front().at(1)) {
+ const char option = tokens.front().at(1);
+ tokens.pop_front();
+ switch (option) {
case 'd':
debugOutput++;
break;
case 'h':
humanReadableGdbmi = true;
break;
+ case 'u':
+ if (tokens.empty()) {
+ *errorMessage = msgLocalsUsage(args);
+ return std::string();
+ }
+ split(tokens.front(), ',', std::back_inserter(uninitializedInames));
+ tokens.pop_front();
+ break;
+ case 'e':
+ if (tokens.empty()) {
+ *errorMessage = msgLocalsUsage(args);
+ return std::string();
+ }
+ split(tokens.front(), ',', std::back_inserter(expandedInames));
+ tokens.pop_front();
+ break;
}
- tokens.pop_front();
}
+ // Frame and iname
unsigned frame;
if (tokens.empty() || sscanf(tokens.front().c_str(), "%u", &frame) != 1) {
*errorMessage = msgLocalsUsage(args);
@@ -175,7 +199,10 @@ static std::string commmandLocals(ExtensionCommandContext &exc,PCSTR args, int *
SymbolGroup * const symGroup = ExtensionContext::instance().symbolGroup(exc.symbols(), exc.threadId(), frame, errorMessage);
if (!symGroup)
return std::string();
-
+ if (!expandedInames.empty())
+ symGroup->expandList(expandedInames, errorMessage);
+ if (!uninitializedInames.empty())
+ symGroup->markUninitialized(uninitializedInames);
// Complete dump
if (iname.empty())
return debugOutput ? symGroup->debug(debugOutput - 1) : symGroup->dump(humanReadableGdbmi);
diff --git a/src/libs/qtcreatorcdbext/symbolgroup.cpp b/src/libs/qtcreatorcdbext/symbolgroup.cpp
index ba33d804d8..f08a629276 100644
--- a/src/libs/qtcreatorcdbext/symbolgroup.cpp
+++ b/src/libs/qtcreatorcdbext/symbolgroup.cpp
@@ -40,6 +40,7 @@
enum { debug = 0 };
typedef std::vector<int>::size_type VectorIndexType;
+typedef std::vector<std::string> StringVector;
const char rootNameC[] = "local";
@@ -207,9 +208,10 @@ SymbolGroup *SymbolGroup::create(CIDebugControl *control, CIDebugSymbols *debugS
// ------- SymbolGroupNode
SymbolGroupNode::SymbolGroupNode(CIDebugSymbolGroup *symbolGroup,
- const std::string &n,
+ const std::string &name,
+ const std::string &iname,
SymbolGroupNode *parent) :
- m_symbolGroup(symbolGroup), m_parent(parent), m_name(n)
+ m_symbolGroup(symbolGroup), m_parent(parent), m_name(name), m_iname(iname), m_flags(0)
{
memset(&m_parameters, 0, sizeof(DEBUG_SYMBOL_PARAMETERS));
m_parameters.ParentSymbol = DEBUG_ANY_ID;
@@ -230,23 +232,6 @@ bool SymbolGroupNode::isArrayElement() const
return m_parent && (m_parent->m_parameters.Flags & DEBUG_SYMBOL_IS_ARRAY);
}
-// iName: Fix array elements to be named 'array.0' instead of 'array.[0]' so
-// that sorting in Qt Creator works.
-std::string SymbolGroupNode::iName() const
-{
- std::string rc = m_name;
-
- //rc += isArrayElement() ? 'a' : 'n';
- if (isArrayElement() && !rc.empty() && rc.at(0) == '[') {
- const std::string::size_type last = rc.size() - 1;
- if (rc.at(last) == ']') {
- rc.erase(last, 1);
- rc.erase(0, 1);
- }
- }
- return rc;
-}
-
// Return full iname as 'locals.this.m_sth'.
std::string SymbolGroupNode::fullIName() const
{
@@ -258,6 +243,58 @@ std::string SymbolGroupNode::fullIName() const
return rc;
}
+// Fix an array iname "[0]" -> "0" for sorting to work correctly
+static inline void fixArrayIname(std::string *iname)
+{
+ if (!iname->empty() && iname->at(0) == '[') {
+ const std::string::size_type last = iname->size() - 1;
+ if (iname->at(last) == ']') {
+ iname->erase(last, 1);
+ iname->erase(0, 1);
+ }
+ }
+}
+
+// Fix up names and inames
+static inline void fixNames(bool isTopLevel, StringVector *names, StringVector *inames)
+{
+ if (names->empty())
+ return;
+ unsigned unnamedId = 1;
+ /* 1) Fix name="__formal", which occurs when someone writes "void foo(int /* x * /)..."
+ * 2) Fix array inames for sorting: "[6]" -> name="[6]",iname="6"
+ * 3) For toplevels: Fix shadowed variables in the order the debugger expects them:
+ \code
+ int x; // Occurrence (1), should be reported as name="x <shadowed 1>"/iname="x#1"
+ if (true) {
+ int x = 5; (2) // Occurrence (2), should be reported as name="x"/iname="x"
+ }
+ \endcode */
+ StringVector::iterator nameIt = names->begin();
+ const StringVector::iterator namesEnd = names->end();
+ for (StringVector::iterator iNameIt = inames->begin(); nameIt != namesEnd ; ++nameIt, ++iNameIt) {
+ std::string &name = *nameIt;
+ std::string &iname = *iNameIt;
+ if (name.empty() || name == "__formal") {
+ const std::string number = toString(unnamedId++);
+ name = "<unnamed " + number + '>';
+ iname = "unnamed#" + number;
+ } else {
+ fixArrayIname(&iname);
+ }
+ if (isTopLevel) {
+ if (const StringVector::size_type shadowCount = std::count(nameIt + 1, namesEnd, name)) {
+ const std::string number = toString(shadowCount);
+ name += " <shadowed ";
+ name += number;
+ name += '>';
+ iname += '#';
+ iname += number;
+ }
+ }
+ }
+}
+
// Index: Index of symbol, parameterOffset: Looking only at a part of the symbol array, offset
void SymbolGroupNode::parseParameters(VectorIndexType index,
VectorIndexType parameterOffset,
@@ -279,15 +316,31 @@ void SymbolGroupNode::parseParameters(VectorIndexType index,
const VectorIndexType size = vec.size();
// Scan the top level elements
+ StringVector names;
+ names.reserve(size);
+ // Pass 1) Determine names. We need the complete set first in order to do some corrections.
const VectorIndexType startIndex = isTopLevel ? 0 : index + 1;
for (VectorIndexType pos = startIndex - parameterOffset; pos < size ; pos++ ) {
if (vec.at(pos).ParentSymbol == index) {
const VectorIndexType symbolGroupIndex = pos + parameterOffset;
- HRESULT hr = m_symbolGroup->GetSymbolName(ULONG(symbolGroupIndex), buf, BufSize, &obtainedSize);
- const std::string name = SUCCEEDED(hr) ? std::string(buf) : std::string("unnamed");
- SymbolGroupNode *child = new SymbolGroupNode(m_symbolGroup, name, this);
+ if (FAILED(m_symbolGroup->GetSymbolName(ULONG(symbolGroupIndex), buf, BufSize, &obtainedSize)))
+ buf[0] = '\0';
+ names.push_back(std::string(buf));
+ }
+ }
+ // 2) Fix names
+ StringVector inames = names;
+ fixNames(isTopLevel, &names, &inames);
+ // Pass 3): Add nodes with fixed names
+ StringVector::size_type nameIndex = 0;
+ for (VectorIndexType pos = startIndex - parameterOffset; pos < size ; pos++ ) {
+ if (vec.at(pos).ParentSymbol == index) {
+ const VectorIndexType symbolGroupIndex = pos + parameterOffset;
+ SymbolGroupNode *child = new SymbolGroupNode(m_symbolGroup, names.at(nameIndex),
+ inames.at(nameIndex), this);
child->parseParameters(symbolGroupIndex, parameterOffset, vec);
m_children.push_back(child);
+ nameIndex++;
}
}
if (isTopLevel)
@@ -296,7 +349,7 @@ void SymbolGroupNode::parseParameters(VectorIndexType index,
SymbolGroupNode *SymbolGroupNode::create(CIDebugSymbolGroup *sg, const std::string &name, const SymbolGroup::SymbolParameterVector &vec)
{
- SymbolGroupNode *rc = new SymbolGroupNode(sg, name);
+ SymbolGroupNode *rc = new SymbolGroupNode(sg, name, name);
rc->parseParameters(DEBUG_ANY_ID, 0, vec);
return rc;
}
@@ -436,28 +489,40 @@ void SymbolGroupNode::dump(std::ostream &str, unsigned child, unsigned depth,
str << ",addr=\"" << std::hex << std::showbase << addr << std::noshowbase << std::dec
<< '"';
- ULONG obtainedSize = 0;
- if (const wchar_t *wbuf = getValue(index, &obtainedSize)) {
- const ULONG valueSize = obtainedSize - 1;
- // ASCII or base64?
- if (isSevenBitClean(wbuf, valueSize)) {
- std::wstring value = wbuf;
- fixValue(type, &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 << '"';
+ bool valueEditable = true;
+ bool valueEnabled = true;
+
+ const bool uninitialized = m_flags & Uninitialized;
+ if (uninitialized) {
+ valueEditable = valueEnabled = false;
+ str << ",valueencoded=\"0\",value=\"<not in scope>\"";
+ } else {
+ ULONG obtainedSize = 0;
+ if (const wchar_t *wbuf = getValue(index, &obtainedSize)) {
+ const ULONG valueSize = obtainedSize - 1;
+ // ASCII or base64?
+ if (isSevenBitClean(wbuf, valueSize)) {
+ std::wstring value = wbuf;
+ fixValue(type, &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;
}
- delete [] wbuf;
}
// Children: Dump all known or subelements (guess).
- const VectorIndexType childCountGuess = m_children.empty() ? m_parameters.SubElements : m_children.size();
+ const VectorIndexType childCountGuess = uninitialized ? 0 :
+ (m_children.empty() ? m_parameters.SubElements : m_children.size());
// No children..suppose we are editable and enabled
- if (childCountGuess == 0)
- str << ",valueenabled=\"true\",valueeditable=\"true\"";
- str << ",numchild=\"" << childCountGuess << '"';
- if (!m_children.empty()) {
+ if (childCountGuess != 0)
+ valueEditable = false;
+ str << ",valueenabled=\"" << (valueEnabled ? "true" : "false") << '"'
+ << ",valueeditable=\"" << (valueEditable ? "true" : "false") << '"'
+ << ",numchild=\"" << childCountGuess << '"';
+ if (!uninitialized && !m_children.empty()) {
str << ",children=[";
if (humanReadable)
str << '\n';
@@ -501,9 +566,14 @@ bool SymbolGroupNode::accept(SymbolGroupNodeVisitor &visitor, unsigned child, un
void SymbolGroupNode::debug(std::ostream &str, unsigned verbosity, unsigned depth, ULONG index) const
{
indentStream(str, depth);
- str << '"' << m_name << "\" Children=" << m_children.size() << ' ' << m_parameters;
- if (verbosity)
- str << " Address=0x" << std::hex << address(index) << std::dec << " Type=\"" << getType(index) << "\" Value=\"" << gdbmiWStringFormat(rawValue(index)) << '"';
+ str << '"' << m_name << "\" Children=" << m_children.size() << ' ' << m_parameters
+ << " flags=" << m_flags;
+ if (verbosity) {
+ str << " Address=0x" << std::hex << address(index) << std::dec
+ << " Type=\"" << getType(index) << '"';
+ if (!(m_flags & Uninitialized))
+ str << "\" Value=\"" << gdbmiWStringFormat(rawValue(index)) << '"';
+ }
str << '\n';
}
@@ -531,6 +601,10 @@ bool SymbolGroupNode::expand(ULONG index, std::string *errorMessage)
*errorMessage = "No subelements to expand in node: " + fullIName();
return false;
}
+ if (m_flags & Uninitialized) {
+ *errorMessage = "Refusing to expand uninitialized node: " + fullIName();
+ return false;
+ }
const HRESULT hr = m_symbolGroup->ExpandSymbol(index, TRUE);
@@ -626,7 +700,7 @@ unsigned SymbolGroup::expandList(const std::vector<std::string> &nodes, std::str
{
if (nodes.empty())
return 0;
- // Create a set with a key <level, name>. Also required for 1 node.
+ // Create a set with a key <level, name>. Also required for 1 node (see above).
InamePathEntrySet pathEntries;
const VectorIndexType nodeCount = nodes.size();
for (VectorIndexType i= 0; i < nodeCount; i++) {
@@ -670,6 +744,21 @@ bool SymbolGroup::expand(const std::string &nodeName, std::string *errorMessage)
return node->expand(index, errorMessage);
}
+// Mark uninitialized (top level only)
+void SymbolGroup::markUninitialized(const std::vector<std::string> &uniniNodes)
+{
+ if (m_root && !m_root->children().empty() && !uniniNodes.empty()) {
+ const std::vector<std::string>::const_iterator unIniNodesBegin = uniniNodes.begin();
+ const std::vector<std::string>::const_iterator unIniNodesEnd = uniniNodes.end();
+
+ 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);
+ }
+ }
+}
+
static inline std::string msgAssignError(const std::string &nodeName,
const std::string &value,
const std::string &why)
diff --git a/src/libs/qtcreatorcdbext/symbolgroup.h b/src/libs/qtcreatorcdbext/symbolgroup.h
index de9843ea3d..ae88e6b034 100644
--- a/src/libs/qtcreatorcdbext/symbolgroup.h
+++ b/src/libs/qtcreatorcdbext/symbolgroup.h
@@ -45,6 +45,9 @@ class SymbolGroupNode {
SymbolGroupNode(const SymbolGroupNode&);
SymbolGroupNode& operator=(const SymbolGroupNode&);
public:
+ enum Flags {
+ Uninitialized = 0x1
+ };
typedef std::vector<DEBUG_SYMBOL_PARAMETERS> SymbolParameterVector;
typedef std::vector<SymbolGroupNode *> SymbolGroupNodePtrVector;
typedef SymbolGroupNodePtrVector::iterator SymbolGroupNodePtrVectorIterator;
@@ -52,6 +55,7 @@ public:
explicit SymbolGroupNode(CIDebugSymbolGroup *symbolGroup,
const std::string &name,
+ const std::string &iname,
SymbolGroupNode *parent = 0);
~SymbolGroupNode() { removeChildren(); }
@@ -65,7 +69,7 @@ public:
const std::string &name() const { return m_name; }
std::string fullIName() const;
- std::string iName() const;
+ const std::string &iName() const { return m_iname; }
const SymbolGroupNodePtrVector &children() const { return m_children; }
SymbolGroupNode *childAt(unsigned) const;
@@ -91,6 +95,9 @@ public:
ULONG subElements() const { return m_parameters.SubElements; }
+ unsigned flags() const { return m_flags; }
+ void setFlags(unsigned f) { m_flags = f; }
+
private:
// Return allocated wide string array of value
wchar_t *getValue(ULONG index, ULONG *obtainedSize = 0) const;
@@ -102,6 +109,8 @@ private:
DEBUG_SYMBOL_PARAMETERS m_parameters; // Careful when using ParentSymbol. It might not be correct.
SymbolGroupNodePtrVector m_children;
const std::string m_name;
+ const std::string m_iname;
+ unsigned m_flags;
};
/* Visitor that takes care of iterating over the nodes and the index bookkeeping.
@@ -165,6 +174,8 @@ public:
// Expand a node list "locals.i1,locals.i2", expanding all nested child nodes
// (think mkdir -p).
unsigned expandList(const std::vector<std::string> &nodes, std::string *errorMessage);
+ // Mark uninitialized (top level only)
+ void markUninitialized(const std::vector<std::string> &nodes);
// Expand a single node "locals.A.B" requiring that "locals.A.B" is already visible
// (think mkdir without -p).
diff --git a/src/plugins/debugger/cdb2/bytearrayinputstream.cpp b/src/plugins/debugger/cdb2/bytearrayinputstream.cpp
index 5c916cdd90..a1b1d40a6c 100644
--- a/src/plugins/debugger/cdb2/bytearrayinputstream.cpp
+++ b/src/plugins/debugger/cdb2/bytearrayinputstream.cpp
@@ -37,6 +37,12 @@ ByteArrayInputStream::ByteArrayInputStream(QByteArray &ba) :
{
}
+void ByteArrayInputStream::appendSeparator(char c)
+{
+ if (!m_target.isEmpty() && !m_target.endsWith(c))
+ m_target.append(c);
+}
+
void hexPrefixOn(ByteArrayInputStream &bs)
{
bs.setHexPrefix(true);
@@ -57,6 +63,11 @@ void dec(ByteArrayInputStream &bs)
bs.setIntegerBase(10);
}
+void blankSeparator(ByteArrayInputStream &bs)
+{
+ bs.appendSeparator();
+}
+
QByteArray trimFront(QByteArray in)
{
if (in.isEmpty())
diff --git a/src/plugins/debugger/cdb2/bytearrayinputstream.h b/src/plugins/debugger/cdb2/bytearrayinputstream.h
index a10962698c..d9b8258adc 100644
--- a/src/plugins/debugger/cdb2/bytearrayinputstream.h
+++ b/src/plugins/debugger/cdb2/bytearrayinputstream.h
@@ -61,6 +61,8 @@ public:
bool hexPrefix() const { return m_hexPrefix; }
void setIntegerBase(int b) { m_integerBase = b; }
int integerBase() const { return m_integerBase; }
+ // Append a separator if required (target does not end with it)
+ void appendSeparator(char c = ' ');
private:
template <class IntType> void appendInt(IntType i);
@@ -93,6 +95,7 @@ void hexPrefixOn(ByteArrayInputStream &bs);
void hexPrefixOff(ByteArrayInputStream &bs);
void hex(ByteArrayInputStream &bs);
void dec(ByteArrayInputStream &bs);
+void blankSeparator(ByteArrayInputStream &bs);
// Bytearray parse helpers
QByteArray trimFront(QByteArray in);
diff --git a/src/plugins/debugger/cdb2/cdbengine2.cpp b/src/plugins/debugger/cdb2/cdbengine2.cpp
index f89383bf36..5452548d05 100644
--- a/src/plugins/debugger/cdb2/cdbengine2.cpp
+++ b/src/plugins/debugger/cdb2/cdbengine2.cpp
@@ -61,6 +61,7 @@
#include <QtCore/QDebug>
#include <QtCore/QTextStream>
#include <QtCore/QDateTime>
+#include <QtGui/QToolTip>
#ifdef Q_OS_WIN
# include <utils/winutils.h>
@@ -73,6 +74,7 @@ Q_DECLARE_METATYPE(Debugger::Internal::DisassemblerViewAgent*)
Q_DECLARE_METATYPE(Debugger::Internal::MemoryViewAgent*)
enum { debug = 0 };
+enum { debugLocals = 0 };
enum { debugBreakpoints = 0 };
#if 0
@@ -107,6 +109,8 @@ enum { debugBreakpoints = 0 };
namespace Debugger {
namespace Cdb {
+static const char localsPrefixC[] = "local.";
+
using namespace Debugger::Internal;
struct MemoryViewCookie {
@@ -346,10 +350,11 @@ void CdbEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEd
// No numerical or any other expressions [yet]
if (!(exp.at(0).isLetter() || exp.at(0) == QLatin1Char('_')))
return;
- const QByteArray iname = QByteArray("local.") + exp.toAscii();
- const QModelIndex index = watchHandler()->itemIndex(iname);
- Q_UNUSED(index)
- Q_UNUSED(mousePos)
+ const QByteArray iname = QByteArray(localsPrefixC) + exp.toAscii();
+ if (const WatchData *data = watchHandler()->findItem(iname)) {
+ QToolTip::hideText();
+ QToolTip::showText(mousePos, data->toToolTip());
+ }
}
void CdbEngine::setupEngine()
@@ -903,8 +908,6 @@ void CdbEngine::postExtensionCommand(const QByteArray &cmd,
showMessage(msg, LogError);
return;
}
- if (!flags & QuietCommand)
- showMessage(QString::fromLocal8Bit(cmd), LogInput);
const int token = m_nextCommandToken++;
@@ -915,6 +918,9 @@ void CdbEngine::postExtensionCommand(const QByteArray &cmd,
if (!arguments.isEmpty())
str << ' ' << arguments;
+ if (!flags & QuietCommand)
+ showMessage(QString::fromLocal8Bit(fullCmd), LogInput);
+
CdbExtensionCommandPtr pendingCommand(new CdbExtensionCommand(fullCmd, token, flags, handler, nextCommandFlag, cookie));
m_extensionCommandQueue.push_back(pendingCommand);
@@ -934,9 +940,10 @@ void CdbEngine::activateFrame(int index)
const Debugger::Internal::StackFrames &frames = stackHandler()->frames();
QTC_ASSERT(index < frames.size(), return; )
- if (debug)
+ const StackFrame frame = frames.at(index);
+ if (debug || debugLocals)
qDebug("activateFrame idx=%d '%s' %d", index,
- qPrintable(frames.at(index).file), frames.at(index).line);
+ qPrintable(frame.file), frame.line);
stackHandler()->setCurrentIndex(index);
const bool showAssembler = !frames.at(index).isUsable();
if (showAssembler) { // Assembly code: Clean out model and force instruction mode.
@@ -944,30 +951,46 @@ void CdbEngine::activateFrame(int index)
watchHandler()->endCycle();
QAction *assemblerAction = theAssemblerAction();
if (assemblerAction->isChecked()) {
- gotoLocation(frames.at(index), true);
+ gotoLocation(frame, true);
} else {
assemblerAction->trigger(); // Seems to trigger update
}
return;
}
- gotoLocation(frames.at(index), true);
- // Watchers: Initial expand and query
+ gotoLocation(frame, true);
+ // Watchers: Initial expand, get uninitialized and query
+ QByteArray arguments;
+ ByteArrayInputStream str(arguments);
+ // Pre-expand
const QSet<QByteArray> expanded = watchHandler()->expandedINames();
if (!expanded.isEmpty()) {
- QByteArray expandArguments;
- ByteArrayInputStream expandStr(expandArguments);
- expandStr << index << ' ';
+ str << blankSeparator << "-e ";
int i = 0;
foreach(const QByteArray &e, expanded) {
if (i++)
- expandStr << ',';
- expandStr << e;
+ str << ',';
+ str << e;
}
- postExtensionCommand("expandlocals", expandArguments, 0, &CdbEngine::handleExpandLocals);
}
-
+ // Uninitialized variables if desired
+ if (debuggerCore()->boolSetting(UseCodeModel)) {
+ QStringList uninitializedVariables;
+ getUninitializedVariables(debuggerCore()->cppCodeModelSnapshot(),
+ frame.function, frame.file, frame.line, &uninitializedVariables);
+ if (!uninitializedVariables.isEmpty()) {
+ str << blankSeparator << "-u ";
+ int i = 0;
+ foreach(const QString &u, uninitializedVariables) {
+ if (i++)
+ str << ',';
+ str << localsPrefixC << u;
+ }
+ }
+ }
+ // Required arguments: frame
+ str << blankSeparator << index;
watchHandler()->beginCycle();
- postExtensionCommand("locals", QByteArray::number(index), 0, &CdbEngine::handleLocals);
+ postExtensionCommand("locals", arguments, 0, &CdbEngine::handleLocals);
}
void CdbEngine::selectThread(int index)
diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp
index 90251b2a79..a21af15c46 100644
--- a/src/plugins/debugger/watchutils.cpp
+++ b/src/plugins/debugger/watchutils.cpp
@@ -1409,9 +1409,16 @@ static bool gdbMiGetBoolValue(bool *target,
struct GdbMiRecursionContext
{
- GdbMiRecursionContext(int recursionLevelIn = 0) :
- recursionLevel(recursionLevelIn), childNumChild(-1), childIndex(0) {}
+ enum Type
+ {
+ Debugger, // Debugger symbol dump, recursive/symmetrical
+ GdbMacrosCpp // old gdbmacros.cpp format, unsymmetrical
+ };
+ GdbMiRecursionContext(Type t, int recursionLevelIn = 0) :
+ type(t), recursionLevel(recursionLevelIn), childNumChild(-1), childIndex(0) {}
+
+ const Type type;
int recursionLevel;
int childNumChild;
int childIndex;
@@ -1429,31 +1436,41 @@ static void gbdMiToWatchData(const GdbMi &root,
QString v;
QByteArray b;
// Check for name/iname and use as expression default
- if (ctx.recursionLevel == 0) {
- // parents have only iname, from which name is derived
- QString iname;
- if (!gdbMiGetStringValue(&iname, root, "iname"))
- qWarning("Internal error: iname missing");
- w.iname = iname.toLatin1();
- w.name = iname;
- const int lastDotPos = w.name.lastIndexOf(QLatin1Char('.'));
- if (lastDotPos != -1)
- w.name.remove(0, lastDotPos + 1);
- w.exp = w.name.toLatin1();
+ w.sortId = ctx.childIndex;
+ // Fully symmetrical
+ if (ctx.type == GdbMiRecursionContext::Debugger) {
+ gdbMiGetByteArrayValue(&w.iname, root, "iname");
+ gdbMiGetStringValue(&w.name, root, "name");
+ gdbMiGetByteArrayValue(&w.exp, root, "exp");
} else {
- // Children can have a 'name' attribute. If missing, assume array index
- // For display purposes, it can be overridden by "key"
- if (!gdbMiGetStringValue(&w.name, root, "name")) {
- w.name = QString::number(ctx.childIndex);
- }
- // Set iname
- w.iname = ctx.parentIName;
- w.iname += '.';
- w.iname += w.name.toLatin1();
- // Key?
- QString key;
- if (gdbMiGetStringValue(&key, root, "key", "keyencoded")) {
- w.name = key.size() > 13 ? key.mid(0, 13) + QLatin1String("...") : key;
+ // gdbmacros.cpp: iname/name present according to recursion level
+ // Check for name/iname and use as expression default
+ if (ctx.recursionLevel == 0) {
+ // parents have only iname, from which name is derived
+ QString iname;
+ if (!gdbMiGetStringValue(&iname, root, "iname"))
+ qWarning("Internal error: iname missing");
+ w.iname = iname.toLatin1();
+ w.name = iname;
+ const int lastDotPos = w.name.lastIndexOf(QLatin1Char('.'));
+ if (lastDotPos != -1)
+ w.name.remove(0, lastDotPos + 1);
+ w.exp = w.name.toLatin1();
+ } else {
+ // Children can have a 'name' attribute. If missing, assume array index
+ // For display purposes, it can be overridden by "key"
+ if (!gdbMiGetStringValue(&w.name, root, "name")) {
+ w.name = QString::number(ctx.childIndex);
+ }
+ // Set iname
+ w.iname = ctx.parentIName;
+ w.iname += '.';
+ w.iname += w.name.toLatin1();
+ // Key?
+ QString key;
+ if (gdbMiGetStringValue(&key, root, "key", "keyencoded")) {
+ w.name = key.size() > 13 ? key.mid(0, 13) + QLatin1String("...") : key;
+ }
}
}
if (w.name.isEmpty()) {
@@ -1507,7 +1524,7 @@ static void gbdMiToWatchData(const GdbMi &root,
if (children.empty())
return;
wl->back().setChildrenUnneeded();
- GdbMiRecursionContext nextLevelContext(ctx.recursionLevel + 1);
+ GdbMiRecursionContext nextLevelContext(ctx.type, ctx.recursionLevel + 1);
nextLevelContext.parentIName = w.iname;
gdbMiGetStringValue(&nextLevelContext.childType, root, "childtype");
if (!gdbMiGetIntValue(&nextLevelContext.childNumChild, root, "childnumchild"))
@@ -1528,12 +1545,12 @@ bool QtDumperHelper::parseValue(const char *data, QList<WatchData> *l)
if (!root.isValid())
return false;
foreach(const GdbMi &child, root.children())
- gbdMiToWatchData(child, GdbMiRecursionContext(), l);
+ gbdMiToWatchData(child, GdbMiRecursionContext(GdbMiRecursionContext::Debugger), l);
} else {
root.fromStringMultiple(QByteArray(data));
if (!root.isValid())
return false;
- gbdMiToWatchData(root, GdbMiRecursionContext(), l);
+ gbdMiToWatchData(root, GdbMiRecursionContext(GdbMiRecursionContext::GdbMacrosCpp), l);
}
return true;
}