diff --git a/share/qtcreator/dumper/bridge.py b/share/qtcreator/dumper/bridge.py index 77b6eef22c6d5d918d6c4c4c14b2ec783dd8766a..edc4542bda59cd03051f6f54be3c4e0eb9db7545 100644 --- a/share/qtcreator/dumper/bridge.py +++ b/share/qtcreator/dumper/bridge.py @@ -1,4 +1,6 @@ +import binascii + cdbLoaded = False lldbLoaded = False gdbLoaded = False @@ -287,6 +289,29 @@ try: removeTempFile(filename, file) return lines + def selectedInferior(): + try: + # Does not exist in 7.3. + return gdb.selected_inferior() + except: + pass + # gdb.Inferior is new in gdb 7.2 + return gdb.inferiors()[0] + + def readRawMemory(base, size): + try: + inferior = selectedInferior() + return binascii.hexlify(inferior.read_memory(base, size)) + except: + pass + s = "" + t = lookupType("unsigned char").pointer() + base = base.cast(t) + for i in xrange(size): + s += "%02x" % int(base.dereference()) + base += 1 + return s + ####################################################################### # # Types diff --git a/share/qtcreator/dumper/dumper.py b/share/qtcreator/dumper/dumper.py index 5af212220bdc4345f7e236733620247c96d78e55..206e0113110e45cad3c0b0c6b9b1026be115b8aa 100644 --- a/share/qtcreator/dumper/dumper.py +++ b/share/qtcreator/dumper/dumper.py @@ -42,11 +42,6 @@ def removeTempFile(name, file): except: pass -try: - import binascii -except: - pass - verbosity = 0 verbosity = 1 @@ -69,8 +64,14 @@ Hex4EncodedLittleEndianWithoutQuotes, \ Hex2EncodedLocal8Bit, \ JulianDate, \ MillisecondsSinceMidnight, \ -JulianDateAndMillisecondsSinceMidnight \ - = range(17) +JulianDateAndMillisecondsSinceMidnight, \ +Hex2EncodedInt1, \ +Hex2EncodedInt2, \ +Hex2EncodedInt4, \ +Hex2EncodedInt8, \ +Hex2EncodedFloat4, \ +Hex2EncodedFloat8 \ + = range(23) # Display modes StopDisplay, \ @@ -479,6 +480,26 @@ def isSimpleType(typeobj): or code == FloatCode \ or code == EnumCode +def simpleEncoding(typeobj): + code = typeobj.code + if code == BoolCode or code == CharCode: + return Hex2EncodedInt1 + if code == IntCode: + if typeobj.sizeof == 1: + return Hex2EncodedInt1 + if typeobj.sizeof == 2: + return Hex2EncodedInt2 + if typeobj.sizeof == 4: + return Hex2EncodedInt4 + if typeobj.sizeof == 8: + return Hex2EncodedInt8 + if code == FloatCode: + if typeobj.sizeof == 4: + return Hex2EncodedFloat4 + if typeobj.sizeof == 8: + return Hex2EncodedFloat8 + return None + def warn(message): if True or verbosity > 0: print "XXX: %s\n" % message.encode("latin1") @@ -668,80 +689,23 @@ def findFirstZero(p, maximum): p = p + 1 return maximum + 1 -def extractCharArray(p, maxsize): - p = p.cast(lookupType("unsigned char").pointer()) - s = "" - i = 0 - while i < maxsize: - c = int(p.dereference()) - if c == 0: - return s - s += "%c" % c - p += 1 - i += 1 - if p.dereference() != 0: - s += "..." +def encodeCArray(p, innerType, suffix): + t = lookupType(innerType) + p = p.cast(t.pointer()) + limit = findFirstZero(p, qqStringCutOff) + s = readRawMemory(p, limit * t.sizeof) + if limit > qqStringCutOff: + s += suffix return s -def extractByteArray(value): - d_ptr = value['d'].dereference() - data = d_ptr['data'] - size = d_ptr['size'] - alloc = d_ptr['alloc'] - check(0 <= size and size <= alloc and alloc <= 100*1000*1000) - checkRef(d_ptr["ref"]) - if size > 0: - checkAccess(data, 4) - checkAccess(data + size) == 0 - return extractCharArray(data, min(qqStringCutOff, size)) - -def encodeCharArray(p, maxsize = None, limit = None): - if maxsize is None: - maxsize = qqStringCutOff - t = lookupType("unsigned char").pointer() - p = p.cast(t) - if limit is None: - limit = findFirstZero(p, maxsize) - s = "" - try: - # gdb.Inferior is new in gdb 7.2 - inferior = gdb.inferiors()[0] - s = binascii.hexlify(inferior.read_memory(p, limit)) - except: - for i in xrange(limit): - s += "%02x" % int(p.dereference()) - p += 1 - if limit > maxsize: - s += "2e2e2e" - return s +def encodeCharArray(p): + return encodeCArray(p, "unsigned char", "2e2e2e") -def encodeChar2Array(p, maxsize = None): - if maxsize == None: - maxsize = qqStringCutOff - t = lookupType("unsigned short").pointer() - p = p.cast(t) - limit = findFirstZero(p, maxsize) - s = "" - for i in xrange(limit): - s += "%04x" % int(p.dereference()) - p += 1 - if i == maxsize: - s += "2e002e002e00" - return s +def encodeChar2Array(p): + return encodeCArray(p, "unsigned short", "2e002e002e00") -def encodeChar4Array(p, maxsize = None): - if maxsize == None: - maxsize = qqStringCutOff - t = lookupType("unsigned int").pointer() - p = p.cast(t) - limit = findFirstZero(p, maxsize) - s = "" - for i in xrange(limit): - s += "%08x" % int(p.dereference()) - p += 1 - if i > maxsize: - s += "2e0000002e0000002e000000" - return s +def encodeChar4Array(p): + return encodeCArray(p, "unsigned int", "2e0000002e0000002e000000") def qByteArrayData(value): private = value['d'] @@ -758,13 +722,15 @@ def qByteArrayData(value): def encodeByteArray(value): data, size, alloc = qByteArrayData(value) - check(0 <= size and size <= alloc and alloc <= 100*1000*1000) - if size > 0: - checkAccess(data, 4) - checkAccess(data + size) == 0 - return encodeCharArray(data, limit = size) + if alloc != 0: + check(0 <= size and size <= alloc and alloc <= 100*1000*1000) + limit = min(size, qqStringCutOff) + s = readRawMemory(data, limit) + if limit < size: + s += "2e2e2e" + return s -def qQStringData(value): +def qStringData(value): private = value['d'] checkRef(private['ref']) try: @@ -778,26 +744,11 @@ def qQStringData(value): return private['data'], int(private['size']), int(private['alloc']) def encodeString(value): - data, size, alloc = qQStringData(value) - + data, size, alloc = qStringData(value) if alloc != 0: check(0 <= size and size <= alloc and alloc <= 100*1000*1000) - if size > 0: - checkAccess(data, 4) - checkAccess(data + size) == 0 - s = "" limit = min(size, qqStringCutOff) - try: - # gdb.Inferior is new in gdb 7.2 - inferior = gdb.inferiors()[0] - s = binascii.hexlify(inferior.read_memory(data, 2 * limit)) - except: - p = data - for i in xrange(limit): - val = int(p.dereference()) - s += "%02x" % (val % 256) - s += "%02x" % (val / 256) - p += 1 + s = readRawMemory(data, 2 * limit) if limit < size: s += "2e002e002e00" return s @@ -1082,7 +1033,7 @@ class Dumper: for item in listOfLocals([]): self.expandedINames.add(item.iname) self.expandedINames.discard("") - warn("EXPANDED: %s" % self.expandedINames) + #warn("EXPANDED: %s" % self.expandedINames) # Take care of the return value of the last function call. if len(resultVarName) > 0: @@ -1353,21 +1304,25 @@ class Dumper: self.putName(name) self.putItem(value) - def tryPutArrayContents(self, type, base, n): - if isSimpleType(type): - self.put('{value="') - self.put('"},{value="'.join([str((base + i).dereference()) - for i in xrange(n)])) - self.put('"}'); - return True - return False + def tryPutArrayContents(self, typeobj, base, n): + if not isSimpleType(typeobj): + return False + size = n * typeobj.sizeof; + self.put('childtype="%s",' % typeobj) + self.put('addrbase="0x%x",' % long(base)) + self.put('addrstep="0x%x",' % long(typeobj.sizeof)) + self.put('arrayencoding="%s",' % simpleEncoding(typeobj)) + self.put('arraydata="') + self.put(readRawMemory(base, size)) + self.put('",') + return True def putArrayData(self, type, base, n, childNumChild = None, maxNumChild = 10000): base = base.cast(type.pointer()) - with Children(self, n, type, childNumChild, maxNumChild, - base, type.sizeof): - if not self.tryPutArrayContents(type, base, n): + if not self.tryPutArrayContents(type, base, n): + with Children(self, n, type, childNumChild, maxNumChild, + base, type.sizeof): for i in self.childRange(): self.putSubItem(i, (base + i).dereference()) @@ -1507,9 +1462,9 @@ class Dumper: if self.currentIName in self.expandedINames: p = value.cast(targetType.pointer()) ts = targetType.sizeof - with Children(self, childType=targetType, - addrBase=p, addrStep=ts): - if not self.tryPutArrayContents(targetType, p, type.sizeof/ts): + if not self.tryPutArrayContents(targetType, p, type.sizeof/ts): + with Children(self, childType=targetType, + addrBase=p, addrStep=ts): self.putFields(value) return @@ -1557,7 +1512,7 @@ class Dumper: # Use Latin1 as default for char *. self.putAddress(value.address) self.putType(typeName) - self.putValue(encodeCharArray(value, 100), Hex2EncodedLatin1) + self.putValue(encodeCharArray(value), Hex2EncodedLatin1) self.putNumChild(0) return @@ -1578,7 +1533,7 @@ class Dumper: # Explicitly requested Latin1 formatting. self.putAddress(value.address) self.putType(typeName) - self.putValue(encodeCharArray(value, 100), Hex2EncodedLatin1) + self.putValue(encodeCharArray(value), Hex2EncodedLatin1) self.putNumChild(0) return @@ -1586,7 +1541,7 @@ class Dumper: # Explicitly requested UTF-8 formatting. self.putAddress(value.address) self.putType(typeName) - self.putValue(encodeCharArray(value, 100), Hex2EncodedUtf8) + self.putValue(encodeCharArray(value), Hex2EncodedUtf8) self.putNumChild(0) return @@ -1594,7 +1549,7 @@ class Dumper: # Explicitly requested local 8 bit formatting. self.putAddress(value.address) self.putType(typeName) - self.putValue(encodeCharArray(value, 100), Hex2EncodedLocal8Bit) + self.putValue(encodeCharArray(value), Hex2EncodedLocal8Bit) self.putNumChild(0) return @@ -1602,7 +1557,7 @@ class Dumper: # Explicitly requested UTF-16 formatting. self.putAddress(value.address) self.putType(typeName) - self.putValue(encodeChar2Array(value), Hex4EncodedBigEndian) + self.putValue(encodeChar2Array(value), Hex4EncodedLittleEndian) self.putNumChild(0) return @@ -1610,7 +1565,7 @@ class Dumper: # Explicitly requested UCS-4 formatting. self.putAddress(value.address) self.putType(typeName) - self.putValue(encodeChar4Array(value), Hex8EncodedBigEndian) + self.putValue(encodeChar4Array(value), Hex8EncodedLittleEndian) self.putNumChild(0) return @@ -1860,7 +1815,8 @@ def threadnames(arg): out = '[' oldthread = gdb.selected_thread() try: - for thread in gdb.inferiors()[0].threads(): + inferior = selectedInferior() + for thread in inferior.threads(): maximalStackDepth = int(arg) thread.switch() e = gdb.selected_frame () diff --git a/share/qtcreator/dumper/qttypes.py b/share/qtcreator/dumper/qttypes.py index 9d00282fbc8ddb15d0ee250ea6a6a0e42a2f4a28..f54a41961b00fb2b008e6fbfd753a7b1035cf37d 100644 --- a/share/qtcreator/dumper/qttypes.py +++ b/share/qtcreator/dumper/qttypes.py @@ -459,9 +459,6 @@ def qdump__QList(d, value): check(begin >= 0 and end >= 0 and end <= 1000 * 1000 * 1000) size = end - begin check(size >= 0) - #if n > 0: - # checkAccess(&list.front()) - # checkAccess(&list.back()) checkRef(d_ptr["ref"]) # Additional checks on pointer arrays. @@ -1650,7 +1647,6 @@ def qdump__QVector(d, value): d.putItemCount(size) d.putNumChild(size) if d.isExpanded(): - d.putField("size", size) d.putArrayData(innerType, p, size) @@ -2569,8 +2565,10 @@ if False: def qdump__Function(d, value): min = value["min"] max = value["max"] - var = extractByteArray(value["var"]) - f = extractByteArray(value["f"]) + data, size, alloc = qByteArrayData(value["var"]) + var = extractCString(data) + data, size, alloc = qByteArrayData(value["f"]) + f = extractCString(data) d.putValue("%s, %s=%f..%f" % (f, var, min, max)) d.putNumChild(0) d.putField("typeformats", "Normal,Displayed"); diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 5603d5f91bd066a22b35f234256d4cae3bfba6e3..7e62a8f1c44a5e5a10431535fbde745269e3b579 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -592,7 +592,7 @@ QString decodeData(const QByteArray &ba, int encoding) case Hex8EncodedBigEndian: { // 10, %08x encoded 32 bit data const QChar doubleQuote(QLatin1Char('"')); QByteArray decodedBa = QByteArray::fromHex(ba); - for (int i = 0; i < decodedBa.size(); i += 4) { + for (int i = 0; i < decodedBa.size() - 3; i += 4) { char c = decodedBa.at(i); decodedBa[i] = decodedBa.at(i + 3); decodedBa[i + 3] = c; @@ -643,6 +643,54 @@ QString decodeData(const QByteArray &ba, int encoding) return QCoreApplication::translate("Debugger", "<Encoding error>"); } +template <class T> +void decodeArrayHelper(QList<WatchData> *list, const WatchData &tmplate, + const QByteArray &rawData) +{ + const QByteArray ba = QByteArray::fromHex(rawData); + const T *p = (const T *) ba.data(); + WatchData data; + const QByteArray exp = "*(" + gdbQuoteTypes(tmplate.type) + "*)0x"; + for (int i = 0, n = ba.size() / sizeof(T); i < n; ++i) { + data = tmplate; + data.sortId = i; + data.iname += QByteArray::number(i); + data.name = QString::fromLatin1("[%1]").arg(i); + data.value = QString::number(p[i]); + data.address += i * sizeof(T); + data.exp = exp + QByteArray::number(data.address, 16); + data.setAllUnneeded(); + list->append(data); + } +} + +void decodeArray(QList<WatchData> *list, const WatchData &tmplate, + const QByteArray &rawData, int encoding) +{ + switch (encoding) { + case Hex2EncodedInt1: + decodeArrayHelper<uchar>(list, tmplate, rawData); + break; + case Hex2EncodedInt2: + decodeArrayHelper<ushort>(list, tmplate, rawData); + break; + case Hex2EncodedInt4: + decodeArrayHelper<uint>(list, tmplate, rawData); + break; + case Hex2EncodedInt8: + decodeArrayHelper<quint64>(list, tmplate, rawData); + break; + case Hex2EncodedFloat4: + decodeArrayHelper<float>(list, tmplate, rawData); + break; + case Hex2EncodedFloat8: + decodeArrayHelper<double>(list, tmplate, rawData); + break; + default: + qDebug() << "ENCODING ERROR: " << encoding; + } +} + // Editor tooltip support bool isCppEditor(Core::IEditor *editor) { @@ -870,41 +918,49 @@ void parseWatchData(const QSet<QByteArray> &expandedINames, setWatchDataChildCount(childtemplate, item.findChild("childnumchild")); //qDebug() << "CHILD TEMPLATE:" << childtemplate.toString(); - for (int i = 0, n = children.children().size(); i != n; ++i) { - const GdbMi &child = children.children().at(i); - WatchData data1 = childtemplate; - data1.sortId = i; - GdbMi name = child.findChild("name"); - if (name.isValid()) - data1.name = _(name.data()); - else - data1.name = QString::number(i); - GdbMi iname = child.findChild("iname"); - if (iname.isValid()) { - data1.iname = iname.data(); - } else { - data1.iname = data.iname; - data1.iname += '.'; - data1.iname += data1.name.toLatin1(); - } - if (!data1.name.isEmpty() && data1.name.at(0).isDigit()) - data1.name = QLatin1Char('[') + data1.name + QLatin1Char(']'); - if (addressStep) { - setWatchDataAddress(data1, addressBase); - addressBase += addressStep; - } - QByteArray key = child.findChild("key").data(); - if (!key.isEmpty()) { - int encoding = child.findChild("keyencoded").data().toInt(); - QString skey = decodeData(key, encoding); - if (skey.size() > 13) { - skey = skey.left(12); - skey += _("..."); + mi = item.findChild("arraydata"); + if (mi.isValid()) { + int encoding = item.findChild("arrayencoding").data().toInt(); + childtemplate.iname = data.iname + '.'; + childtemplate.address = addressBase; + decodeArray(list, childtemplate, mi.data(), encoding); + } else { + for (int i = 0, n = children.children().size(); i != n; ++i) { + const GdbMi &child = children.children().at(i); + WatchData data1 = childtemplate; + data1.sortId = i; + GdbMi name = child.findChild("name"); + if (name.isValid()) + data1.name = _(name.data()); + else + data1.name = QString::number(i); + GdbMi iname = child.findChild("iname"); + if (iname.isValid()) { + data1.iname = iname.data(); + } else { + data1.iname = data.iname; + data1.iname += '.'; + data1.iname += data1.name.toLatin1(); + } + if (!data1.name.isEmpty() && data1.name.at(0).isDigit()) + data1.name = QLatin1Char('[') + data1.name + QLatin1Char(']'); + if (addressStep) { + setWatchDataAddress(data1, addressBase); + addressBase += addressStep; + } + QByteArray key = child.findChild("key").data(); + if (!key.isEmpty()) { + int encoding = child.findChild("keyencoded").data().toInt(); + QString skey = decodeData(key, encoding); + if (skey.size() > 13) { + skey = skey.left(12); + skey += _("..."); + } + //data1.name += " (" + skey + ")"; + data1.name = skey; } - //data1.name += " (" + skey + ")"; - data1.name = skey; + parseWatchData(expandedINames, data1, child, list); } - parseWatchData(expandedINames, data1, child, list); } } diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h index d77f943ad2344b93969ff15af4b18dfbcc8ef92c..77b4eeefe80bc86a0d3e34470330e11b13729341 100644 --- a/src/plugins/debugger/watchutils.h +++ b/src/plugins/debugger/watchutils.h @@ -72,7 +72,13 @@ enum DebuggerEncoding Hex2EncodedLocal8BitWithQuotes = 13, JulianDate = 14, MillisecondsSinceMidnight = 15, - JulianDateAndMillisecondsSinceMidnight = 16 + JulianDateAndMillisecondsSinceMidnight = 16, + Hex2EncodedInt1 = 17, + Hex2EncodedInt2 = 18, + Hex2EncodedInt4 = 19, + Hex2EncodedInt8 = 20, + Hex2EncodedFloat4 = 21, + Hex2EncodedFloat8 = 22 }; bool isEditorDebuggable(Core::IEditor *editor); @@ -103,6 +109,9 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos, QString cppFunctionAt(const QString &fileName, int line); // Decode string data as returned by the dumper helpers. QString decodeData(const QByteArray &baIn, int encoding); +// Decode string data as returned by the dumper helpers. +void decodeArray(WatchData *list, const WatchData &tmplate, + const QByteArray &rawData, int encoding); // Get variables that are not initialized at a certain line // of a function from the code model. Shadowed variables will diff --git a/tests/manual/debugger/simple/simple_test_app.cpp b/tests/manual/debugger/simple/simple_test_app.cpp index 9909495fe641a617ce1d91c52ffcb1fafc76248a..e743812524712e2e54a843d88c6a11c6e7810462 100644 --- a/tests/manual/debugger/simple/simple_test_app.cpp +++ b/tests/manual/debugger/simple/simple_test_app.cpp @@ -2714,7 +2714,7 @@ namespace stdmap { void testStdMapUIntFloatIterator() { - typedef std::map<uint, float> Map; + typedef std::map<int, float> Map; Map map; map[11] = 11.0; map[22] = 22.0; @@ -2732,11 +2732,11 @@ namespace stdmap { BREAK_HERE; // Expand map. - // Check map <6 items> std::map<unsigned int, float>. + // Check map <6 items> std::map<int, float>. // Check map.11 11 float. - // Check it1.first 11 unsigned int. + // Check it1.first 11 int. // Check it1.second 11 float. - // Check it1.first 55 unsigned int. + // Check it1.first 55 int. // Check it1.second 55 float. // Continue. dummyStatement(&map, &it1, &it2, &it3, &it4, &it5, &it6);