From c8a61cc8f2dbc155184c80fb5846ea9dc8641e2a Mon Sep 17 00:00:00 2001 From: hjk <qtc-committer@nokia.com> Date: Thu, 11 Mar 2010 18:55:52 +0100 Subject: [PATCH] debugger: implement selected of string encoding per pointer type/individual pointer --- share/qtcreator/gdbmacros/dumper.py | 148 +++++++++++++----- src/plugins/debugger/gdb/classicgdbengine.cpp | 13 +- src/plugins/debugger/gdb/gdbengine.cpp | 20 +-- src/plugins/debugger/gdb/pythongdbengine.cpp | 12 +- src/plugins/debugger/watchhandler.cpp | 100 +++++++++--- src/plugins/debugger/watchhandler.h | 5 +- src/plugins/debugger/watchutils.cpp | 35 ++++- src/plugins/debugger/watchwindow.cpp | 9 +- tests/manual/gdbdebugger/simple/app.cpp | 2 + 9 files changed, 244 insertions(+), 100 deletions(-) diff --git a/share/qtcreator/gdbmacros/dumper.py b/share/qtcreator/gdbmacros/dumper.py index 79402c00f48..26328f5c1bb 100644 --- a/share/qtcreator/gdbmacros/dumper.py +++ b/share/qtcreator/gdbmacros/dumper.py @@ -432,12 +432,50 @@ def qtNamespace(): # Happens for none-Qt applications return "" -def encodeCharArray(p, size): +def findFirstZero(p, max): + for i in xrange(max): + if p.dereference() == 0: + return i + p = p + 1 + return -1 + +def encodeCharArray(p, maxsize): + t = gdb.lookup_type("unsigned char").pointer() + p = p.cast(t) + i = findFirstZero(p, maxsize) + limit = select(i < 0, maxsize, i) s = "" - p = p.cast(gdb.lookup_type("unsigned char").pointer()) - for i in xrange(size): + for i in xrange(limit): s += "%02x" % int(p.dereference()) p += 1 + if i == maxsize: + s += "2e2e2e" + return s + +def encodeChar2Array(p, maxsize): + t = gdb.lookup_type("unsigned short").pointer() + p = p.cast(t) + i = findFirstZero(p, maxsize) + limit = select(i < 0, maxsize, i) + s = "" + for i in xrange(limit): + s += "%04x" % int(p.dereference()) + p += 1 + if i == maxsize: + s += "2e002e002e00" + return s + +def encodeChar4Array(p, maxsize): + t = gdb.lookup_type("unsigned int").pointer() + p = p.cast(t) + i = findFirstZero(p, maxsize) + limit = select(i < 0, maxsize, i) + s = "" + for i in xrange(limit): + s += "%08x" % int(p.dereference()) + p += 1 + if i == maxsize: + s += "2e0000002e0000002e000000" return s def encodeByteArray(value): @@ -450,10 +488,7 @@ def encodeByteArray(value): if size > 0: checkAccess(data, 4) checkAccess(data + size) == 0 - - innerType = gdb.lookup_type("char") - p = gdb.Value(data.cast(innerType.pointer())) - return encodeCharArray(p, size) + return encodeCharArray(data, size) def encodeString(value): d_ptr = value['d'].dereference() @@ -502,22 +537,33 @@ class FrameCommand(gdb.Command): def __init__(self): super(FrameCommand, self).__init__("bb", gdb.COMMAND_OBSCURE) - def invoke(self, arg, from_tty): - args = arg.split(' ') - - #warn("ARG: %s" % arg) - #warn("ARGS: %s" % args) - options = args[0].split(",") - varList = args[1][1:] - if len(varList) == 0: - varList = [] - else: - varList = varList.split(",") - expandedINames = set(args[2].split(",")) + def invoke(self, args, from_tty): + options = [] + varList = [] + typeformats = {} + formats = {} watchers = "" - if len(args) > 3: - watchers = base64.b16decode(args[3], True) - #warn("WATCHERS: %s" % watchers) + for arg in args.split(' '): + pos = arg.find(":") + 1 + if arg.startswith("options:"): + options = arg[pos:].split(",") + elif arg.startswith("vars:"): + vars = arg[pos:].split(",") + elif arg.startswith("expanded:"): + expandedINames = set(arg[pos:].split(",")) + elif arg.startswith("typeformats:"): + for f in arg[pos:].split(","): + pos = f.find("=") + if pos != -1: + type = base64.b16decode(f[0:pos], True) + typeformats[type] = int(f[pos+1:]) + elif arg.startswith("formats:"): + for f in arg[pos:].split(","): + pos = f.find("=") + if pos != -1: + formats[f[0:pos]] = int(f[pos+1:]) + elif arg.startswith("watchers:"): + watchers = base64.b16decode(arg[pos:], True) useFancy = "fancy" in options @@ -552,6 +598,8 @@ class FrameCommand(gdb.Command): d = Dumper() d.dumpers = self.dumpers + d.typeformats = typeformats + d.formats = formats d.useFancy = useFancy d.passExceptions = "passexceptions" in options d.autoDerefPointers = "autoderef" in options @@ -837,6 +885,9 @@ class Dumper: if len(type) > 0 and type != self.childTypes[-1]: self.put('type="%s",' % type) # str(type.unqualified()) ? + def putAddress(self, addr): + self.put('addr="%s",' % cleanAddress(addr)) + def putNumChild(self, numchild): #warn("NUM CHILD: '%s' '%s'" % (numchild, self.childNumChilds[-1])) if numchild != self.childNumChilds[-1]: @@ -1038,13 +1089,36 @@ class Dumper: elif type.code == gdb.TYPE_CODE_PTR: - #warn("A POINTER: %s" % value.type) isHandled = False - if str(type.strip_typedefs()).find("(") != -1: + format = self.formats.get(item.iname) + if format is None: + format = self.typeformats.get(str(value.type)) + + if not format is None: + self.putAddress(value.address) + self.putType(item.value.type) + self.putNumChild(0) + isHandled = True + + if format == 0: + # Bald pointer. + self.putValue(str(cleanAddress(value.address))) + elif format == 1 or format == 2: + # Latin1 or UTF-8 + f = select(format == 1, "6", "9") + self.putValue(encodeCharArray(value, 100), f) + elif format == 3: + # UTF-16. + self.putValue(encodeChar2Array(value, 100), "11") + elif format == 4: + # UCS-4: + self.putValue(encodeChar4Array(value, 100), "10") + + if (not isHandled) and str(type.strip_typedefs()).find("(") != -1: # A function pointer. self.putValue(str(item.value)) - self.put('addr="%s",' % cleanAddress(value.address)) + self.putAddress(value.address) self.putType(item.value.type) self.putNumChild(0) isHandled = True @@ -1069,21 +1143,8 @@ class Dumper: # Display values up to given length directly #warn("CHAR AUTODEREF: %s" % value.address) self.putType(item.value.type) - firstNul = -1 - p = value - found = False - for i in xrange(100): - if p.dereference() == 0: - # Found terminating NUL - found = True - break - p += 1 - if found: - self.putValue(encodeCharArray(value, i), "6") - self.putNumChild(0) - else: - self.putValue(encodeCharArray(value, 100) + "2e2e2e", "6") - self.putNumChild(0) + self.putValue(encodeCharArray(value, 100), "6") + self.putNumChild(0) isHandled = True #warn("AUTODEREF: %s" % self.autoDerefPointers) @@ -1105,8 +1166,9 @@ class Dumper: if not isHandled: #warn("GENERIC PLAIN POINTER: %s" % value.type) self.putType(item.value.type) - self.putValue(str(value)) - self.put('addr="%s",' % cleanAddress(value.address)) + #self.putValue(str(value)) + self.putValue("") + self.putAddress(value.address) self.putNumChild(1) if self.isExpanded(item): self.beginChildren() @@ -1208,7 +1270,7 @@ class Dumper: value = item.value[field.name] child = Item(value, item.iname, field.name, field.name) self.beginHash() - self.put('addr="%s",' % cleanAddress(value.address)) + self.putAddress(value.address) self.putItemHelper(child) self.endHash(); else: diff --git a/src/plugins/debugger/gdb/classicgdbengine.cpp b/src/plugins/debugger/gdb/classicgdbengine.cpp index f366cff8094..5d8cd936ab6 100644 --- a/src/plugins/debugger/gdb/classicgdbengine.cpp +++ b/src/plugins/debugger/gdb/classicgdbengine.cpp @@ -252,10 +252,10 @@ void GdbEngine::updateSubItemClassic(const WatchData &data0) return; } - // we should have a type now. this is relied upon further below + // We should have a type now. This is relied upon further below. QTC_ASSERT(!data.type.isEmpty(), return); - // a common case that can be easily solved + // A common case that can be easily solved. if (data.isChildrenNeeded() && isPointerType(data.type) && !hasDebuggingHelperForType(data.type)) { // We sometimes know what kind of children pointers have @@ -431,8 +431,6 @@ void GdbEngine::handleDebuggingHelperValue3Classic(const GdbResponse &response) while (out.endsWith(' ') || out.endsWith('\n')) out.chop(1); QList<QByteArray> list = out.split(' '); - //qDebug() << "RECEIVED" << response.toString() << "FOR" << data0.toString() - // << " STREAM:" << out; if (list.isEmpty()) { //: Value for variable data.setError(WatchData::msgNotInScope()); @@ -538,7 +536,7 @@ void GdbEngine::tryLoadDebuggingHelpersClassic() postCommand("call (void*)dlopen(\"" + GdbMi::escapeCString(dlopenLib) + "\", " + flag + ")", CB(handleDebuggingHelperSetup)); - // some older systems like CentOS 4.6 prefer this: + // Some older systems like CentOS 4.6 prefer this: postCommand("call (void*)__dlopen(\"" + GdbMi::escapeCString(dlopenLib) + "\", " + flag + ")", CB(handleDebuggingHelperSetup)); @@ -550,7 +548,7 @@ void GdbEngine::tryLoadDebuggingHelpersClassic() void GdbEngine::tryQueryDebuggingHelpersClassic() { PRECONDITION; - // retrieve list of dumpable classes + // Retrieve list of dumpable classes. postCommand("call (void*)qDumpObjectData440(1,0,0,0,0,0,0,0)"); postCommand("p (char*)&qDumpOutBuffer", CB(handleQueryDebuggingHelperClassic)); @@ -560,7 +558,7 @@ void GdbEngine::recheckDebuggingHelperAvailabilityClassic() { PRECONDITION; if (m_gdbAdapter->dumperHandling() != AbstractGdbAdapter::DumperNotAvailable) { - // retrieve list of dumpable classes + // Retrieve list of dumpable classes. postCommand("call (void*)qDumpObjectData440(1,0,0,0,0,0,0,0)"); postCommand("p (char*)&qDumpOutBuffer", CB(handleQueryDebuggingHelperClassic)); @@ -681,7 +679,6 @@ bool GdbEngine::checkDebuggingHelpersClassic() if (!manager()->qtDumperLibraryEnabled()) return false; const QString lib = qtDumperLibraryName(); - //qDebug() << "DUMPERLIB:" << lib; const QFileInfo fi(lib); if (!fi.exists()) { const QStringList &locations = manager()->qtDumperLibraryLocations(); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 60088b3ef2c..50817196b3b 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -3321,7 +3321,7 @@ void GdbEngine::setWatchDataDisplayedType(WatchData &data, const GdbMi &item) void GdbEngine::handleVarCreate(const GdbResponse &response) { WatchData data = response.cookie.value<WatchData>(); - // happens e.g. when we already issued a var-evaluate command + // Happens e.g. when we already issued a var-evaluate command. if (!data.isValid()) return; //qDebug() << "HANDLE VARIABLE CREATION:" << data.toString(); @@ -3351,11 +3351,9 @@ void GdbEngine::handleVarCreate(const GdbResponse &response) void GdbEngine::handleDebuggingHelperSetup(const GdbResponse &response) { - //qDebug() << "CUSTOM SETUP RESULT:" << response.toString(); if (response.resultClass == GdbResultDone) { } else { QString msg = QString::fromLocal8Bit(response.data.findChild("msg").data()); - //qDebug() << "CUSTOM DUMPER SETUP ERROR MESSAGE:" << msg; showStatusMessage(tr("Custom dumper setup: %1").arg(msg), 10000); } } @@ -3381,7 +3379,6 @@ void GdbEngine::handleChildren(const WatchData &data0, const GdbMi &item, } setWatchDataType(data, item.findChild("type")); setWatchDataEditValue(data, item.findChild("editvalue")); - setWatchDataChildCount(data, item.findChild("numchild")); setWatchDataValue(data, item.findChild("value"), item.findChild("valueencoded").data().toInt()); setWatchDataAddress(data, item.findChild("addr")); @@ -3391,6 +3388,7 @@ void GdbEngine::handleChildren(const WatchData &data0, const GdbMi &item, item.findChild("valuetooltipencoded").data().toInt()); setWatchDataValueEnabled(data, item.findChild("valueenabled")); setWatchDataValueEditable(data, item.findChild("valueeditable")); + setWatchDataChildCount(data, item.findChild("numchild")); //qDebug() << "\nAPPEND TO LIST: " << data.toString() << "\n"; list->append(data); @@ -3451,7 +3449,7 @@ void GdbEngine::updateLocals(const QVariant &cookie) } -// Parse a local variable from GdbMi +// Parse a local variable from GdbMi. WatchData GdbEngine::localVariable(const GdbMi &item, const QStringList &uninitializedVariables, QMap<QByteArray, int> *seen) @@ -3479,7 +3477,7 @@ WatchData GdbEngine::localVariable(const GdbMi &item, WatchData data; QString nam = _(name); data.iname = "local." + name + QByteArray::number(n + 1); - //: Variable %1 is the variable name, %2 is a simple count + //: Variable %1 is the variable name, %2 is a simple count. data.name = WatchData::shadowedName(nam, n); if (uninitializedVariables.contains(data.name)) { data.setError(WatchData::msgNotInScope()); @@ -3511,8 +3509,8 @@ WatchData GdbEngine::localVariable(const GdbMi &item, // somewhere in the response. data.setChildrenUnneeded(); } else { - // set value only directly if it is simple enough, otherwise - // pass through the insertData() machinery + // Set value only directly if it is simple enough, otherwise + // pass through the insertData() machinery. if (isIntOrFloatType(data.type) || isPointerType(data.type)) setWatchDataValue(data, item.findChild("value")); if (isSymbianIntType(data.type)) { @@ -3523,7 +3521,11 @@ WatchData GdbEngine::localVariable(const GdbMi &item, if (!m_manager->watchHandler()->isExpandedIName(data.iname)) data.setChildrenUnneeded(); - if (isPointerType(data.type) || data.name == __("this")) + + GdbMi t = item.findChild("numchild"); + if (t.isValid()) + data.setHasChildren(t.data().toInt() > 0); + else if (isPointerType(data.type) || data.name == __("this")) data.setHasChildren(true); return data; } diff --git a/src/plugins/debugger/gdb/pythongdbengine.cpp b/src/plugins/debugger/gdb/pythongdbengine.cpp index 934eaa4500f..3bb164365bd 100644 --- a/src/plugins/debugger/gdb/pythongdbengine.cpp +++ b/src/plugins/debugger/gdb/pythongdbengine.cpp @@ -55,13 +55,7 @@ void GdbEngine::updateLocalsPython(const QByteArray &varList) //m_toolTipExpression.clear(); WatchHandler *handler = m_manager->watchHandler(); - QByteArray expanded; - QSet<QByteArray> expandedINames = handler->expandedINames(); - QSetIterator<QByteArray> jt(expandedINames); - while (jt.hasNext()) { - expanded.append(jt.next()); - expanded.append(','); - } + QByteArray expanded = handler->formatRequests(); if (expanded.isEmpty()) expanded.append("defaults,"); expanded.chop(1); @@ -92,8 +86,8 @@ void GdbEngine::updateLocalsPython(const QByteArray &varList) options += "defaults,"; options.chop(1); - postCommand("bb " + options + " @" + varList + ' ' - + expanded + ' ' + watchers.toHex(), + postCommand("bb options:" + options + " vars:" + varList + ' ' + + expanded + " watchers:" + watchers.toHex(), WatchUpdate, CB(handleStackFramePython)); } diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 34cc848d644..c02d379726e 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -639,27 +639,6 @@ static QString formattedValue(const WatchData &data, int format) return reformatInteger(data.value.toULongLong(), format); return reformatInteger(data.value.toLongLong(), format); } - if (0 && !data.addr.isEmpty()) { - if (format == BaldPointerFormat) - return data.value; - bool ok = false; - const void *addr = - reinterpret_cast<void *>(data.value.toULongLong(&ok, 0)); - if (!ok || !addr) - return data.value; - // FIXME: add a round trip through the debugger to prevent crashs? - if (format == Latin1StringFormat) - return QString::fromLatin1(static_cast<const char *>(addr)); - if (format == Local8BitStringFormat) - return QString::fromLocal8Bit(static_cast<const char *>(addr)); - if (format == Utf8StringFormat) - return QString::fromUtf8(static_cast<const char *>(addr)); - if (format == Utf16StringFormat) - return QString::fromUtf16(static_cast<const ushort *>(addr)); - if (format == Ucs4StringFormat) - return QString::fromUcs4(static_cast<const uint *>(addr)); - return data.value; - } return data.value; } @@ -802,7 +781,6 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const int format = m_handler->m_individualFormats.value(data.iname, -1); if (format == -1) format = m_handler->m_typeFormats.value(data.type, -1); - //qDebug() << "FORMATTED: " << format << formattedValue(data, format); return truncateValue(formattedValue(data, format)); } case 2: { @@ -845,7 +823,7 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const if (isIntType(data.type)) return QStringList() << tr("decimal") << tr("hexadecimal") << tr("binary") << tr("octal"); - if (!data.addr.isEmpty()) + if (data.type.endsWith(QLatin1Char('*'))) return QStringList() << tr("Bald pointer") << tr("Latin1 string") @@ -889,6 +867,7 @@ bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int ro } } else if (role == TypeFormatRole) { m_handler->setFormat(data.type, value.toInt()); + m_handler->m_manager->updateWatchData(data); } else if (role == IndividualFormatRole) { const int format = value.toInt(); if (format == -1) { @@ -896,6 +875,7 @@ bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int ro } else { m_handler->m_individualFormats[data.iname] = format; } + m_handler->m_manager->updateWatchData(data); } emit dataChanged(index, index); return true; @@ -1155,8 +1135,8 @@ WatchItem *WatchModel::findItem(const QByteArray &iname, WatchItem *root) const static void debugRecursion(QDebug &d, const WatchItem *item, int depth) { d << QString(2 * depth, QLatin1Char(' ')) << item->toString() << '\n'; - foreach(const WatchItem *i, item->children) - debugRecursion(d, i, depth + 1); + foreach (const WatchItem *child, item->children) + debugRecursion(d, child, depth + 1); } QDebug operator<<(QDebug d, const WatchModel &m) @@ -1167,6 +1147,16 @@ QDebug operator<<(QDebug d, const WatchModel &m) return d; } +void WatchModel::formatRequests(QByteArray *out, const WatchItem *item) const +{ + int format = m_handler->m_individualFormats.value(item->iname, -1); + if (format == -1) + format = m_handler->m_typeFormats.value(item->type, -1); + if (format != -1) + *out += item->iname + ":format=" + QByteArray::number(format) + ','; + foreach (const WatchItem *child, item->children) + formatRequests(out, child); +} /////////////////////////////////////////////////////////////////////// // @@ -1573,5 +1563,65 @@ void WatchHandler::setFormat(const QString &type, int format) m_tooltips->emitDataChanged(1); } +int WatchHandler::format(const QByteArray &iname) const +{ + int result = -1; + if (const WatchData *item = findItem(iname)) { + int result = m_individualFormats.value(iname, -1); + if (result == -1) + result = m_typeFormats.value(item->type, -1); + } + return result; +} + +QByteArray WatchHandler::formatRequests() const +{ + QByteArray ba; + //m_locals->formatRequests(&ba, m_locals->m_root); + //m_watchers->formatRequests(&ba, m_watchers->m_root); + + ba.append("expanded:"); + if (!m_expandedINames.isEmpty()) { + QSetIterator<QByteArray> jt(m_expandedINames); + while (jt.hasNext()) { + QByteArray iname = jt.next(); + ba.append(iname); + ba.append(','); + } + ba.chop(1); + } + ba.append(' '); + + ba.append("typeformats:"); + if (!m_typeFormats.isEmpty()) { + QHashIterator<QString, int> it(m_typeFormats); + while (it.hasNext()) { + it.next(); + ba.append(it.key().toLatin1().toHex()); + ba.append('='); + ba.append(QByteArray::number(it.value())); + ba.append(','); + } + ba.chop(1); + } + ba.append(' '); + + ba.append("formats:"); + if (!m_individualFormats.isEmpty()) { + QHashIterator<QString, int> it(m_individualFormats); + while (it.hasNext()) { + it.next(); + ba.append(it.key().toLatin1()); + ba.append('='); + ba.append(QByteArray::number(it.value())); + ba.append(','); + } + ba.chop(1); + } + ba.append(' '); + + return ba; +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index effec1e7329..365426b850c 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -139,8 +139,6 @@ public: bool valueEditable; // value will be editable bool error; -private: - public: int source; // Used by some debuggers (CDB) to tell where it originates from (dumper or symbol evaluation) int state; @@ -239,6 +237,7 @@ signals: private: QString niceType(const QString &typeIn) const; + void formatRequests(QByteArray *out, const WatchItem *item) const; WatchHandler *m_handler; WatchType m_type; @@ -284,8 +283,10 @@ public: QStringList watchedExpressions() const; QHash<QByteArray, int> watcherNames() const { return m_watcherNames; } + QByteArray formatRequests() const; static QString watcherEditPlaceHolder(); + int format(const QByteArray &iname) const; private: friend class WatchModel; diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index f84f98835e5..bda7f9d373b 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -640,7 +640,7 @@ QString decodeData(const QByteArray &ba, int encoding) case 5: { // base64 encoded 8 bit data, without quotes (see 1) return quoteUnprintableLatin1(QByteArray::fromBase64(ba)); } - case 6: { // %02x encoded 8 bit data + case 6: { // %02x encoded 8 bit Latin1 data const QChar doubleQuote(QLatin1Char('"')); const QByteArray decodedBa = QByteArray::fromHex(ba); //qDebug() << quoteUnprintableLatin1(decodedBa) << "\n\n"; @@ -660,6 +660,39 @@ QString decodeData(const QByteArray &ba, int encoding) return doubleQuote + QString::fromUcs4(reinterpret_cast<const uint *> (decodedBa.data()), decodedBa.size() / 4) + doubleQuote; } + case 9: { // %02x encoded 8 bit Utf-8 data + const QChar doubleQuote(QLatin1Char('"')); + const QByteArray decodedBa = QByteArray::fromHex(ba); + //qDebug() << quoteUnprintableLatin1(decodedBa) << "\n\n"; + return doubleQuote + QString::fromUtf8(decodedBa) + doubleQuote; + } + case 10: { // %08x encoded 32 bit data, Big Endian + const QChar doubleQuote(QLatin1Char('"')); + QByteArray decodedBa = QByteArray::fromHex(ba); + for (int i = 0; i < decodedBa.size(); i += 4) { + char c = decodedBa.at(i); + decodedBa[i] = decodedBa.at(i + 3); + decodedBa[i + 3] = c; + c = decodedBa.at(i + 1); + decodedBa[i + 1] = decodedBa.at(i + 2); + decodedBa[i + 2] = c; + } + //qDebug() << quoteUnprintableLatin1(decodedBa) << "\n\n"; + return doubleQuote + QString::fromUcs4(reinterpret_cast<const uint *> + (decodedBa.data()), decodedBa.size() / 4) + doubleQuote; + } + case 11: { // %02x encoded 16 bit data, Big Endian + const QChar doubleQuote(QLatin1Char('"')); + QByteArray decodedBa = QByteArray::fromHex(ba); + for (int i = 0; i < decodedBa.size(); i += 2) { + char c = decodedBa.at(i); + decodedBa[i] = decodedBa.at(i + 1); + decodedBa[i + 1] = c; + } + //qDebug() << quoteUnprintableLatin1(decodedBa) << "\n\n"; + return doubleQuote + QString::fromUcs4(reinterpret_cast<const uint *> + (decodedBa.data()), decodedBa.size() / 4) + doubleQuote; + } } qDebug() << "ENCODING ERROR: " << encoding; return QCoreApplication::translate("Debugger", "<Encoding error>"); diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index 268c53ba812..7d076e26594 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -269,7 +269,8 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev) actWatchUnknownMemory->setEnabled(actionsEnabled && canShowMemory); if (canShowMemory && !address.isEmpty()) - actWatchKnownMemory = new QAction(tr("Open Memory Editor at %1").arg(address), &menu); + actWatchKnownMemory = + new QAction(tr("Open Memory Editor at %1").arg(address), &menu); menu.addSeparator(); QAction *actWatchOrRemove; @@ -293,8 +294,10 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev) menu.addAction(theDebuggerAction(RecheckDebuggingHelpers)); menu.addAction(theDebuggerAction(UseDebuggingHelpers)); - QAction *actClearCodeModelSnapshot = new QAction(tr("Refresh Code Model Snapshot"), &menu); - actClearCodeModelSnapshot->setEnabled(actionsEnabled && theDebuggerAction(UseCodeModel)->isChecked()); + QAction *actClearCodeModelSnapshot + = new QAction(tr("Refresh Code Model Snapshot"), &menu); + actClearCodeModelSnapshot->setEnabled(actionsEnabled + && theDebuggerAction(UseCodeModel)->isChecked()); menu.addAction(actClearCodeModelSnapshot); menu.addSeparator(); menu.addAction(theDebuggerAction(UseToolTipsInLocalsView)); diff --git a/tests/manual/gdbdebugger/simple/app.cpp b/tests/manual/gdbdebugger/simple/app.cpp index 316ed1ce78a..18540d2cfb3 100644 --- a/tests/manual/gdbdebugger/simple/app.cpp +++ b/tests/manual/gdbdebugger/simple/app.cpp @@ -1486,6 +1486,8 @@ int main(int argc, char *argv[]) testPlugin(); testQList(); testQLinkedList(); + char *s = "aöa"; + wchar_t *w = L"aöa"; testNamespace(); //return 0; testQHash(); -- GitLab