diff options
author | Friedemann Kleint <Friedemann.Kleint@digia.com> | 2012-12-21 11:11:15 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@digia.com> | 2012-12-21 15:41:39 +0100 |
commit | 5f04706a88fb6915228f7c937ad8a1bc0169aad6 (patch) | |
tree | de91c127d652a5ad5b0466ae26270cc122398ebb | |
parent | d1d4b7c21b4cc8c2acea98010df8677cf2f8cd16 (diff) | |
download | qt-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.cpp | 2 | ||||
-rw-r--r-- | src/libs/qtcreatorcdbext/stringutils.cpp | 37 | ||||
-rw-r--r-- | src/libs/qtcreatorcdbext/stringutils.h | 32 | ||||
-rw-r--r-- | src/libs/qtcreatorcdbext/symbolgroupnode.cpp | 31 | ||||
-rw-r--r-- | src/libs/qtcreatorcdbext/symbolgroupnode.h | 6 | ||||
-rw-r--r-- | src/libs/qtcreatorcdbext/symbolgroupvalue.cpp | 75 | ||||
-rw-r--r-- | src/libs/qtcreatorcdbext/symbolgroupvalue.h | 7 | ||||
-rw-r--r-- | src/plugins/debugger/cdb/cdbengine.cpp | 7 | ||||
-rw-r--r-- | src/plugins/debugger/watchutils.h | 2 |
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, |