OSDN Git Service

Debugger [CDB]: Enable Assignment to string classes.
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>
Tue, 17 May 2011 10:19:24 +0000 (12:19 +0200)
committerFriedemann Kleint <Friedemann.Kleint@nokia.com>
Tue, 17 May 2011 10:19:24 +0000 (12:19 +0200)
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
src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
src/libs/qtcreatorcdbext/stringutils.cpp
src/libs/qtcreatorcdbext/stringutils.h
src/libs/qtcreatorcdbext/symbolgroup.cpp
src/libs/qtcreatorcdbext/symbolgroup.h
src/libs/qtcreatorcdbext/symbolgroupnode.cpp
src/libs/qtcreatorcdbext/symbolgroupnode.h
src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
src/libs/qtcreatorcdbext/symbolgroupvalue.h
src/plugins/debugger/cdb/cdbengine.cpp

index 07f34b8..67574be 100644 (file)
@@ -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,
index e19c52a..67a834b 100644 (file)
@@ -157,7 +157,10 @@ static const CommandDescription commandDescriptions[] = {
 {"addsymbol","Adds a symbol to symbol group (testing command).",
  "[-t token] <frame-number> <name-expression> [optional-iname]"},
 {"assign","Assigns a value to a variable in current symbol group.",
- "[-t token] <iname=value>"},
+ "[-t token] [-h] <iname=value>\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<StringList>(argsIn, &token);
+        StringList tokens = commandTokens<StringList>(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) {
index 844773e..dddfe36 100644 (file)
@@ -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)
index 8349235..5bc5f52 100644 (file)
@@ -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);
index b23d0b5..6d2a0a6 100644 (file)
@@ -441,35 +441,26 @@ void SymbolGroup::markUninitialized(const std::vector<std::string> &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<char *>(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
index bdb1251..b2b9fc1 100644 (file)
@@ -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; }
index f76ef98..f5f6eda 100644 (file)
@@ -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<char *>(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<std::string, std::string> StringStringPair;
index b25fa67..a10b3aa 100644 (file)
@@ -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();
index 6e432f7..f1c87a9 100644 (file)
@@ -34,6 +34,7 @@
 #include "symbolgroup.h"
 #include "stringutils.h"
 #include "containers.h"
+#include "extensioncontext.h"
 
 #include <iomanip>
 #include <algorithm>
@@ -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<unsigned char *>(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<AbstractSymbolGroupNode *>
     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<const char*>(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<const unsigned char *>(begin);
+        unsigned short *target = reinterpret_cast<unsigned short *>(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<AbstractSymbolGroupNode *>
     dumpComplexType(SymbolGroupNode *n, int type, void *specialInfo,
                     const SymbolGroupValueContext &ctx)
index c45b35c..964e5e1 100644 (file)
@@ -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<AbstractSymbolGroupNode *>
     dumpComplexType(SymbolGroupNode *node, int type, void *specialInfo,
index c66fb9a..cfb6b1b 100644 (file)
@@ -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<const char *>(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.