summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@digia.com>2012-12-21 11:11:15 +0100
committerFriedemann Kleint <Friedemann.Kleint@digia.com>2012-12-21 15:41:39 +0100
commit5f04706a88fb6915228f7c937ad8a1bc0169aad6 (patch)
treede91c127d652a5ad5b0466ae26270cc122398ebb
parentd1d4b7c21b4cc8c2acea98010df8677cf2f8cd16 (diff)
downloadqt-creator-5f04706a88fb6915228f7c937ad8a1bc0169aad6.tar.gz
Implement basics for edit value handling in CDB.
- Add routine for formatting edit values. - Optionally store memory in SymbolGroupNode (along with special info) to be able to re-use it for edit values using a simple convenience class MemoryHandle. - Prototypically implement QString and QByteArray / Qt 5. Task-number: QTCREATORBUG-8344 Change-Id: I6d2cac7a1e9ac48e94335142c41dc1bfb984c515 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
-rw-r--r--src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp2
-rw-r--r--src/libs/qtcreatorcdbext/stringutils.cpp37
-rw-r--r--src/libs/qtcreatorcdbext/stringutils.h32
-rw-r--r--src/libs/qtcreatorcdbext/symbolgroupnode.cpp31
-rw-r--r--src/libs/qtcreatorcdbext/symbolgroupnode.h6
-rw-r--r--src/libs/qtcreatorcdbext/symbolgroupvalue.cpp75
-rw-r--r--src/libs/qtcreatorcdbext/symbolgroupvalue.h7
-rw-r--r--src/plugins/debugger/cdb/cdbengine.cpp7
-rw-r--r--src/plugins/debugger/watchutils.h2
9 files changed, 179 insertions, 20 deletions
diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
index d6fa621407..58d27ca3a6 100644
--- a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
+++ b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
@@ -275,7 +275,7 @@ extern "C" HRESULT CALLBACK pid(CIDebugClient *client, PCSTR args)
int token;
commandTokens<StringList>(args, &token);
- dprintf("Qt Creator CDB extension version 2.6.1 (Qt 5 support) %d bit built %s.\n",
+ dprintf("Qt Creator CDB extension version 2.7 (Qt 5 support) %d bit built %s.\n",
sizeof(void *) * 8, __DATE__);
if (const ULONG pid = currentProcessId(client)) {
ExtensionContext::instance().report('R', token, 0, "pid", "%u", pid);
diff --git a/src/libs/qtcreatorcdbext/stringutils.cpp b/src/libs/qtcreatorcdbext/stringutils.cpp
index 5f0cff7a6b..a3d094b4c8 100644
--- a/src/libs/qtcreatorcdbext/stringutils.cpp
+++ b/src/libs/qtcreatorcdbext/stringutils.cpp
@@ -27,6 +27,10 @@
**
****************************************************************************/
+#ifndef _SCL_SECURE_NO_WARNINGS // silence std::string::copy
+# define _SCL_SECURE_NO_WARNINGS
+#endif
+
#include "stringutils.h"
#include <cctype>
@@ -285,12 +289,29 @@ void decodeHex(const char *p, const char *end, unsigned char *target)
}
}
-std::wstring dataToHexW(const unsigned char *p, const unsigned char *end)
+MemoryHandle *MemoryHandle::fromStdString(const std::string &s)
+{
+ const size_t size = s.size();
+ unsigned char *data = new unsigned char[size];
+ s.copy(reinterpret_cast<char *>(data), size);
+ return new MemoryHandle(data, size);
+}
+
+MemoryHandle *MemoryHandle::fromStdWString(const std::wstring &ws)
+{
+ const size_t size = ws.size();
+ wchar_t *data = new wchar_t[size];
+ ws.copy(data, size);
+ return new MemoryHandle(data, size);
+}
+
+template <class String>
+inline String dataToHexHelper(const unsigned char *p, const unsigned char *end)
{
if (p == end)
- return std::wstring();
+ return String();
- std::wstring rc;
+ String rc;
rc.reserve(2 * (end - p));
for ( ; p < end ; ++p) {
const unsigned c = *p;
@@ -300,6 +321,16 @@ std::wstring dataToHexW(const unsigned char *p, const unsigned char *end)
return rc;
}
+std::wstring dataToHexW(const unsigned char *p, const unsigned char *end)
+{
+ return dataToHexHelper<std::wstring>(p, end);
+}
+
+std::string dataToHex(const unsigned char *p, const unsigned char *end)
+{
+ return dataToHexHelper<std::string>(p, end);
+}
+
// Readable hex: '0xAA 0xBB'..
std::wstring dataToReadableHexW(const unsigned char *begin, const unsigned char *end)
{
diff --git a/src/libs/qtcreatorcdbext/stringutils.h b/src/libs/qtcreatorcdbext/stringutils.h
index 27965d8f0c..798fe435b6 100644
--- a/src/libs/qtcreatorcdbext/stringutils.h
+++ b/src/libs/qtcreatorcdbext/stringutils.h
@@ -188,9 +188,41 @@ std::string stringFromHex(const char *begin, const char *end);
void decodeHex(const char *begin, const char *end, unsigned char *target);
std::wstring dataToHexW(const unsigned char *begin, const unsigned char *end);
+std::string dataToHex(const unsigned char *begin, const unsigned char *end);
// Create readable hex: '0xAA 0xBB'..
std::wstring dataToReadableHexW(const unsigned char *begin, const unsigned char *end);
+// Flat memory handle to pass allocated memory around.
+class MemoryHandle {
+ MemoryHandle(const MemoryHandle &);
+ MemoryHandle& operator=(const MemoryHandle &);
+
+public:
+ explicit MemoryHandle(const unsigned char *memory, size_t size) : m_size(size), m_memory(memory) {}
+ explicit MemoryHandle(const wchar_t *wcharData, size_t size) :
+ m_size(size * sizeof(wchar_t)),
+ m_memory(reinterpret_cast<const unsigned char *>(wcharData)) {}
+
+ static MemoryHandle* fromStdString(const std::string &s);
+ static MemoryHandle* fromStdWString(const std::wstring &s);
+
+ ~MemoryHandle() { delete [] m_memory; }
+
+ size_t size() const { return m_size; }
+ const unsigned char *data() const { return m_memory; }
+ const unsigned char *begin() const { return m_memory; }
+ const unsigned char *end() const { return m_memory + m_size; }
+
+ std::string dump(bool wantQuotes) const { return dumpMemory(begin(), m_size, wantQuotes); }
+ std::wstring toHexW() const { return dataToHexW(begin(), end()); }
+ std::string toHex() const { return dataToHex(begin(), end()); }
+ std::wstring toReadableHexW() const { return dataToReadableHexW(begin(), end()); }
+
+private:
+ const size_t m_size;
+ const unsigned char *m_memory;
+};
+
// Format a map as a GDBMI hash {key="value",..}
void formatGdbmiHash(std::ostream &os, const std::map<std::string, std::string> &, bool closeHash = true);
diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp
index 88b8422386..4ce1a421ab 100644
--- a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp
+++ b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp
@@ -327,7 +327,12 @@ int DumpParameters::format(const std::string &type, const std::string &iname) co
return iit->second;
}
if (!typeFormats.empty()) {
- const FormatMap::const_iterator tit = typeFormats.find(type);
+ // Strip 'struct' / 'class' prefixes and pointer types
+ // when called with a raw cdb types.
+ std::string stripped = SymbolGroupValue::stripClassPrefixes(type);
+ if (stripped != type)
+ stripped = SymbolGroupValue::stripPointerType(stripped);
+ const FormatMap::const_iterator tit = typeFormats.find(stripped);
if (tit != typeFormats.end())
return tit->second;
}
@@ -589,15 +594,25 @@ SymbolGroupNode::SymbolGroupNode(SymbolGroup *symbolGroup,
ULONG index,
const std::string &module,
const std::string &name,
- const std::string &iname) :
- BaseSymbolGroupNode(name, iname),
- m_symbolGroup(symbolGroup),
- m_module(module), m_index(index), m_dumperType(-1), m_dumperContainerSize(-1), m_dumperSpecialInfo(0)
+ const std::string &iname)
+ : BaseSymbolGroupNode(name, iname)
+ , m_symbolGroup(symbolGroup)
+ , m_module(module)
+ , m_index(index)
+ , m_dumperType(-1)
+ , m_dumperContainerSize(-1)
+ , m_dumperSpecialInfo(0)
+ , m_memory(0)
{
memset(&m_parameters, 0, sizeof(DEBUG_SYMBOL_PARAMETERS));
m_parameters.ParentSymbol = DEBUG_ANY_ID;
}
+SymbolGroupNode::~SymbolGroupNode()
+{
+ delete m_memory;
+}
+
const SymbolGroupNode *SymbolGroupNode::symbolGroupNodeParent() const
{
if (const AbstractSymbolGroupNode *p = parent())
@@ -1004,7 +1019,8 @@ bool SymbolGroupNode::runSimpleDumpers(const SymbolGroupValueContext &ctx)
if (testFlags(SimpleDumperMask))
return false;
addFlags(dumpSimpleType(this , ctx, &m_dumperValue,
- &m_dumperType, &m_dumperContainerSize, &m_dumperSpecialInfo));
+ &m_dumperType, &m_dumperContainerSize,
+ &m_dumperSpecialInfo, &m_memory));
if (symbolGroupDebug)
DebugPrint() << "<SymbolGroupNode::runSimpleDumpers " << name() << " '"
<< wStringToString(m_dumperValue) << "' Type="
@@ -1105,6 +1121,9 @@ int SymbolGroupNode::dumpNode(std::ostream &str,
base64Encode(str, reinterpret_cast<const unsigned char *>(value.c_str()), value.size() * sizeof(wchar_t));
str << '"';
}
+ const int format = dumpParameters.format(t, aFullIName);
+ if (format > 0)
+ dumpEditValue(this, ctx, format, str);
}
// Children: Dump all known non-obscured or subelements
unsigned childCountGuess = 0;
diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.h b/src/libs/qtcreatorcdbext/symbolgroupnode.h
index 802e057abc..7604403a44 100644
--- a/src/libs/qtcreatorcdbext/symbolgroupnode.h
+++ b/src/libs/qtcreatorcdbext/symbolgroupnode.h
@@ -45,6 +45,7 @@ class SymbolGroupNodeVisitor;
class SymbolGroup;
struct SymbolGroupValueContext;
class SymbolGroupNode;
+class MemoryHandle;
// Helper struct used for check results when recoding CDB char pointer output.
struct DumpParameterRecodeResult
@@ -214,6 +215,8 @@ public:
WatchNode = 0x100
};
+ ~SymbolGroupNode();
+
typedef std::vector<DEBUG_SYMBOL_PARAMETERS> SymbolParameterVector;
void parseParameters(SymbolParameterVector::size_type index,
@@ -268,6 +271,8 @@ public:
ULONG subElements() const { return m_parameters.SubElements; }
ULONG index() const { return m_index; }
+ MemoryHandle *memory() const { return m_memory; }
+
virtual SymbolGroupNode *asSymbolGroupNode() { return this; }
virtual const SymbolGroupNode *asSymbolGroupNode() const { return this; }
@@ -296,6 +301,7 @@ private:
int m_dumperType;
int m_dumperContainerSize;
void *m_dumperSpecialInfo; // Opaque information passed from simple to complex dumpers
+ MemoryHandle *m_memory; // Memory shared between simple dumper and edit value.
};
class ReferenceSymbolGroupNode : public AbstractSymbolGroupNode
diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
index cccd4dcd52..95c3f8780f 100644
--- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
+++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
@@ -1546,7 +1546,8 @@ bool readQt5StringData(const SymbolGroupValue &dV, int qtMajorVersion,
return true;
}
-static inline bool dumpQString(const SymbolGroupValue &v, std::wostream &str)
+static inline bool dumpQString(const SymbolGroupValue &v, std::wostream &str,
+ MemoryHandle **memoryHandle = 0)
{
const QtInfo &qtInfo = QtInfo::get(v.context());
const SymbolGroupValue dV = v["d"];
@@ -1557,7 +1558,10 @@ static inline bool dumpQString(const SymbolGroupValue &v, std::wostream &str)
if (const SymbolGroupValue sizeValue = dV["size"]) {
const int size = sizeValue.intValue();
if (size >= 0) {
- str << L'"' << dV["data"].wcharPointerData(size) << L'"';
+ const std::wstring stringData = dV["data"].wcharPointerData(size);
+ str << L'"' << stringData << L'"';
+ if (memoryHandle)
+ *memoryHandle = MemoryHandle::fromStdWString(stringData);
return true;
}
}
@@ -1581,7 +1585,11 @@ static inline bool dumpQString(const SymbolGroupValue &v, std::wostream &str)
} else {
str << L"\"\"";
}
- delete [] memory;
+ if (memoryHandle) {
+ *memoryHandle = new MemoryHandle(memory, size);
+ } else {
+ delete [] memory;
+ }
return true;
}
@@ -1634,7 +1642,8 @@ static unsigned qAtomicIntSize(const SymbolGroupValueContext &ctx)
}
// Dump a QByteArray
-static inline bool dumpQByteArray(const SymbolGroupValue &v, std::wostream &str)
+static inline bool dumpQByteArray(const SymbolGroupValue &v, std::wostream &str,
+ MemoryHandle **memoryHandle = 0)
{
const QtInfo &qtInfo = QtInfo::get(v.context());
const SymbolGroupValue dV = v["d"];
@@ -1682,7 +1691,11 @@ static inline bool dumpQByteArray(const SymbolGroupValue &v, std::wostream &str)
} else {
str << L"<empty>";
}
- delete [] memory;
+ if (memoryHandle) {
+ *memoryHandle = new MemoryHandle(reinterpret_cast<unsigned char *>(memory), size);
+ } else {
+ delete [] memory;
+ }
return true;
}
@@ -2441,7 +2454,8 @@ static inline bool dumpQSharedPointer(const SymbolGroupValue &v, std::wostream &
unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx,
std::wstring *s, int *knownTypeIn /* = 0 */,
int *containerSizeIn /* = 0 */,
- void **specialInfoIn /* = 0 */)
+ void **specialInfoIn /* = 0 */,
+ MemoryHandle **memoryHandleIn /* = 0 */)
{
QTC_TRACE_IN
if (containerSizeIn)
@@ -2491,7 +2505,7 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx,
rc = dumpQChar(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QByteArray:
- rc = dumpQByteArray(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
+ rc = dumpQByteArray(v, str, memoryHandleIn) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QFileInfo:
rc = dumpQFileInfo(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
@@ -2518,7 +2532,7 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx,
rc = dumpQScriptValue(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QString:
- rc = dumpQString(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
+ rc = dumpQString(v, str, memoryHandleIn) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
break;
case KT_QColor:
rc = dumpQColor(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
@@ -2594,6 +2608,51 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx,
return rc;
}
+static inline void formatEditValue(int displayFormat, const MemoryHandle *mh, std::ostream &str)
+{
+ str << "editformat=\"" << displayFormat << "\",editvalue=\""
+ << mh->toHex() << "\",";
+}
+
+bool dumpEditValue(const SymbolGroupNode *n, const SymbolGroupValueContext &,
+ int desiredFormat, std::ostream &str)
+{
+ // Keep in sync watchhandler.cpp/showEditValue(), dumper.py.
+ enum DebuggerEditFormats {
+ DisplayImageData = 1,
+ DisplayUtf16String = 2,
+ DisplayImageFile = 3,
+ DisplayProcess = 4,
+ DisplayLatin1String = 5,
+ DisplayUtf8String = 6
+ };
+
+ enum Formats {
+ NormalFormat = 0,
+ StringSeparateWindow = 1 // corresponds to menu index.
+ };
+
+ if (desiredFormat <= 0)
+ return true;
+
+ if (SymbolGroupValue::verbose)
+ DebugPrint() << __FUNCTION__ << ' ' << n->name() << '/' << desiredFormat;
+
+ switch (n->dumperType()) {
+ case KT_QString:
+ if (desiredFormat == StringSeparateWindow)
+ if (const MemoryHandle *mh = n->memory())
+ formatEditValue(DisplayUtf16String, mh, str);
+ break;
+ case KT_QByteArray:
+ if (desiredFormat == StringSeparateWindow)
+ if (const MemoryHandle *mh = n->memory())
+ formatEditValue(DisplayLatin1String, mh, str);
+ break;
+ }
+ return true;
+}
+
// Dump of QByteArray: Display as an array of unsigned chars.
static inline std::vector<AbstractSymbolGroupNode *>
complexDumpQByteArray(SymbolGroupNode *n, const SymbolGroupValueContext &ctx)
diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.h b/src/libs/qtcreatorcdbext/symbolgroupvalue.h
index 18cb418e29..9568f11116 100644
--- a/src/libs/qtcreatorcdbext/symbolgroupvalue.h
+++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.h
@@ -40,6 +40,7 @@
class AbstractSymbolGroupNode;
class SymbolGroupNode;
class SymbolGroup;
+class MemoryHandle;
struct SymbolGroupValueContext
{
@@ -248,7 +249,11 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx,
std::wstring *s,
int *knownType = 0,
int *containerSizeIn = 0,
- void **specialInfoIn = 0);
+ void **specialInfoIn = 0,
+ MemoryHandle **memoryHandleIn = 0);
+
+bool dumpEditValue(const SymbolGroupNode *n, const SymbolGroupValueContext &,
+ int desiredFormat, std::ostream &str);
enum AssignEncoding
{
diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp
index 5bcd493109..1277390162 100644
--- a/src/plugins/debugger/cdb/cdbengine.cpp
+++ b/src/plugins/debugger/cdb/cdbengine.cpp
@@ -625,6 +625,13 @@ void CdbEngine::setupEngine()
STATE_DEBUG(state(), Q_FUNC_INFO, __LINE__, "notifyEngineSetupFailed")
notifyEngineSetupFailed();
}
+ const QStringList stringFormats = QStringList()
+ << tr("Normal") << tr("Separate Window");
+ WatchHandler *wh = watchHandler();
+ wh->addTypeFormats("QString", stringFormats);
+ wh->addTypeFormats("QString *", stringFormats);
+ wh->addTypeFormats("QByteArray", stringFormats);
+ wh->addTypeFormats("QByteArray *", stringFormats);
}
bool CdbEngine::launchCDB(const DebuggerStartParameters &sp, QString *errorMessage)
diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h
index 29d93fef07..5e0f2a4d8f 100644
--- a/src/plugins/debugger/watchutils.h
+++ b/src/plugins/debugger/watchutils.h
@@ -83,7 +83,7 @@ enum DebuggerEncoding
Hex2EncodedFloat8 = 26
};
-// Keep in sync with dumper.py
+// Keep in sync with dumper.py, symbolgroupvalue.cpp of CDB
enum DebuggerDisplay {
StopDisplay = 0,
DisplayImageData = 1,