From 581765055d6bdb9959c48bcc2ddd2cc249cfd011 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 17 May 2011 12:19:24 +0200 Subject: [PATCH] Debugger [CDB]: Enable Assignment to string classes. Assign to QString/QByteArray following gdbmacros.py implementation (call resize if required, copy data into buffer). Assign to std::[w]string only it has sufficient memory (since std::string<>.resize cannot be called). --- src/libs/qtcreatorcdbext/knowntype.h | 9 +- .../qtcreatorcdbext/qtcreatorcdbextension.cpp | 33 +- src/libs/qtcreatorcdbext/stringutils.cpp | 9 + src/libs/qtcreatorcdbext/stringutils.h | 3 + src/libs/qtcreatorcdbext/symbolgroup.cpp | 27 +- src/libs/qtcreatorcdbext/symbolgroup.h | 2 + src/libs/qtcreatorcdbext/symbolgroupnode.cpp | 30 +- src/libs/qtcreatorcdbext/symbolgroupnode.h | 7 + src/libs/qtcreatorcdbext/symbolgroupvalue.cpp | 296 +++++++++++++++++- src/libs/qtcreatorcdbext/symbolgroupvalue.h | 15 + src/plugins/debugger/cdb/cdbengine.cpp | 31 +- 11 files changed, 429 insertions(+), 33 deletions(-) diff --git a/src/libs/qtcreatorcdbext/knowntype.h b/src/libs/qtcreatorcdbext/knowntype.h index 07f34b827fc..67574be6eb2 100644 --- a/src/libs/qtcreatorcdbext/knowntype.h +++ b/src/libs/qtcreatorcdbext/knowntype.h @@ -46,6 +46,7 @@ enum KnownType KT_ContainerType = 0x200000, KT_HasSimpleDumper = 0x400000, KT_HasComplexDumper = 0x800000, // Non-container complex dumper + KT_Editable = 0x1000000, // Editable complex type // Types: PODs KT_Char = KT_POD_Type + 1, KT_UnsignedChar = KT_POD_Type + 2, @@ -56,8 +57,8 @@ enum KnownType KT_PointerType = KT_POD_Type + 7, // pointer to class or complex type // Types: Qt Basic KT_QChar = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 1, - KT_QByteArray = KT_Qt_Type + KT_Qt_MovableType + KT_HasComplexDumper + KT_HasSimpleDumper + 2, - KT_QString = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 3, + KT_QByteArray = KT_Qt_Type + KT_Editable + KT_Qt_MovableType + KT_HasComplexDumper + KT_HasSimpleDumper + 2, + KT_QString = KT_Qt_Type + KT_Editable + KT_Qt_MovableType + KT_HasSimpleDumper + 3, KT_QColor = KT_Qt_Type + KT_HasSimpleDumper + 4, KT_QFlags = KT_Qt_Type + KT_HasSimpleDumper + 5, KT_QDate = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 6, @@ -163,8 +164,8 @@ enum KnownType KT_QMap = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 10, KT_QMultiMap = KT_Qt_Type + KT_ContainerType + KT_HasSimpleDumper + 11, // Types: STL - KT_StdString = KT_STL_Type + KT_HasSimpleDumper + 1, - KT_StdWString = KT_STL_Type + KT_HasSimpleDumper + 2, + KT_StdString = KT_STL_Type + KT_Editable + KT_HasSimpleDumper + 1, + KT_StdWString = KT_STL_Type + KT_Editable + KT_HasSimpleDumper + 2, // Types: STL containers KT_StdVector = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 1, KT_StdList = KT_STL_Type + KT_ContainerType + KT_HasSimpleDumper + 2, diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp index e19c52a0211..67a834bed41 100644 --- a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp +++ b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp @@ -157,7 +157,10 @@ static const CommandDescription commandDescriptions[] = { {"addsymbol","Adds a symbol to symbol group (testing command).", "[-t token] [optional-iname]"}, {"assign","Assigns a value to a variable in current symbol group.", - "[-t token] "}, + "[-t token] [-h] \n" + "-h Data are hex-encoded, binary data\n" + "-u Data are hex-encoded, UTF16 data" +}, {"threads","Lists threads in GDBMI format.","[-t token]"}, {"registers","Lists registers in GDBMI format","[-t token]"}, {"modules","Lists modules in GDBMI format.","[-t token]"}, @@ -775,12 +778,30 @@ extern "C" HRESULT CALLBACK assign(CIDebugClient *client, PCSTR argsIn) std::string errorMessage; bool success = false; - + AssignEncoding enc = AssignPlainValue; int token = 0; do { - const StringList tokens = commandTokens(argsIn, &token); + StringList tokens = commandTokens(argsIn, &token); + if (tokens.empty()) { + errorMessage = singleLineUsage(commandDescriptions[CmdAssign]); + break; + } + + if (tokens.front() == "-h") { + enc = AssignHexEncoded; + tokens.pop_front(); + } else if (tokens.front() == "-u") { + enc = AssignHexEncodedUtf16; + tokens.pop_front(); + } + + if (tokens.empty()) { + errorMessage = singleLineUsage(commandDescriptions[CmdAssign]); + break; + } + // Parse 'assign locals.x=5' - const std::string::size_type equalsPos = tokens.size() == 1 ? tokens.front().find('=') : std::string::npos; + const std::string::size_type equalsPos = tokens.front().find('='); if (equalsPos == std::string::npos) { errorMessage = singleLineUsage(commandDescriptions[CmdAssign]); break; @@ -796,7 +817,9 @@ extern "C" HRESULT CALLBACK assign(CIDebugClient *client, PCSTR argsIn) SymbolGroup *symGroup = ExtensionContext::instance().symbolGroup(exc.symbols(), exc.threadId(), currentFrame, &errorMessage); if (!symGroup) break; - success = symGroup->assign(iname, value, &errorMessage); + success = symGroup->assign(iname, enc, value, + SymbolGroupValueContext(exc.dataSpaces(), exc.symbols()), + &errorMessage); } while (false); if (success) { diff --git a/src/libs/qtcreatorcdbext/stringutils.cpp b/src/libs/qtcreatorcdbext/stringutils.cpp index 844773ee257..dddfe3614bb 100644 --- a/src/libs/qtcreatorcdbext/stringutils.cpp +++ b/src/libs/qtcreatorcdbext/stringutils.cpp @@ -222,6 +222,15 @@ std::string stringFromHex(const char *p, const char *end) return rc; } +void decodeHex(const char *p, const char *end, unsigned char *target) +{ + for ( ; p < end; p++) { + unsigned c = 16 * hexDigit(*p); + c += hexDigit(*++p); + *target++ = c; + } +} + std::wstring dataToHexW(const unsigned char *p, const unsigned char *end) { if (p == end) diff --git a/src/libs/qtcreatorcdbext/stringutils.h b/src/libs/qtcreatorcdbext/stringutils.h index 8349235a7c0..5bc5f52b7be 100644 --- a/src/libs/qtcreatorcdbext/stringutils.h +++ b/src/libs/qtcreatorcdbext/stringutils.h @@ -180,6 +180,9 @@ std::wstring stringToWString(const std::string &w); // String from hex "414A" -> "AJ". std::string stringFromHex(const char *begin, const char *end); +// Decode hex to a memory area. +void decodeHex(const char *begin, const char *end, unsigned char *target); + std::wstring dataToHexW(const unsigned char *begin, const unsigned char *end); // Create readable hex: '0xAA 0xBB'.. std::wstring dataToReadableHexW(const unsigned char *begin, const unsigned char *end); diff --git a/src/libs/qtcreatorcdbext/symbolgroup.cpp b/src/libs/qtcreatorcdbext/symbolgroup.cpp index b23d0b5f733..6d2a0a6bf6c 100644 --- a/src/libs/qtcreatorcdbext/symbolgroup.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroup.cpp @@ -441,35 +441,26 @@ void SymbolGroup::markUninitialized(const std::vector &uniniNodes) } } -static inline std::string msgAssignError(const std::string &nodeName, - const std::string &value, - const std::string &why) -{ - std::ostringstream str; - str << "Unable to assign '" << value << "' to '" << nodeName << "': " << why; - return str.str(); -} - -bool SymbolGroup::assign(const std::string &nodeName, const std::string &value, +bool SymbolGroup::assign(const std::string &nodeName, + int valueEncoding, + const std::string &value, + const SymbolGroupValueContext &ctx, std::string *errorMessage) { AbstractSymbolGroupNode *aNode = find(nodeName); if (aNode == 0) { - *errorMessage = msgAssignError(nodeName, value, "No such node"); + *errorMessage = SymbolGroupNode::msgAssignError(nodeName, value, "No such node"); return false; } SymbolGroupNode *node = aNode->resolveReference()->asSymbolGroupNode(); if (node == 0) { - *errorMessage = msgAssignError(nodeName, value, "Invalid node type"); + *errorMessage = SymbolGroupNode::msgAssignError(nodeName, value, "Invalid node type"); return false; } - const HRESULT hr = m_symbolGroup->WriteSymbol(node->index(), const_cast(value.c_str())); - if (FAILED(hr)) { - *errorMessage = msgAssignError(nodeName, value, msgDebugEngineComFailed("WriteSymbol", hr)); - return false; - } - return true; + return (node->dumperType() & KT_Editable) ? // Edit complex types + assignType(node, valueEncoding, value, ctx, errorMessage) : + node->assign(value, errorMessage); } bool SymbolGroup::accept(SymbolGroupNodeVisitor &visitor) const diff --git a/src/libs/qtcreatorcdbext/symbolgroup.h b/src/libs/qtcreatorcdbext/symbolgroup.h index bdb125130d3..b2b9fc1c742 100644 --- a/src/libs/qtcreatorcdbext/symbolgroup.h +++ b/src/libs/qtcreatorcdbext/symbolgroup.h @@ -103,7 +103,9 @@ public: // Assign a value by iname bool assign(const std::string &node, + int valueEncoding, const std::string &value, + const SymbolGroupValueContext &ctx, std::string *errorMessage); CIDebugSymbolGroup *debugSymbolGroup() const { return m_symbolGroup; } diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp index f76ef984166..f5f6edad87b 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp @@ -1021,9 +1021,13 @@ int SymbolGroupNode::dumpNode(std::ostream &str, } } } - // No children..suppose we are editable and enabled - if (childCountGuess != 0 || (m_parameters.Flags & DEBUG_SYMBOL_READ_ONLY) != 0) + // No children..suppose we are editable and enabled. + if (m_parameters.Flags & DEBUG_SYMBOL_READ_ONLY) { valueEditable = false; + } else { + if (childCountGuess != 0 && !(m_dumperType & KT_Editable)) + valueEditable = false; + } str << ",valueenabled=\"" << (valueEnabled ? "true" : "false") << '"' << ",valueeditable=\"" << (valueEditable ? "true" : "false") << '"'; return childCountGuess; @@ -1265,6 +1269,28 @@ SymbolGroupNode *SymbolGroupNode::addSymbolByName(const std::string &module, return node; } +std::string SymbolGroupNode::msgAssignError(const std::string &nodeName, + const std::string &value, + const std::string &why) +{ + std::ostringstream str; + str << "Unable to assign '" << value << "' to '" << nodeName << "': " << why; + return str.str(); +} + +// Simple type +bool SymbolGroupNode::assign(const std::string &value, std::string *errorMessage /* = 0 */) +{ + const HRESULT hr = + m_symbolGroup->debugSymbolGroup()->WriteSymbol(m_index, const_cast(value.c_str())); + if (FAILED(hr)) { + if (errorMessage) + *errorMessage = SymbolGroupNode::msgAssignError(name(), value, msgDebugEngineComFailed("WriteSymbol", hr)); + return false; + } + return true; +} + // Utility returning a pair ('[42]','42') as name/iname pair // for a node representing an array index typedef std::pair StringStringPair; diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.h b/src/libs/qtcreatorcdbext/symbolgroupnode.h index b25fa67df96..a10b3aa6c94 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupnode.h +++ b/src/libs/qtcreatorcdbext/symbolgroupnode.h @@ -227,6 +227,9 @@ public: std::wstring symbolGroupRawValue() const; std::wstring symbolGroupFixedValue() const; + + bool assign(const std::string &value, std::string *errorMessage = 0); + // A quick check if symbol is valid by checking for inaccessible value bool isMemoryAccessible() const; @@ -254,6 +257,10 @@ public: // Remove self off parent and return the indexes to be shifted or unsigned(-1). bool removeSelf(SymbolGroupNode *root, std::string *errorMessage); + static std::string msgAssignError(const std::string &nodeName, + const std::string &value, + const std::string &why); + private: const SymbolGroupNode *symbolGroupNodeParent() const; SymbolGroupNode *symbolGroupNodeParent(); diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp index 6e432f7f86f..f1c87a94a6b 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp @@ -34,6 +34,7 @@ #include "symbolgroup.h" #include "stringutils.h" #include "containers.h" +#include "extensioncontext.h" #include #include @@ -266,7 +267,8 @@ unsigned char *SymbolGroupValue::readMemory(CIDebugDataSpaces *ds, ULONG64 addre delete [] buffer; if (errorMessage) { std::ostringstream estr; - estr << "Cannot read " << length << " bytes from " << address << ": " + estr << "Cannot read " << length << " bytes from 0x" + << std::hex << address << ": " << msgDebugEngineComFailed("ReadVirtual", hr); *errorMessage = estr.str(); } @@ -274,12 +276,44 @@ unsigned char *SymbolGroupValue::readMemory(CIDebugDataSpaces *ds, ULONG64 addre } if (received < length && errorMessage) { std::ostringstream estr; - estr << "Warning: Received only " << received << " bytes of " << length << " requested at " << address << '.'; + estr << "Warning: Received only " << received + << " bytes of " << length + << " requested at 0x" << std::hex << address << '.'; *errorMessage = estr.str(); } return buffer; } +bool SymbolGroupValue::writeMemory(CIDebugDataSpaces *ds, ULONG64 address, + const unsigned char *data, ULONG length, + std::string *errorMessage /* =0 */) +{ + ULONG filled = 0; + const HRESULT hr = ds->FillVirtual(address, length, + const_cast(data), + length, &filled); + if (FAILED(hr)) { + if (errorMessage) { + std::ostringstream estr; + estr << "Cannot write " << length << " bytes to 0x" + << std::hex << address << ": " + << msgDebugEngineComFailed("FillVirtual", hr); + *errorMessage = estr.str(); + } + return false; + } + if (filled < length) { + if (errorMessage) { + std::ostringstream estr; + estr << "Filled only " << filled << " bytes of " << length + << " at 0x" << std::hex << address << '.'; + *errorMessage = estr.str(); + } + return false; + } + return true; +} + // Return allocated array of data unsigned char *SymbolGroupValue::pointerData(unsigned length) const { @@ -2217,6 +2251,264 @@ static inline std::vector return rc; } +/* AssignmentStringData: Helper struct used for assigning values + * to string classes. Contains an (allocated) data array with size for use + * with IDebugDataSpaced::FillVirtual() + string length information and + * provides a conversion function decodeString() to create the array + * depending on the argument format (blow up ASCII to UTF16 or vice versa). */ + +struct AssignmentStringData +{ + explicit AssignmentStringData(size_t dataLengthIn, size_t stringLengthIn); + static AssignmentStringData decodeString(const char *begin, const char *end, + int valueEncoding, bool toUtf16); + + static inline AssignmentStringData decodeString(const std::string &value, + int valueEncoding, bool toUtf16) + { return decodeString(value.c_str(), value.c_str() + value.size(), + valueEncoding, toUtf16); } + + unsigned char *data; + size_t dataLength; + size_t stringLength; +}; + +AssignmentStringData::AssignmentStringData(size_t dataLengthIn, size_t stringLengthIn) : + data(new unsigned char[dataLengthIn]), dataLength(dataLengthIn), + stringLength(stringLengthIn) +{ + if (dataLength) + memset(data, 0, dataLength); +} + +AssignmentStringData AssignmentStringData::decodeString(const char *begin, const char *end, + int valueEncoding, bool toUtf16) +{ + if (toUtf16) { // Target is UTF16 consisting of unsigned short characters. + switch (valueEncoding) { + // Hex encoded ASCII/2 digits per char: Decode to plain characters and + // recurse to expand them. + case AssignHexEncoded: { + const AssignmentStringData decoded = decodeString(begin, end, AssignHexEncoded, false); + const char *source = reinterpret_cast(decoded.data); + const AssignmentStringData utf16 = decodeString(source, source + decoded.stringLength, + AssignPlainValue, true); + delete [] decoded.data; + return utf16; + } + // Hex encoded UTF16: 4 hex digits per character: Decode sequence. + case AssignHexEncodedUtf16: { + const size_t stringLength = (end - begin) / 4; + AssignmentStringData result(sizeof(unsigned short) *(stringLength + 1), stringLength); + decodeHex(begin, end, result.data); + return result; + } + default: + break; + } + // Convert plain ASCII data to UTF16 by expanding. + const size_t stringLength = end - begin; + AssignmentStringData result(sizeof(unsigned short) *(stringLength + 1), stringLength); + const unsigned char *source = reinterpret_cast(begin); + unsigned short *target = reinterpret_cast(result.data); + std::copy(source, source + stringLength, target); + return result; + } // toUtf16 + switch (valueEncoding) { + case AssignHexEncoded: { // '0A5A'..2 digits per character + const size_t stringLength = (end - begin) / 2; + AssignmentStringData result(stringLength + 1, stringLength); + decodeHex(begin, end, result.data); + return result; + } + // Condense UTF16 characters to ASCII: Decode and use only every 2nd character + // (little endian, first byte) + case AssignHexEncodedUtf16: { + const AssignmentStringData decoded = decodeString(begin, end, AssignHexEncoded, false); + const size_t stringLength = decoded.stringLength / 2; + const AssignmentStringData result(stringLength + 1, stringLength); + const unsigned char *sourceEnd = decoded.data + decoded.stringLength; + unsigned char *target = result.data; + for (const unsigned char *source = decoded.data; source < sourceEnd; source += 2) + *target++ = *source; + delete [] decoded.data; + return result; + } + break; + default: + break; + } + // Plain 0-terminated copy + const size_t stringLength = end - begin; + AssignmentStringData result(stringLength + 1, stringLength); + memcpy(result.data, begin, stringLength); + return result; +} + +// Assignment helpers +static inline std::string msgAssignStringFailed(const std::string &value, int errorCode) +{ + std::ostringstream estr; + estr << "Unable to assign a string of " << value.size() << " bytes: Error " << errorCode; + return estr.str(); +} + +/* QString assign helper: If QString instance has sufficiently allocated, + * memory, write the data. Else invoke 'QString::resize' and + * recurse (since 'd' might become invalid). This works for QString with UTF16 + * data and for QByteArray with ASCII data due to the similar member + * names and both using a terminating '\0' w_char/byte. */ +static int assignQStringI(SymbolGroupNode *n, const char *className, + const AssignmentStringData &data, + const SymbolGroupValueContext &ctx, + bool doAlloc = true) +{ + const SymbolGroupValue v(n, ctx); + SymbolGroupValue d = v["d"]; + if (!d) + return 1; + // Check the size, re-allocate if required. + const size_t allocated = d["alloc"].intValue(); + const bool needRealloc = allocated < data.stringLength; + if (needRealloc) { + if (!doAlloc) // Calling re-alloc failed somehow. + return 3; + std::ostringstream callStr; + const std::string funcName + = QtInfo::get(ctx).prependQtCoreModule(std::string(className) + "::resize"); + callStr << funcName << '(' << std::hex << std::showbase + << v.address() << ',' << data.stringLength << ')'; + std::wstring wOutput; + std::string errorMessage; + return ExtensionContext::instance().call(callStr.str(), &wOutput, &errorMessage) ? + assignQStringI(n, className, data, ctx, false) : 5; + } + // Write data. + const ULONG64 address = d["data"].pointerValue(); + if (!address) + return 9; + if (!SymbolGroupValue::writeMemory(v.context().dataspaces, + address, data.data, ULONG(data.dataLength))) + return 11; + // Correct size unless we re-allocated + if (!needRealloc) { + const SymbolGroupValue size = d["size"]; + if (!size || !size.node()->assign(toString(data.stringLength))) + return 17; + } + return 0; +} + +// QString assignment +static inline bool assignQString(SymbolGroupNode *n, + int valueEncoding, const std::string &value, + const SymbolGroupValueContext &ctx, + std::string *errorMessage) +{ + const AssignmentStringData utf16 = AssignmentStringData::decodeString(value, valueEncoding, true); + const int errorCode = assignQStringI(n, "QString", utf16, ctx); + delete [] utf16.data; + if (errorCode) { + *errorMessage = msgAssignStringFailed(value, errorCode); + return false; + } + return true; +} + +// QByteArray assignment +static inline bool assignQByteArray(SymbolGroupNode *n, + int valueEncoding, const std::string &value, + const SymbolGroupValueContext &ctx, + std::string *errorMessage) +{ + const AssignmentStringData data = AssignmentStringData::decodeString(value, valueEncoding, false); + const int errorCode = assignQStringI(n, "QByteArray", data, ctx); + delete [] data.data; + if (errorCode) { + *errorMessage = msgAssignStringFailed(value, errorCode); + return false; + } + return true; +} + +// Helper to assign character data to std::string or std::wstring. +static inline int assignStdStringI(SymbolGroupNode *n, int type, + const AssignmentStringData &data, + const SymbolGroupValueContext &ctx) +{ + /* We do not reallocate and just write to the allocated buffer + * (internal small buffer or _Ptr depending on reserved) provided sufficient + * memory is there since it is apparently not possible to call the template + * function std::string::resize(). + * See the dumpStd_W_String() how to figure out if the internal buffer + * or an allocated array is used. */ + + const SymbolGroupValue v(n, ctx); + SymbolGroupValue bx = v[unsigned(0)]["_Bx"]; + SymbolGroupValue size; + int reserved = 0; + if (bx) { // MSVC2010 + size = v[unsigned(0)]["_Mysize"]; + reserved = v[unsigned(0)]["_Myres"].intValue(); + } else { // MSVC2008 + bx = v["_Bx"]; + size = v["_Mysize"]; + reserved = v["_Myres"].intValue(); + } + if (reserved < 0 || !size || !bx) + return 42; + if (reserved <= data.stringLength) + return 1; // Insufficient memory. + // Copy data: 'Buf' array for small strings, else pointer 'Ptr'. + const int bufSize = type == KT_StdString ? 16 : 8; // see basic_string. + const ULONG64 address = (bufSize <= reserved) ? + bx["_Ptr"].pointerValue() : bx["_Buf"].address(); + if (!address) + return 3; + if (!SymbolGroupValue::writeMemory(v.context().dataspaces, + address, data.data, ULONG(data.dataLength))) + return 7; + // Correct size + if (!size.node()->assign(toString(data.stringLength))) + return 13; + return 0; +} + +// assignment of std::string assign via ASCII, std::wstring via UTF16 +static inline bool assignStdString(SymbolGroupNode *n, + int type, int valueEncoding, const std::string &value, + const SymbolGroupValueContext &ctx, + std::string *errorMessage) +{ + const bool toUtf16 = type == KT_StdWString; + const AssignmentStringData data = AssignmentStringData::decodeString(value, valueEncoding, + toUtf16); + const int errorCode = assignStdStringI(n, type, data, ctx); + delete [] data.data; + if (errorCode) { + *errorMessage = msgAssignStringFailed(value, errorCode); + return false; + } + return true; +} + +bool assignType(SymbolGroupNode *n, int valueEncoding, const std::string &value, + const SymbolGroupValueContext &ctx, std::string *errorMessage) +{ + switch (n->dumperType()) { + case KT_QString: + return assignQString(n, valueEncoding, value, ctx, errorMessage); + case KT_QByteArray: + return assignQByteArray(n, valueEncoding, value, ctx, errorMessage); + case KT_StdString: + case KT_StdWString: + return assignStdString(n, n->dumperType(), valueEncoding, value, ctx, errorMessage); + default: + break; + } + return false; +} + std::vector dumpComplexType(SymbolGroupNode *n, int type, void *specialInfo, const SymbolGroupValueContext &ctx) diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.h b/src/libs/qtcreatorcdbext/symbolgroupvalue.h index c45b35ca119..964e5e16924 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.h +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.h @@ -143,6 +143,10 @@ public: ULONG64 address, double defaultValue = 0.0, std::string *errorMessage = 0); + static bool writeMemory(CIDebugDataSpaces *ds, ULONG64 address, + const unsigned char *data, ULONG length, + std::string *errorMessage = 0); + static unsigned pointerSize(); static unsigned intSize(); @@ -224,6 +228,17 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, int *containerSizeIn = 0, void **specialInfoIn = 0); +enum AssignEncoding +{ + AssignPlainValue, + AssignHexEncoded, + AssignHexEncodedUtf16 +}; + +bool assignType(SymbolGroupNode *n, int valueEncoding, const std::string &value, + const SymbolGroupValueContext &ctx, + std::string *errorMessage); + // Non-container complex dumpers (QObjects/QVariants). std::vector dumpComplexType(SymbolGroupNode *node, int type, void *specialInfo, diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index c66fb9ab6fb..cfb6b1b2f87 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -1261,6 +1261,15 @@ void CdbEngine::handleJumpToLineAddressResolution(const CdbBuiltinCommandPtr &cm } } +static inline bool isAsciiWord(const QString &s) +{ + foreach (const QChar &c, s) { + if (!c.isLetterOrNumber() || c.toAscii() == 0) + return false; + } + return true; +} + void CdbEngine::assignValueInDebugger(const WatchData *w, const QString &expr, const QVariant &value) { if (debug) @@ -1270,10 +1279,28 @@ void CdbEngine::assignValueInDebugger(const WatchData *w, const QString &expr, c qWarning("Internal error: assignValueInDebugger: Invalid state or no stack frame."); return; } - QByteArray cmd; ByteArrayInputStream str(cmd); - str << m_extensionCommandPrefixBA << "assign " << w->iname << '=' << value.toString(); + switch (value.type()) { + case QVariant::String: { + // Convert qstring to Utf16 data not considering endianness for Windows. + const QString s = value.toString(); + if (isAsciiWord(s)) { + str << m_extensionCommandPrefixBA << "assign \"" << w->iname << '=' + << s.toLatin1() << '"'; + } else { + const QByteArray utf16(reinterpret_cast(s.utf16()), 2 * s.size()); + str << m_extensionCommandPrefixBA << "assign -u " << w->iname << '=' + << utf16.toHex(); + } + } + break; + default: + str << m_extensionCommandPrefixBA << "assign " << w->iname << '=' + << value.toString(); + break; + } + postCommand(cmd, 0); // Update all locals in case we change a union or something pointed to // that affects other variables, too.