From 2e7479aef0d978848135551ce166952ce44f31ed Mon Sep 17 00:00:00 2001 From: hjk Date: Fri, 24 Jan 2014 15:13:20 +0100 Subject: [PATCH] Debugger: Add data extraction for dumper inferior call results. Change-Id: I868be727c48cb3aa570f196dadde71706df01596 Reviewed-by: hjk --- share/qtcreator/debugger/dumper.py | 66 ++++++++++++++---- share/qtcreator/debugger/gdbbridge.py | 42 +++++++----- share/qtcreator/debugger/qttypes.py | 67 +++++++++---------- .../debugger/simple/simple_test_app.cpp | 7 +- 4 files changed, 115 insertions(+), 67 deletions(-) diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 20456e6288..1502b5a5c2 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -28,6 +28,7 @@ ############################################################################ import os +import struct import sys import base64 @@ -70,16 +71,51 @@ class Blob(object): def size(self): return self.size - def toHexOutput(self): - if hasattr(self.data, "tobytes"): - encoded = base64.b16encode(self.data.tobytes()) - else: - encoded = base64.b16encode(self.data) + def toBytes(self): + """Retrieves "lazy" contents from memoryviews.""" + data = self.data + if isinstance(data, memoryview): + data = data.tobytes() + if sys.version_info[0] == 2 and isinstance(data, buffer): + data = ''.join([c for c in data]) + return data + + def extractByte(self, offset = 0): + return struct.unpack_from("b", self.data, offset)[0] + + def extractShort(self, offset = 0): + return struct.unpack_from("h", self.data, offset)[0] + + def extractUShort(self, offset = 0): + return struct.unpack_from("H", self.data, offset)[0] + + def extractInt(self, offset = 0): + return struct.unpack_from("i", self.data, offset)[0] + + def extractUInt(self, offset = 0): + return struct.unpack_from("I", self.data, offset)[0] - if hasattr(encoded, "decode"): - return encoded.decode("utf8") - return encoded + def extractLong(self, offset = 0): + return struct.unpack_from("l", self.data, offset)[0] + # FIXME: Note these should take target architecture into account. + def extractULong(self, offset = 0): + return struct.unpack_from("L", self.data, offset)[0] + + def extractInt64(self, offset = 0): + return struct.unpack_from("q", self.data, offset)[0] + + def extractUInt64(self, offset = 0): + return struct.unpack_from("Q", self.data, offset)[0] + + def extractDouble(self, offset = 0): + return struct.unpack_from("d", self.data, offset)[0] + + def extractFloat(self, offset = 0): + return struct.unpack_from("f", self.data, offset)[0] + + def extractPointer(self, offset = 0): + return struct.unpack_from("P", self.data, offset)[0] # # Gnuplot based display for array-like structures. @@ -296,17 +332,22 @@ class DumperBase: self.cachedFormats[typeName] = stripped return stripped - # Hex decoding operating on string->string + # Hex decoding operating on str, return str. def hexdecode(self, s): if sys.version_info[0] == 2: return s.decode("hex") return bytes.fromhex(s).decode("utf8") - # Hex decoding operating on string->string + # Hex decoding operating on str or bytes, return str. def hexencode(self, s): if sys.version_info[0] == 2: return s.encode("hex") - return base64.b16encode(s.encode("utf8")).decode("utf8") + if isinstance(s, str): + s = s.encode("utf8") + return base64.b16encode(s).decode("utf8") + + #def toBlob(self, value): + # return self.extractBlob(value.address, value.type.sizeof) def isArmArchitecture(self): return False @@ -379,7 +420,8 @@ class DumperBase: return s def readMemory(self, addr, size): - return self.extractBlob(addr, size).toHexOutput() + data = self.extractBlob(addr, size).toBytes() + return self.hexencode(data) def encodeByteArray(self, value): return self.encodeByteArrayHelper(self.dereferenceValue(value)) diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index 0cc2f4cde3..8e878ec5c7 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -394,11 +394,11 @@ Value = gdb.Value -def stripTypedefs(type): - type = type.unqualified() - while type.code == TypedefCode: - type = type.strip_typedefs().unqualified() - return type +def stripTypedefs(typeobj): + typeobj = typeobj.unqualified() + while typeobj.code == TypedefCode: + typeobj = typeobj.strip_typedefs().unqualified() + return typeobj ####################################################################### @@ -497,8 +497,8 @@ class Dumper(DumperBase): for f in arg[pos:].split(","): pos = f.find("=") if pos != -1: - type = self.hexdecode(f[0:pos]) - self.typeformats[type] = int(f[pos+1:]) + typeName = self.hexdecode(f[0:pos]) + self.typeformats[typeName] = int(f[pos+1:]) elif arg.startswith("formats:"): for f in arg[pos:].split(","): pos = f.find("=") @@ -565,11 +565,11 @@ class Dumper(DumperBase): with OutputSafer(self): self.anonNumber = -1 - type = value.type.unqualified() - typeName = str(type) + typeobj = value.type.unqualified() + typeName = str(typeobj) # Special handling for char** argv. - if type.code == PointerCode \ + if typeobj.code == PointerCode \ and item.iname == "local.argv" \ and typeName == "char **": n = 0 @@ -616,13 +616,14 @@ class Dumper(DumperBase): self.output.append('],typeinfo=[') for name in self.typesToReport.keys(): - type = self.typesToReport[name] + typeobj = self.typesToReport[name] # Happens e.g. for '(anonymous namespace)::InsertDefOperation' - if not type is None: + if not typeobj is None: self.output.append('{name="%s",size="%s"}' - % (self.hexencode(name), type.sizeof)) + % (self.hexencode(name), typeobj.sizeof)) self.output.append(']') self.typesToReport = {} + return "".join(self.output) def enterSubItem(self, item): @@ -946,11 +947,9 @@ class Dumper(DumperBase): return struct.unpack("q", self.readRawMemory(addr, 8))[0] def extractInt(self, addr): - #return long(gdb.Value(addr).cast(self.intPtrType()).dereference()) return struct.unpack("i", self.readRawMemory(addr, 4))[0] def extractByte(self, addr): - #return long(gdb.Value(addr).cast(self.charPtrType()).dereference()) & 0xFF return struct.unpack("b", self.readRawMemory(addr, 1))[0] # Do not use value.address here as this might not have one, @@ -1429,6 +1428,19 @@ class Dumper(DumperBase): with Children(self): self.putFields(value) + def toBlob(self, value): + size = toInteger(value.type.sizeof) + if value.address: + return self.extractBlob(value.address, size) + + # No address. Possibly the result of an inferior call. + y = value.cast(gdb.lookup_type("unsigned char").array(0, int(size - 1))) + buf = bytearray(struct.pack('x' * size)) + for i in range(size): + buf[i] = int(y[i]) + + return Blob(bytes(buf)) + def extractBlob(self, base, size): inferior = self.selectedInferior() return Blob(inferior.read_memory(base, size)) diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index 5e6b96b128..55065c0b84 100644 --- a/share/qtcreator/debugger/qttypes.py +++ b/share/qtcreator/debugger/qttypes.py @@ -1964,43 +1964,40 @@ def qdump__QUrl(d, value): d.putGenericItem("query", stringType, query, Hex4EncodedLittleEndian) d.putGenericItem("fragment", stringType, fragment, Hex4EncodedLittleEndian) -def qdumpHelper_QVariant_0(d, data): +def qdumpHelper_QVariant_0(d, blob): # QVariant::Invalid d.putBetterType("%sQVariant (invalid)" % d.qtNamespace()) d.putValue("(invalid)") -def qdumpHelper_QVariant_1(d, data): +def qdumpHelper_QVariant_1(d, blob): # QVariant::Bool d.putBetterType("%sQVariant (bool)" % d.qtNamespace()) - if int(data["b"]): - d.putValue("true") - else: - d.putValue("false") + d.putValue("true" if blob.extractByte() else "false") -def qdumpHelper_QVariant_2(d, data): +def qdumpHelper_QVariant_2(d, blob): # QVariant::Int d.putBetterType("%sQVariant (int)" % d.qtNamespace()) - d.putValue(int(data["i"])) + d.putValue("%s" % blob.extractInt()) -def qdumpHelper_QVariant_3(d, data): +def qdumpHelper_QVariant_3(d, blob): # uint d.putBetterType("%sQVariant (uint)" % d.qtNamespace()) - d.putValue(int(data["u"])) + d.putValue(blob.extractUInt()) -def qdumpHelper_QVariant_4(d, data): +def qdumpHelper_QVariant_4(d, blob): # qlonglong d.putBetterType("%sQVariant (qlonglong)" % d.qtNamespace()) - d.putValue(int(data["ll"])) + d.putValue(blob.extractInt64()) -def qdumpHelper_QVariant_5(d, data): +def qdumpHelper_QVariant_5(d, blob): # qulonglong d.putBetterType("%sQVariant (qulonglong)" % d.qtNamespace()) - d.putValue(int(data["ull"])) + d.putValue(blob.extractUInt64()) -def qdumpHelper_QVariant_6(d, data): +def qdumpHelper_QVariant_6(d, blob): # QVariant::Double d.putBetterType("%sQVariant (double)" % d.qtNamespace()) - d.putValue(float(data["d"])) + d.putValue(blob.extractDouble()) qdumpHelper_QVariants_A = [ qdumpHelper_QVariant_0, @@ -2038,45 +2035,45 @@ qdumpHelper_QVariants_B = [ "QVariantHash",# 28 ] -def qdumpHelper_QVariant_31(d, data): +def qdumpHelper_QVariant_31(d, blob): # QVariant::VoidStart d.putBetterType("%sQVariant (void *)" % d.qtNamespace()) - d.putValue("0x%x" % data["ptr"]) + d.putValue("0x%x" % blob.extractPointer()) -def qdumpHelper_QVariant_32(d, data): +def qdumpHelper_QVariant_32(d, blob): # QVariant::Long d.putBetterType("%sQVariant (long)" % d.qtNamespace()) - d.putValue(toInteger(data["l"])) + d.putValue("%s" % blob.extractLong()) -def qdumpHelper_QVariant_33(d, data): +def qdumpHelper_QVariant_33(d, blob): # QVariant::Short d.putBetterType("%sQVariant (short)" % d.qtNamespace()) - d.putValue(toInteger(data["s"])) + d.putValue("%s" % blob.extractShort()) -def qdumpHelper_QVariant_34(d, data): +def qdumpHelper_QVariant_34(d, blob): # QVariant::Char d.putBetterType("%sQVariant (char)" % d.qtNamespace()) - d.putValue(toInteger(data["c"])) + d.putValue("%s" % blob.extractByte()) -def qdumpHelper_QVariant_35(d, data): +def qdumpHelper_QVariant_35(d, blob): # QVariant::ULong d.putBetterType("%sQVariant (unsigned long)" % d.qtNamespace()) - d.putValue(toInteger(data["ul"])) + d.putValue("%s" % blob.extractULong()) -def qdumpHelper_QVariant_36(d, data): +def qdumpHelper_QVariant_36(d, blob): # QVariant::UShort d.putBetterType("%sQVariant (unsigned short)" % d.qtNamespace()) - d.putValue(toInteger(data["us"])) + d.putValue("%s" % blob.extractUShort()) -def qdumpHelper_QVariant_37(d, data): +def qdumpHelper_QVariant_37(d, blob): # QVariant::UChar d.putBetterType("%sQVariant (unsigned char)" % d.qtNamespace()) - d.putValue(toInteger(data["uc"])) + d.putValue("%s" % blob.extractByte()) -def qdumpHelper_QVariant_38(d, data): +def qdumpHelper_QVariant_38(d, blob): # QVariant::Float d.putBetterType("%sQVariant (float)" % d.qtNamespace()) - d.putValue("%f" % data["f"]) + d.putValue("%s" % blob.extractFloat()) qdumpHelper_QVariants_D = [ qdumpHelper_QVariant_31, @@ -2118,16 +2115,17 @@ qdumpHelper_QVariants_E = [ def qdumpHelper__QVariant(d, value): data = value["d"]["data"] variantType = int(value["d"]["type"]) + blob = d.toBlob(data) #warn("VARIANT TYPE: %s : " % variantType) # Well-known simple type. if variantType <= 6: - qdumpHelper_QVariants_A[variantType](d, data) + qdumpHelper_QVariants_A[variantType](d, blob) d.putNumChild(0) return (None, None, True) if variantType >= 31 and variantType <= 38: - qdumpHelper_QVariants_D[variantType - 31](d, data) + qdumpHelper_QVariants_D[variantType - 31](d, blob) d.putNumChild(0) return (None, None, True) @@ -2147,6 +2145,7 @@ def qdumpHelper__QVariant(d, value): sizePD = 8 # sizeof(QVariant::Private::Data) isSpecial = d.qtVersion() >= 0x050000 \ and (innert == "QVariantMap" or innert == "QVariantHash") + #warn("IS SPECIAL: %s" % special) if innerType.sizeof > sizePD or isSpecial: val = data["ptr"].cast(innerType.pointer().pointer()).dereference().dereference() else: diff --git a/tests/manual/debugger/simple/simple_test_app.cpp b/tests/manual/debugger/simple/simple_test_app.cpp index 18f3506a5c..58f6621974 100644 --- a/tests/manual/debugger/simple/simple_test_app.cpp +++ b/tests/manual/debugger/simple/simple_test_app.cpp @@ -4527,12 +4527,7 @@ namespace qvariant { BREAK_HERE; // Check vm <0 items> QVariantMap. // Continue. - vm["a"] = QVariant(1); - vm["b"] = QVariant(2); - vm["c"] = QVariant("Some String"); - vm["d"] = QVariant(21); - vm["e"] = QVariant(22); - vm["f"] = QVariant("2Some String"); + vm["abd"] = QVariant(1); BREAK_HERE; // Expand vm vm.0 vm.5. // Check vm <6 items> QVariantMap. -- GitLab