forked from qt-creator/qt-creator
Debugger: Re-work bridges
The type cache has been split into smaller caches for individual aspects. Type ids are now integral, not strings. In addition, there is new supporting code for logging, timing and profiling Change-Id: I6db72a149650d42aecf8b899869c542b1303d43b Reviewed-by: David Schulz <david.schulz@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -75,6 +75,13 @@ class Dumper(DumperBase):
|
||||
self.outputLock = threading.Lock()
|
||||
self.isCdb = True
|
||||
|
||||
#FIXME
|
||||
typeid = self.typeid_for_string('@QVariantMap')
|
||||
del self.type_code_cache[typeid]
|
||||
del self.type_target_cache[typeid]
|
||||
del self.type_size_cache[typeid]
|
||||
del self.type_alignment_cache[typeid]
|
||||
|
||||
def enumValue(self, nativeValue):
|
||||
val = nativeValue.nativeDebuggerValue()
|
||||
# remove '0n' decimal prefix of the native cdb value output
|
||||
@@ -117,6 +124,7 @@ class Dumper(DumperBase):
|
||||
elif not nativeValue.type().resolved and nativeValue.type().code() == TypeCode.Struct and not nativeValue.hasChildren():
|
||||
val.ldisplay = self.enumValue(nativeValue)
|
||||
val.isBaseClass = val.name == nativeValue.type().name()
|
||||
val.typeid = self.from_native_type(nativeValue.type())
|
||||
val.nativeValue = nativeValue
|
||||
val.laddress = nativeValue.address()
|
||||
val.lbitsize = nativeValue.bitsize()
|
||||
@@ -137,14 +145,10 @@ class Dumper(DumperBase):
|
||||
for f in nativeType.fields()])
|
||||
return typeId
|
||||
|
||||
def nativeValueType(self, nativeValue):
|
||||
return self.fromNativeType(nativeValue.type())
|
||||
|
||||
def fromNativeType(self, nativeType):
|
||||
def from_native_type(self, nativeType):
|
||||
self.check(isinstance(nativeType, cdbext.Type))
|
||||
typeId = self.nativeTypeId(nativeType)
|
||||
if self.typeData.get(typeId, None) is not None:
|
||||
return self.Type(self, typeId)
|
||||
typeid = self.typeid_for_string(self.nativeTypeId(nativeType))
|
||||
self.type_nativetype_cache[typeid] = nativeType
|
||||
|
||||
if nativeType.name().startswith('void'):
|
||||
nativeType = FakeVoidType(nativeType.name(), self)
|
||||
@@ -154,70 +158,61 @@ class Dumper(DumperBase):
|
||||
if nativeType.name().startswith('<function>'):
|
||||
code = TypeCode.Function
|
||||
elif nativeType.targetName() != nativeType.name():
|
||||
return self.createPointerType(nativeType.targetName())
|
||||
return self.create_pointer_typeid(self.typeid_for_string(nativeType.targetName()))
|
||||
|
||||
if code == TypeCode.Array:
|
||||
# cdb reports virtual function tables as arrays those ar handled separetly by
|
||||
# the DumperBase. Declare those types as structs prevents a lookup to a
|
||||
# none existing type
|
||||
if not nativeType.name().startswith('__fptr()') and not nativeType.name().startswith('<gentype '):
|
||||
targetName = nativeType.targetName()
|
||||
count = nativeType.arrayElements()
|
||||
if targetName.endswith(']'):
|
||||
(prefix, suffix, inner_count) = self.splitArrayType(targetName)
|
||||
type_name = '%s[%d][%d]%s' % (prefix, count, inner_count, suffix)
|
||||
else:
|
||||
type_name = '%s[%d]' % (targetName, count)
|
||||
tdata = self.TypeData(self, typeId)
|
||||
tdata.name = type_name
|
||||
tdata.code = TypeCode.Array
|
||||
tdata.ltarget = targetName
|
||||
tdata.lbitsize = lambda: nativeType.bitsize()
|
||||
return self.Type(self, typeId)
|
||||
targetName = nativeType.targetName().strip()
|
||||
self.type_name_cache[typeid] = nativeType.name()
|
||||
self.type_code_cache[typeid] = code
|
||||
self.type_target_cache[typeid] = self.typeid_for_string(targetName)
|
||||
self.type_size_cache[typeid] = nativeType.bitsize() // 8
|
||||
return typeid
|
||||
|
||||
code = TypeCode.Struct
|
||||
|
||||
tdata = self.TypeData(self, typeId)
|
||||
tdata.name = nativeType.name()
|
||||
tdata.lbitsize = lambda: nativeType.bitsize()
|
||||
tdata.code = code
|
||||
tdata.moduleName = lambda: nativeType.module()
|
||||
if code == TypeCode.Struct:
|
||||
tdata.lfields = lambda value: \
|
||||
self.listFields(nativeType, value)
|
||||
tdata.lalignment = lambda: \
|
||||
self.nativeStructAlignment(nativeType)
|
||||
tdata.enumDisplay = lambda intval, addr, form: \
|
||||
self.type_name_cache[typeid] = nativeType.name()
|
||||
self.type_size_cache[typeid] = nativeType.bitsize() // 8
|
||||
self.type_code_cache[typeid] = code
|
||||
self.type_modulename_cache[typeid] = nativeType.module()
|
||||
self.type_enum_display_cache[typeid] = lambda intval, addr, form: \
|
||||
self.nativeTypeEnumDisplay(nativeType, intval, form)
|
||||
tdata.templateArguments = lambda: \
|
||||
self.listTemplateParameters(nativeType.name())
|
||||
return self.Type(self, typeId)
|
||||
return typeid
|
||||
|
||||
def listNativeValueChildren(self, nativeValue):
|
||||
def listNativeValueChildren(self, nativeValue, include_bases):
|
||||
fields = []
|
||||
index = 0
|
||||
nativeMember = nativeValue.childFromIndex(index)
|
||||
while nativeMember:
|
||||
# Why this restriction to things with address? Can't nativeValue
|
||||
# be e.g. located in registers, without address?
|
||||
if nativeMember.address() != 0:
|
||||
yield self.fromNativeValue(nativeMember)
|
||||
if include_bases or nativeMember.name() != nativeMember.type().name():
|
||||
field = self.fromNativeValue(nativeMember)
|
||||
fields.append(field)
|
||||
index += 1
|
||||
nativeMember = nativeValue.childFromIndex(index)
|
||||
return fields
|
||||
|
||||
def listValueChildren(self, value):
|
||||
def listValueChildren(self, value, include_bases=True):
|
||||
nativeValue = value.nativeValue
|
||||
if nativeValue is None:
|
||||
nativeValue = cdbext.createValue(value.address(), self.lookupNativeType(value.type.name, 0))
|
||||
return self.listNativeValueChildren(nativeValue)
|
||||
return self.listNativeValueChildren(nativeValue, include_bases)
|
||||
|
||||
def listFields(self, nativeType, value):
|
||||
def nativeListMembers(self, value, native_type, include_bases):
|
||||
nativeValue = value.nativeValue
|
||||
if nativeValue is None:
|
||||
nativeValue = cdbext.createValue(value.address(), nativeType)
|
||||
return self.listNativeValueChildren(nativeValue)
|
||||
nativeValue = cdbext.createValue(value.address(), native_type)
|
||||
return self.listNativeValueChildren(nativeValue, include_bases)
|
||||
|
||||
def nativeStructAlignment(self, nativeType):
|
||||
#DumperBase.warn("NATIVE ALIGN FOR %s" % nativeType.name)
|
||||
def handleItem(nativeFieldType, align):
|
||||
a = self.fromNativeType(nativeFieldType).alignment()
|
||||
a = self.type_alignment(self.from_native_type(nativeFieldType))
|
||||
return a if a > align else align
|
||||
align = 1
|
||||
for f in nativeType.fields():
|
||||
@@ -398,20 +393,6 @@ class Dumper(DumperBase):
|
||||
else:
|
||||
return typeName
|
||||
|
||||
def lookupType(self, typeNameIn, module=0):
|
||||
if len(typeNameIn) == 0:
|
||||
return None
|
||||
typeName = self.stripQintTypedefs(typeNameIn)
|
||||
if self.typeData.get(typeName, None) is None:
|
||||
nativeType = self.lookupNativeType(typeName, module)
|
||||
if nativeType is None:
|
||||
return None
|
||||
_type = self.fromNativeType(nativeType)
|
||||
if _type.typeId != typeName:
|
||||
self.registerTypeAlias(_type.typeId, typeName)
|
||||
return _type
|
||||
return self.Type(self, typeName)
|
||||
|
||||
def lookupNativeType(self, name, module=0):
|
||||
if name.startswith('void'):
|
||||
return FakeVoidType(name, self)
|
||||
@@ -439,9 +420,6 @@ class Dumper(DumperBase):
|
||||
ptr = cdbext.getAddressByName(type.name + '::staticMetaObject')
|
||||
return ptr
|
||||
|
||||
def warn(self, msg):
|
||||
self.put('{name="%s",value="",type="",numchild="0"},' % msg)
|
||||
|
||||
def fetchVariables(self, args):
|
||||
self.resetStats()
|
||||
(ok, res) = self.tryFetchInterpreterVariables(args)
|
||||
@@ -458,6 +436,7 @@ class Dumper(DumperBase):
|
||||
self.anonNumber = 0
|
||||
|
||||
variables = []
|
||||
try:
|
||||
for val in cdbext.listOfLocals(self.partialVariable):
|
||||
dumperVal = self.fromNativeValue(val)
|
||||
dumperVal.lIsInScope = dumperVal.name not in self.uninitialized
|
||||
@@ -465,6 +444,9 @@ class Dumper(DumperBase):
|
||||
|
||||
self.handleLocals(variables)
|
||||
self.handleWatches(args)
|
||||
except Exception:
|
||||
t,v,tb = sys.exc_info()
|
||||
self.showException("FETCH VARIABLES", t, v, tb)
|
||||
|
||||
self.put('],partial="%d"' % (len(self.partialVariable) > 0))
|
||||
self.put(',timings=%s' % self.timings)
|
||||
@@ -485,9 +467,6 @@ class Dumper(DumperBase):
|
||||
def findValueByExpression(self, exp):
|
||||
return cdbext.parseAndEvaluate(exp)
|
||||
|
||||
def nativeDynamicTypeName(self, address, baseType):
|
||||
return None # Does not work with cdb
|
||||
|
||||
def nativeValueDereferenceReference(self, value):
|
||||
return self.nativeValueDereferencePointer(value)
|
||||
|
||||
@@ -518,7 +497,7 @@ class Dumper(DumperBase):
|
||||
else:
|
||||
val = self.Value(self)
|
||||
val.laddress = value.pointer()
|
||||
val._type = DumperBase.Type(self, value.type.targetName)
|
||||
val.typeid = self.typeid_for_string(value.type.targetName)
|
||||
val.nativeValue = value.nativeValue
|
||||
|
||||
return val
|
||||
@@ -540,14 +519,11 @@ class Dumper(DumperBase):
|
||||
res = self.nativeParseAndEvaluate(symbolName)
|
||||
return None if res is None else res.address()
|
||||
|
||||
def putItemX(self, value):
|
||||
#DumperBase.warn('PUT ITEM: %s' % value.stringify())
|
||||
def putItem(self, value: DumperBase.Value):
|
||||
|
||||
typeobj = value.type # unqualified()
|
||||
typeName = typeobj.name
|
||||
|
||||
self.addToCache(typeobj) # Fill type cache
|
||||
|
||||
if not value.lIsInScope:
|
||||
self.putSpecialValue('optimizedout')
|
||||
#self.putType(typeobj)
|
||||
@@ -571,8 +547,7 @@ class Dumper(DumperBase):
|
||||
return
|
||||
|
||||
self.putAddress(value.address())
|
||||
if value.lbitsize is not None:
|
||||
self.putField('size', value.lbitsize // 8)
|
||||
self.putField('size', self.type_size(value.typeid))
|
||||
|
||||
if typeobj.code == TypeCode.Function:
|
||||
#DumperBase.warn('FUNCTION VALUE: %s' % value)
|
||||
@@ -738,7 +713,7 @@ class Dumper(DumperBase):
|
||||
#DumperBase.warn('INAME: %s' % self.currentIName)
|
||||
if self.autoDerefPointers:
|
||||
# Generic pointer type with AutomaticFormat, but never dereference char types:
|
||||
if value.type.targetName not in (
|
||||
if value.type.targetName.strip() not in (
|
||||
'char',
|
||||
'signed char',
|
||||
'int8_t',
|
||||
@@ -769,7 +744,7 @@ class Dumper(DumperBase):
|
||||
|
||||
def putCStyleArray(self, value):
|
||||
arrayType = value.type
|
||||
innerType = arrayType.ltarget
|
||||
innerType = arrayType.target()
|
||||
address = value.address()
|
||||
if address:
|
||||
self.putValue('@0x%x' % address, priority=-1)
|
||||
@@ -783,7 +758,7 @@ class Dumper(DumperBase):
|
||||
|
||||
p = value.address()
|
||||
if displayFormat != DisplayFormat.Raw and p:
|
||||
if innerType.name in (
|
||||
if innerType.name.strip() in (
|
||||
'char',
|
||||
'int8_t',
|
||||
'qint8',
|
||||
@@ -828,7 +803,7 @@ class Dumper(DumperBase):
|
||||
innerSize = innerType.size()
|
||||
self.putNumChild(n)
|
||||
#DumperBase.warn('ADDRESS: 0x%x INNERSIZE: %s INNERTYPE: %s' % (addrBase, innerSize, innerType))
|
||||
enc = innerType.simpleEncoding()
|
||||
enc = self.type_encoding_cache.get(innerType.typeid, None)
|
||||
maxNumChild = self.maxArrayCount()
|
||||
if enc:
|
||||
self.put('childtype="%s",' % innerType.name)
|
||||
@@ -863,12 +838,8 @@ class Dumper(DumperBase):
|
||||
|
||||
if innerType in ('wchar_t', 'WCHAR'):
|
||||
self.putType(typeName)
|
||||
charSize = self.lookupType('wchar_t').size()
|
||||
(length, data) = self.encodeCArray(ptr, charSize, limit)
|
||||
if charSize == 2:
|
||||
(length, data) = self.encodeCArray(ptr, 2, limit)
|
||||
self.putValue(data, 'utf16', length=length)
|
||||
else:
|
||||
self.putValue(data, 'ucs4', length=length)
|
||||
return True
|
||||
|
||||
if displayFormat == DisplayFormat.Latin1String:
|
||||
@@ -931,19 +902,12 @@ class Dumper(DumperBase):
|
||||
self.putItem(derefValue)
|
||||
self.currentChildType = savedCurrentChildType
|
||||
|
||||
def extractPointer(self, value):
|
||||
code = 'I' if self.ptrSize() == 4 else 'Q'
|
||||
return self.extractSomething(value, code, 8 * self.ptrSize())
|
||||
|
||||
def createValue(self, datish, typish):
|
||||
if self.isInt(datish): # Used as address.
|
||||
if isinstance(datish, int): # Used as address.
|
||||
return self.createValueFromAddressAndType(datish, typish)
|
||||
if isinstance(datish, bytes):
|
||||
val = self.Value(self)
|
||||
if isinstance(typish, self.Type):
|
||||
val._type = typish
|
||||
else:
|
||||
val._type = self.Type(self, typish)
|
||||
val.typeid = self.create_typeid(typish)
|
||||
#DumperBase.warn('CREATING %s WITH DATA %s' % (val.type.name, self.hexencode(datish)))
|
||||
val.ldata = datish
|
||||
val.check()
|
||||
@@ -952,11 +916,8 @@ class Dumper(DumperBase):
|
||||
|
||||
def createValueFromAddressAndType(self, address, typish):
|
||||
val = self.Value(self)
|
||||
if isinstance(typish, self.Type):
|
||||
val._type = typish
|
||||
else:
|
||||
val._type = self.Type(self, typish)
|
||||
val.typeid = self.create_typeid(typish)
|
||||
val.laddress = address
|
||||
if self.useDynamicType:
|
||||
val._type = val.type.dynamicType(address)
|
||||
val.typeid = self.dynamic_typeid_at_address(val.typeid, address)
|
||||
return val
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -10,11 +10,10 @@ import gdb
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
import sys
|
||||
import struct
|
||||
import tempfile
|
||||
|
||||
from dumper import DumperBase, Children, toInteger, TopLevelItem
|
||||
from dumper import DumperBase, Children, TopLevelItem
|
||||
from utils import TypeCode
|
||||
from gdbtracepoint import *
|
||||
|
||||
@@ -119,7 +118,6 @@ ScanStackCommand()
|
||||
class PlainDumper():
|
||||
def __init__(self, printer):
|
||||
self.printer = printer
|
||||
self.typeCache = {}
|
||||
|
||||
def __call__(self, d, value):
|
||||
if value.nativeValue is None:
|
||||
@@ -137,8 +135,6 @@ class PlainDumper():
|
||||
if isinstance(val, str):
|
||||
# encode and avoid extra quotes ('"') at beginning and end
|
||||
d.putValue(d.hexencode(val), 'utf8:1:0')
|
||||
elif sys.version_info[0] <= 2 and isinstance(val, unicode):
|
||||
d.putValue(val)
|
||||
elif val is not None: # Assuming LazyString
|
||||
d.putCharArrayValue(val.address, val.length,
|
||||
val.type.target().sizeof)
|
||||
@@ -166,7 +162,7 @@ def importPlainDumpers(args):
|
||||
gdb.execute('disable pretty-printer .* .*')
|
||||
except:
|
||||
# Might occur in non-ASCII directories
|
||||
DumperBase.warn('COULD NOT DISABLE PRETTY PRINTERS')
|
||||
theDumper.warn('COULD NOT DISABLE PRETTY PRINTERS')
|
||||
else:
|
||||
theDumper.usePlainDumpers = True
|
||||
theDumper.importPlainDumpers()
|
||||
@@ -192,15 +188,17 @@ class Dumper(DumperBase):
|
||||
|
||||
# These values will be kept between calls to 'fetchVariables'.
|
||||
self.isGdb = True
|
||||
self.typeCache = {}
|
||||
self.interpreterBreakpointResolvers = []
|
||||
|
||||
def warn(self, message):
|
||||
print('bridgemessage={msg="%s"},' % message.replace('"', '$').encode('latin1'))
|
||||
|
||||
def prepare(self, args):
|
||||
self.output = []
|
||||
self.setVariableFetchingOptions(args)
|
||||
|
||||
def fromFrameValue(self, nativeValue):
|
||||
#DumperBase.warn('FROM FRAME VALUE: %s' % nativeValue.address)
|
||||
#self.warn('FROM FRAME VALUE: %s' % nativeValue.address)
|
||||
val = nativeValue
|
||||
if self.useDynamicType:
|
||||
try:
|
||||
@@ -209,71 +207,43 @@ class Dumper(DumperBase):
|
||||
pass
|
||||
return self.fromNativeValue(val)
|
||||
|
||||
def nativeValueType(self, nativeValue):
|
||||
return self.fromNativeType(nativeValue.type)
|
||||
|
||||
def fromNativeValue(self, nativeValue):
|
||||
#DumperBase.warn('FROM NATIVE VALUE: %s' % nativeValue)
|
||||
#self.warn('FROM NATIVE VALUE: %s' % nativeValue)
|
||||
self.check(isinstance(nativeValue, gdb.Value))
|
||||
nativeType = nativeValue.type
|
||||
code = nativeType.code
|
||||
|
||||
val = self.Value(self)
|
||||
val.nativeValue = nativeValue
|
||||
|
||||
if code == gdb.TYPE_CODE_REF:
|
||||
targetType = self.fromNativeType(nativeType.target().unqualified())
|
||||
val = self.createReferenceValue(toInteger(nativeValue.address), targetType)
|
||||
val.nativeValue = nativeValue
|
||||
#DumperBase.warn('CREATED REF: %s' % val)
|
||||
target_typeid = self.from_native_type(nativeType.target().unqualified())
|
||||
val.ldata = int(nativeValue.address)
|
||||
if self.useDynamicType: # needed for Gdb13393
|
||||
target_typeid = self.dynamic_typeid_at_address(target_typeid, val.ldata)
|
||||
val.typeid = self.create_reference_typeid(target_typeid)
|
||||
#self.warn('CREATED REF: %s' % val)
|
||||
return val
|
||||
|
||||
if code == gdb.TYPE_CODE_PTR:
|
||||
try:
|
||||
nativeTargetValue = nativeValue.dereference()
|
||||
except:
|
||||
nativeTargetValue = None
|
||||
targetType = self.fromNativeType(nativeType.target().unqualified())
|
||||
val = self.createPointerValue(toInteger(nativeValue), targetType)
|
||||
# The nativeValue is needed in case of multiple inheritance, see
|
||||
# QTCREATORBUG-17823. Using it triggers nativeValueDereferencePointer()
|
||||
# later which
|
||||
# is surprisingly expensive.
|
||||
val.nativeValue = nativeValue
|
||||
#DumperBase.warn('CREATED PTR 1: %s' % val)
|
||||
target_typeid = self.from_native_type(nativeType.target().unqualified())
|
||||
val.ldata = int(nativeValue)
|
||||
val.typeid = self.create_pointer_typeid(target_typeid)
|
||||
#self.warn('CREATED PTR 1: %s' % val)
|
||||
if nativeValue.address is not None:
|
||||
val.laddress = toInteger(nativeValue.address)
|
||||
#DumperBase.warn('CREATED PTR 2: %s' % val)
|
||||
val.laddress = int(nativeValue.address)
|
||||
#self.warn('CREATED PTR 2: %s' % val)
|
||||
return val
|
||||
if code == gdb.TYPE_CODE_TYPEDEF:
|
||||
targetType = nativeType.strip_typedefs().unqualified()
|
||||
#DumperBase.warn('TARGET TYPE: %s' % targetType)
|
||||
if targetType.code == gdb.TYPE_CODE_ARRAY:
|
||||
val = self.Value(self)
|
||||
else:
|
||||
try:
|
||||
# Cast may fail for arrays, for typedefs to __uint128_t with
|
||||
# gdb.error: That operation is not available on integers
|
||||
# of more than 8 bytes.
|
||||
# See test for Bug5799, QTCREATORBUG-18450.
|
||||
val = self.fromNativeValue(nativeValue.cast(targetType))
|
||||
except:
|
||||
val = self.Value(self)
|
||||
#DumperBase.warn('CREATED TYPEDEF: %s' % val)
|
||||
else:
|
||||
val = self.Value(self)
|
||||
|
||||
val.nativeValue = nativeValue
|
||||
if nativeValue.address is not None:
|
||||
val.laddress = toInteger(nativeValue.address)
|
||||
else:
|
||||
size = nativeType.sizeof
|
||||
chars = self.lookupNativeType('unsigned char')
|
||||
y = nativeValue.cast(chars.array(0, int(nativeType.sizeof - 1)))
|
||||
buf = bytearray(struct.pack('x' * size))
|
||||
for i in range(size):
|
||||
val.laddress = int(nativeValue.address)
|
||||
elif code == gdb.TYPE_CODE_STRUCT:
|
||||
try:
|
||||
buf[i] = int(y[i])
|
||||
val.ldata = nativeValue.bytes # GDB 15 only
|
||||
except:
|
||||
pass
|
||||
val.ldata = bytes(buf)
|
||||
val.ldata = self.nativeDataFromValueFallback(nativeValue, nativeValue.type.sizeof)
|
||||
|
||||
val._type = self.fromNativeType(nativeType)
|
||||
val.typeid = self.from_native_type(nativeType)
|
||||
val.lIsInScope = not nativeValue.is_optimized_out
|
||||
code = nativeType.code
|
||||
if code == gdb.TYPE_CODE_ENUM:
|
||||
@@ -283,10 +253,15 @@ class Dumper(DumperBase):
|
||||
val.ldisplay += ' (%s)' % intval
|
||||
elif code == gdb.TYPE_CODE_COMPLEX:
|
||||
val.ldisplay = str(nativeValue)
|
||||
elif code in [gdb.TYPE_CODE_BOOL, gdb.TYPE_CODE_INT]:
|
||||
elif code == gdb.TYPE_CODE_BOOL:
|
||||
# FIXME: why?
|
||||
# Using ldata breaks StdVariant test, not setting lvalue breaks the Bitfield[s2] test.
|
||||
val.lvalue = int(nativeValue)
|
||||
val.ldata = None
|
||||
elif code == gdb.TYPE_CODE_INT:
|
||||
try:
|
||||
# extract int presentation from native value and remember it
|
||||
val.lvalue = int(nativeValue)
|
||||
val.ldata = int(nativeValue)
|
||||
except:
|
||||
# GDB only support converting integers of max. 64 bits to Python int as of now
|
||||
pass
|
||||
@@ -294,65 +269,81 @@ class Dumper(DumperBase):
|
||||
# val.type.ltarget = nativeValue[0].type.unqualified()
|
||||
return val
|
||||
|
||||
def nativeDataFromValueFallback(self, nativeValue, size):
|
||||
chars = self.lookupNativeType('unsigned char')
|
||||
try:
|
||||
y = nativeValue.cast(chars.array(0, int(size - 1)))
|
||||
buf = bytearray(struct.pack('x' * size))
|
||||
for i in range(size):
|
||||
try:
|
||||
buf[i] = int(y[i])
|
||||
except:
|
||||
pass
|
||||
return bytes(buf)
|
||||
except:
|
||||
self.warn('VALUE EXTRACTION FAILED: VALUE: %s SIZE: %s' % (nativeValue, size))
|
||||
return None
|
||||
|
||||
def ptrSize(self):
|
||||
result = gdb.lookup_type('void').pointer().sizeof
|
||||
self.ptrSize = lambda: result
|
||||
return result
|
||||
|
||||
def fromNativeType(self, nativeType):
|
||||
def from_native_type(self, nativeType):
|
||||
self.check(isinstance(nativeType, gdb.Type))
|
||||
code = nativeType.code
|
||||
#DumperBase.warn('FROM NATIVE TYPE: %s' % nativeType)
|
||||
|
||||
#self.warn('FROM NATIVE TYPE: %s' % nativeType)
|
||||
nativeType = nativeType.unqualified()
|
||||
|
||||
typeid_str = self.native_type_key(nativeType)
|
||||
known_typeid = self.typeid_from_typekey.get(typeid_str, None)
|
||||
if known_typeid is not None:
|
||||
return known_typeid
|
||||
|
||||
code = nativeType.code
|
||||
|
||||
if code == gdb.TYPE_CODE_PTR:
|
||||
#DumperBase.warn('PTR')
|
||||
targetType = self.fromNativeType(nativeType.target().unqualified())
|
||||
return self.createPointerType(targetType)
|
||||
#self.warn('PTR')
|
||||
target_typeid = self.from_native_type(nativeType.target().unqualified())
|
||||
typeid = self.create_pointer_typeid(target_typeid)
|
||||
|
||||
if code == gdb.TYPE_CODE_REF:
|
||||
#DumperBase.warn('REF')
|
||||
targetType = self.fromNativeType(nativeType.target().unqualified())
|
||||
return self.createReferenceType(targetType)
|
||||
elif code == gdb.TYPE_CODE_REF:
|
||||
#self.warn('REF')
|
||||
target_typeid = self.from_native_type(nativeType.target().unqualified())
|
||||
typeid = self.create_reference_typeid(target_typeid)
|
||||
|
||||
if hasattr(gdb, "TYPE_CODE_RVALUE_REF"):
|
||||
if code == gdb.TYPE_CODE_RVALUE_REF:
|
||||
#DumperBase.warn('RVALUEREF')
|
||||
targetType = self.fromNativeType(nativeType.target())
|
||||
return self.createRValueReferenceType(targetType)
|
||||
elif code == gdb.TYPE_CODE_RVALUE_REF and hasattr(gdb, "TYPE_CODE_RVALUE_REF"):
|
||||
#self.warn('RVALUEREF')
|
||||
target_typeid = self.from_native_type(nativeType.target())
|
||||
typeid = self.create_rvalue_reference_typeid(target_typeid)
|
||||
|
||||
if code == gdb.TYPE_CODE_ARRAY:
|
||||
#DumperBase.warn('ARRAY')
|
||||
elif code == gdb.TYPE_CODE_ARRAY:
|
||||
#self.warn('ARRAY')
|
||||
nativeTargetType = nativeType.target().unqualified()
|
||||
targetType = self.fromNativeType(nativeTargetType)
|
||||
target_typeid = self.from_native_type(nativeTargetType)
|
||||
if nativeType.sizeof == 0:
|
||||
# QTCREATORBUG-23998, note that nativeType.name == None here,
|
||||
# whereas str(nativeType) returns sth like 'QObject [5]'
|
||||
count = self.arrayItemCountFromTypeName(str(nativeType), 1)
|
||||
else:
|
||||
count = nativeType.sizeof // nativeTargetType.sizeof
|
||||
return self.createArrayType(targetType, count)
|
||||
typeid = self.create_array_typeid(target_typeid, count)
|
||||
|
||||
if code == gdb.TYPE_CODE_TYPEDEF:
|
||||
#DumperBase.warn('TYPEDEF')
|
||||
elif code == gdb.TYPE_CODE_TYPEDEF:
|
||||
#self.warn('TYPEDEF')
|
||||
nativeTargetType = nativeType.unqualified()
|
||||
while nativeTargetType.code == gdb.TYPE_CODE_TYPEDEF:
|
||||
nativeTargetType = nativeTargetType.strip_typedefs().unqualified()
|
||||
targetType = self.fromNativeType(nativeTargetType)
|
||||
return self.createTypedefedType(targetType, str(nativeType),
|
||||
self.nativeTypeId(nativeType))
|
||||
target_typeid = self.from_native_type(nativeTargetType)
|
||||
typeid = self.create_typedefed_typeid(target_typeid, str(nativeType), typeid_str)
|
||||
|
||||
if code == gdb.TYPE_CODE_ERROR:
|
||||
elif code == gdb.TYPE_CODE_ERROR:
|
||||
self.warn('Type error: %s' % nativeType)
|
||||
return self.Type(self, '')
|
||||
typeid = 0 # the invalid id
|
||||
|
||||
typeId = self.nativeTypeId(nativeType)
|
||||
res = self.typeData.get(typeId, None)
|
||||
if res is None:
|
||||
tdata = self.TypeData(self, typeId)
|
||||
tdata.name = str(nativeType)
|
||||
tdata.lbitsize = nativeType.sizeof * 8
|
||||
tdata.code = {
|
||||
else:
|
||||
typeid = self.typeid_for_string(typeid_str)
|
||||
type_code = {
|
||||
#gdb.TYPE_CODE_TYPEDEF : TypeCode.Typedef, # Handled above.
|
||||
gdb.TYPE_CODE_METHOD: TypeCode.Function,
|
||||
gdb.TYPE_CODE_VOID: TypeCode.Void,
|
||||
@@ -372,38 +363,60 @@ class Dumper(DumperBase):
|
||||
gdb.TYPE_CODE_COMPLEX: TypeCode.Complex,
|
||||
gdb.TYPE_CODE_STRING: TypeCode.FortranString,
|
||||
}[code]
|
||||
if tdata.code == TypeCode.Enum:
|
||||
tdata.enumDisplay = lambda intval, addr, form: \
|
||||
self.nativeTypeEnumDisplay(nativeType, intval, form)
|
||||
if tdata.code == TypeCode.Struct:
|
||||
tdata.lalignment = lambda: \
|
||||
self.nativeStructAlignment(nativeType)
|
||||
tdata.lfields = lambda value: \
|
||||
self.listMembers(value, nativeType)
|
||||
tdata.templateArguments = lambda: \
|
||||
self.listTemplateParameters(nativeType)
|
||||
# warn('CREATE TYPE: %s' % typeId)
|
||||
#else:
|
||||
# warn('REUSE TYPE: %s' % typeId)
|
||||
return self.Type(self, typeId)
|
||||
self.type_name_cache[typeid] = str(nativeType)
|
||||
self.type_size_cache[typeid] = nativeType.sizeof
|
||||
self.type_code_cache[typeid] = type_code
|
||||
self.type_nativetype_cache[typeid] = nativeType
|
||||
|
||||
def listTemplateParameters(self, nativeType):
|
||||
targs = []
|
||||
pos = 0
|
||||
while True:
|
||||
if type_code == TypeCode.Enum:
|
||||
self.type_enum_display_cache[typeid] = lambda intval, addr, form: \
|
||||
self.nativeTypeEnumDisplay(nativeType, intval, form)
|
||||
|
||||
self.type_nativetype_cache[typeid] = nativeType
|
||||
|
||||
# FIXME: Field offset caching (or later extraction?) broken
|
||||
# if code == gdb.TYPE_CODE_STRUCT:
|
||||
# field_type_name = self.type_name_cache.get(typeid, '')
|
||||
# #self.warn("CACHING FIELDS OF %s '%s'" % (typeid, field_type_name))
|
||||
# try:
|
||||
# fields = nativeType.fields()
|
||||
# #self.warn("FOUND FIELDS %s" % fields)
|
||||
# except:
|
||||
# #self.warn("NO FIELDS IN %s '%s'" % (typeid, field_type_name))
|
||||
# fields = []
|
||||
# for nativeField in fields:
|
||||
# field_name = nativeField.name
|
||||
# if field_name.startswith('std::allocator'):
|
||||
# continue
|
||||
# field_bitpos = nativeField.bitpos
|
||||
# field_typeid = self.typeid_for_string(str(nativeType))
|
||||
# field_size = nativeField.type.sizeof
|
||||
# #self.warn("CACHING '%s' OF %s AT BITPOS %s SIZE %s" %
|
||||
# # (field_name, typeid, field_bitpos, field_size))
|
||||
# self.type_fields_cache[(typeid, field_name)] = self.Field(
|
||||
# name=field_name,
|
||||
# typeid=field_typeid,
|
||||
# bitpos=field_bitpos,
|
||||
# bitsize=field_size * 8
|
||||
# )
|
||||
# pass
|
||||
|
||||
|
||||
#self.warn("FROM NATIVE TYPE: %s %s %s" % (typeid, id(nativeType), nativeType))
|
||||
self.typeid_from_typekey[str(nativeType)] = typeid
|
||||
|
||||
return typeid
|
||||
|
||||
def nativeTemplateParameter(self, typeid, index, nativeType):
|
||||
try:
|
||||
targ = nativeType.template_argument(pos)
|
||||
targ = nativeType.template_argument(index)
|
||||
except:
|
||||
break
|
||||
return None
|
||||
if isinstance(targ, gdb.Type):
|
||||
targs.append(self.fromNativeType(targ.unqualified()))
|
||||
elif isinstance(targ, gdb.Value):
|
||||
targs.append(self.fromNativeValue(targ).value())
|
||||
else:
|
||||
return self.Type(self, self.from_native_type(targ.unqualified()))
|
||||
if isinstance(targ, gdb.Value):
|
||||
return self.fromNativeValue(targ).value()
|
||||
raise RuntimeError('UNKNOWN TEMPLATE PARAMETER')
|
||||
pos += 1
|
||||
targs2 = self.listTemplateParametersManually(str(nativeType))
|
||||
return targs if len(targs) >= len(targs2) else targs2
|
||||
|
||||
def nativeTypeEnumDisplay(self, nativeType, intval, form):
|
||||
try:
|
||||
@@ -432,7 +445,7 @@ class Dumper(DumperBase):
|
||||
pass
|
||||
return form % intval
|
||||
|
||||
def nativeTypeId(self, nativeType):
|
||||
def native_type_key(self, nativeType):
|
||||
if nativeType and (nativeType.code == gdb.TYPE_CODE_TYPEDEF):
|
||||
return '%s{%s}' % (nativeType, nativeType.strip_typedefs())
|
||||
name = str(nativeType)
|
||||
@@ -444,133 +457,106 @@ class Dumper(DumperBase):
|
||||
c = 's'
|
||||
else:
|
||||
return name
|
||||
typeId = c + ''.join(['{%s:%s}' % (f.name, self.nativeTypeId(f.type))
|
||||
id_str = c + ''.join(['{%s:%s}' %
|
||||
(f.name, self.typeid_for_string(self.native_type_key(f.type)))
|
||||
for f in nativeType.fields()])
|
||||
return typeId
|
||||
#self.warn("NATIVE TYPE KEY: %s" % id_str)
|
||||
return id_str
|
||||
|
||||
def nativeStructAlignment(self, nativeType):
|
||||
#DumperBase.warn('NATIVE ALIGN FOR %s' % nativeType.name)
|
||||
def handleItem(nativeFieldType, align):
|
||||
a = self.fromNativeType(nativeFieldType).alignment()
|
||||
return a if a > align else align
|
||||
align = 1
|
||||
for f in nativeType.fields():
|
||||
align = handleItem(f.type, align)
|
||||
return align
|
||||
|
||||
#except:
|
||||
# # Happens in the BoostList dumper for a 'const bool'
|
||||
# # item named 'constant_time_size'. There isn't anything we can do
|
||||
# # in this case.
|
||||
# pass
|
||||
|
||||
#yield value.extractField(field)
|
||||
|
||||
def memberFromNativeFieldAndValue(self, nativeField, nativeValue, fieldName, value):
|
||||
nativeMember = self.nativeMemberFromField(nativeValue, nativeField)
|
||||
if nativeMember is None:
|
||||
val = self.Value(self)
|
||||
val.name = fieldName
|
||||
val._type = self.fromNativeType(nativeField.type)
|
||||
val.lIsInScope = False
|
||||
return val
|
||||
val = self.fromNativeValue(nativeMember)
|
||||
nativeFieldType = nativeField.type.unqualified()
|
||||
if nativeField.bitsize:
|
||||
val.lvalue = int(nativeMember)
|
||||
val.laddress = None
|
||||
fieldType = self.fromNativeType(nativeFieldType)
|
||||
val._type = self.createBitfieldType(fieldType, nativeField.bitsize)
|
||||
val.isBaseClass = nativeField.is_base_class
|
||||
val.name = fieldName
|
||||
return val
|
||||
|
||||
def nativeMemberFromField(self, nativeValue, nativeField):
|
||||
if nativeField.is_base_class:
|
||||
return nativeValue.cast(nativeField.type)
|
||||
try:
|
||||
return nativeValue[nativeField]
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
return nativeValue[nativeField.name]
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
|
||||
def listMembers(self, value, nativeType):
|
||||
def nativeListMembers(self, value, nativeType, include_base):
|
||||
nativeValue = value.nativeValue
|
||||
value_size = self.type_size(value.typeid)
|
||||
ldata = bytes(self.value_data(value, value_size))
|
||||
laddress = value.laddress
|
||||
|
||||
anonNumber = 0
|
||||
|
||||
#DumperBase.warn('LISTING FIELDS FOR %s' % nativeType)
|
||||
fields = []
|
||||
#self.warn('LISTING FIELDS FOR %s' % nativeType)
|
||||
for nativeField in nativeType.fields():
|
||||
fieldName = nativeField.name
|
||||
if not include_base and nativeField.is_base_class:
|
||||
continue
|
||||
|
||||
field_name = nativeField.name
|
||||
# Something without a name.
|
||||
# Anonymous union? We need a dummy name to distinguish
|
||||
# multiple anonymous unions in the struct.
|
||||
# Since GDB commit b5b08fb4 anonymous structs get also reported
|
||||
# with a 'None' name.
|
||||
if fieldName is None or len(fieldName) == 0:
|
||||
# Something without a name.
|
||||
# Anonymous union? We need a dummy name to distinguish
|
||||
# multiple anonymous unions in the struct.
|
||||
if field_name is None or len(field_name) == 0:
|
||||
anonNumber += 1
|
||||
fieldName = '#%s' % anonNumber
|
||||
#DumperBase.warn('FIELD: %s' % fieldName)
|
||||
field_name = '#%s' % anonNumber
|
||||
#self.warn('FIELD: %s' % field_name)
|
||||
|
||||
nativeFieldType = nativeField.type.unqualified()
|
||||
field_typeid = self.from_native_type(nativeFieldType)
|
||||
#self.warn(' TYPE: %s' % nativeFieldType)
|
||||
#self.warn(' TYPE KEY: %s' % self.native_type_key(nativeFieldType))
|
||||
|
||||
if nativeValue is not None:
|
||||
try:
|
||||
native_member = nativeValue[nativeField]
|
||||
except:
|
||||
self.warn(' COULD NOT ACCESS FIELD: %s' % nativeFieldType)
|
||||
continue
|
||||
|
||||
val = self.fromNativeValue(native_member)
|
||||
if nativeField.bitsize:
|
||||
val.lvalue = None
|
||||
val.ldata = int(native_member)
|
||||
val.laddress = None
|
||||
val.typeid = self.create_bitfield_typeid(field_typeid, nativeField.bitsize)
|
||||
val.isBaseClass = nativeField.is_base_class
|
||||
val.name = field_name
|
||||
fields.append(val)
|
||||
continue
|
||||
|
||||
# hasattr(nativeField, 'bitpos') == False indicates a static field,
|
||||
# but if we have access to a nativeValue .fromNativeField will
|
||||
# but if we have access to a nativeValue, so fromNativeField will
|
||||
# also succeed. We essentially skip only static members from
|
||||
# artificial values, like array members constructed from address.
|
||||
if hasattr(nativeField, 'bitpos') or nativeValue is not None:
|
||||
yield self.fromNativeField(nativeField, nativeValue, fieldName)
|
||||
if not hasattr(nativeField, 'bitpos'):
|
||||
continue
|
||||
|
||||
def fromNativeField(self, nativeField, nativeValue, fieldName):
|
||||
nativeFieldType = nativeField.type.unqualified()
|
||||
#DumperBase.warn(' TYPE: %s' % nativeFieldType)
|
||||
#DumperBase.warn(' TYPEID: %s' % self.nativeTypeId(nativeFieldType))
|
||||
|
||||
if hasattr(nativeField, 'bitpos'):
|
||||
bitpos = nativeField.bitpos
|
||||
else:
|
||||
bitpos = 0
|
||||
|
||||
if hasattr(nativeField, 'bitsize') and nativeField.bitsize != 0:
|
||||
bitsize = nativeField.bitsize
|
||||
else:
|
||||
bitsize = 8 * nativeFieldType.sizeof
|
||||
|
||||
fieldType = self.fromNativeType(nativeFieldType)
|
||||
if bitsize != nativeFieldType.sizeof * 8:
|
||||
fieldType = self.createBitfieldType(fieldType, bitsize)
|
||||
else:
|
||||
fieldType = fieldType
|
||||
field_typeid = self.from_native_type(nativeFieldType)
|
||||
is_bitfield = bitsize != nativeFieldType.sizeof * 8
|
||||
|
||||
if nativeValue is None:
|
||||
extractor = None
|
||||
else:
|
||||
extractor = lambda value, \
|
||||
capturedNativeField = nativeField, \
|
||||
capturedNativeValue = nativeValue, \
|
||||
capturedFieldName = fieldName: \
|
||||
self.memberFromNativeFieldAndValue(capturedNativeField,
|
||||
capturedNativeValue,
|
||||
capturedFieldName,
|
||||
value)
|
||||
val = self.Value(self)
|
||||
val.name = field_name
|
||||
val.isBaseClass = nativeField.is_base_class
|
||||
|
||||
if is_bitfield:
|
||||
val.typeid = self.create_bitfield_typeid(field_typeid, bitsize)
|
||||
val.ldata = self.value_extract_bits(value, bitpos, bitsize)
|
||||
else:
|
||||
val.typeid = field_typeid
|
||||
field_offset = bitpos // 8
|
||||
if laddress is not None:
|
||||
val.laddress = laddress + field_offset
|
||||
field_size = (bitsize + 7) // 8
|
||||
val.ldata = ldata[field_offset:field_offset + field_size]
|
||||
|
||||
#self.warn('GOT VAL %s FOR FIELD %s' % (val, nativeField))
|
||||
fields.append(val)
|
||||
|
||||
return fields
|
||||
|
||||
#DumperBase.warn("FOUND NATIVE FIELD: %s bitpos: %s" % (fieldName, bitpos))
|
||||
return self.Field(dumper=self, name=fieldName, isBase=nativeField.is_base_class,
|
||||
bitsize=bitsize, bitpos=bitpos, type=fieldType,
|
||||
extractor=extractor)
|
||||
|
||||
def listLocals(self, partialVar):
|
||||
frame = gdb.selected_frame()
|
||||
|
||||
try:
|
||||
block = frame.block()
|
||||
#DumperBase.warn('BLOCK: %s ' % block)
|
||||
#self.warn('BLOCK: %s ' % block)
|
||||
except RuntimeError as error:
|
||||
#DumperBase.warn('BLOCK IN FRAME NOT ACCESSIBLE: %s' % error)
|
||||
#self.warn('BLOCK IN FRAME NOT ACCESSIBLE: %s' % error)
|
||||
return []
|
||||
except:
|
||||
self.warn('BLOCK NOT ACCESSIBLE FOR UNKNOWN REASONS')
|
||||
@@ -594,14 +580,12 @@ class Dumper(DumperBase):
|
||||
if partialVar is not None and partialVar != name:
|
||||
continue
|
||||
|
||||
# 'NotImplementedError: Symbol type not yet supported in
|
||||
# Python scripts.'
|
||||
#DumperBase.warn('SYMBOL %s (%s, %s)): ' % (symbol, name, symbol.name))
|
||||
#self.warn('SYMBOL %s (%s, %s)): ' % (symbol, name, symbol.name))
|
||||
if self.passExceptions and not self.isTesting:
|
||||
nativeValue = frame.read_var(name, block)
|
||||
value = self.fromFrameValue(nativeValue)
|
||||
value.name = name
|
||||
#DumperBase.warn('READ 0: %s' % value.stringify())
|
||||
#self.warn('READ 0: %s' % value.stringify())
|
||||
items.append(value)
|
||||
continue
|
||||
|
||||
@@ -610,14 +594,14 @@ class Dumper(DumperBase):
|
||||
nativeValue = frame.read_var(name, block)
|
||||
value = self.fromFrameValue(nativeValue)
|
||||
value.name = name
|
||||
#DumperBase.warn('READ 1: %s' % value.stringify())
|
||||
#self.warn('READ 1: %s' % value.stringify())
|
||||
items.append(value)
|
||||
continue
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
#DumperBase.warn('READ 2: %s' % item.value)
|
||||
#self.warn('READ 2: %s' % item.value)
|
||||
value = self.fromFrameValue(frame.read_var(name))
|
||||
value.name = name
|
||||
items.append(value)
|
||||
@@ -631,8 +615,8 @@ class Dumper(DumperBase):
|
||||
pass
|
||||
|
||||
try:
|
||||
#DumperBase.warn('READ 3: %s %s' % (name, item.value))
|
||||
#DumperBase.warn('ITEM 3: %s' % item.value)
|
||||
#self.warn('READ 3: %s %s' % (name, item.value))
|
||||
#self.warn('ITEM 3: %s' % item.value)
|
||||
value = self.fromFrameValue(gdb.parse_and_eval(name))
|
||||
value.name = name
|
||||
items.append(value)
|
||||
@@ -661,16 +645,17 @@ class Dumper(DumperBase):
|
||||
return self.ptrSize() == 8
|
||||
|
||||
def fetchVariables(self, args):
|
||||
start_time = time.perf_counter()
|
||||
self.resetStats()
|
||||
self.prepare(args)
|
||||
|
||||
self.isBigEndian = gdb.execute('show endian', to_string=True).find('big endian') > 0
|
||||
self.packCode = '>' if self.isBigEndian else '<'
|
||||
|
||||
(ok, res) = self.tryFetchInterpreterVariables(args)
|
||||
if ok:
|
||||
safePrint(res)
|
||||
return
|
||||
#(ok, res) = self.tryFetchInterpreterVariables(args)
|
||||
#if ok:
|
||||
# safePrint(res)
|
||||
# return
|
||||
|
||||
self.put('data=[')
|
||||
|
||||
@@ -679,7 +664,7 @@ class Dumper(DumperBase):
|
||||
partialName = partialVar.split('.')[1].split('@')[0] if isPartial else None
|
||||
|
||||
variables = self.listLocals(partialName)
|
||||
#DumperBase.warn('VARIABLES: %s' % variables)
|
||||
#self.warn('VARIABLES: %s' % variables)
|
||||
|
||||
# Take care of the return value of the last function call.
|
||||
if len(self.resultVarName) > 0:
|
||||
@@ -711,9 +696,12 @@ class Dumper(DumperBase):
|
||||
self.put(',qtnamespace="%s"' % self.qtNamespaceToReport)
|
||||
self.qtNamespaceToReport = None
|
||||
|
||||
run_time = time.perf_counter() - start_time
|
||||
#self.warn("PTIME: %s" % run_time)
|
||||
self.put(',partial="%d"' % isPartial)
|
||||
self.put(',runtime="%s"' % run_time)
|
||||
self.put(',counts=%s' % self.counts)
|
||||
self.put(',timings=%s' % self.timings)
|
||||
#self.put(',timings=%s' % self.timings)
|
||||
self.reportResult(''.join(self.output), args)
|
||||
|
||||
def parseAndEvaluate(self, exp):
|
||||
@@ -721,7 +709,7 @@ class Dumper(DumperBase):
|
||||
return None if val is None else self.fromNativeValue(val)
|
||||
|
||||
def nativeParseAndEvaluate(self, exp):
|
||||
#DumperBase.warn('EVALUATE "%s"' % exp)
|
||||
#self.warn('EVALUATE "%s"' % exp)
|
||||
try:
|
||||
val = gdb.parse_and_eval(exp)
|
||||
return val
|
||||
@@ -744,20 +732,20 @@ class Dumper(DumperBase):
|
||||
else:
|
||||
arg += a
|
||||
|
||||
#DumperBase.warn('CALL: %s -> %s(%s)' % (value, function, arg))
|
||||
typeName = value.type.name
|
||||
if typeName.find(':') >= 0:
|
||||
typeName = "'" + typeName + "'"
|
||||
#self.warn('CALL: %s -> %s(%s)' % (value, function, arg))
|
||||
type_name = value.type.name
|
||||
if type_name.find(':') >= 0:
|
||||
type_name = "'" + type_name + "'"
|
||||
# 'class' is needed, see http://sourceware.org/bugzilla/show_bug.cgi?id=11912
|
||||
#exp = '((class %s*)%s)->%s(%s)' % (typeName, value.laddress, function, arg)
|
||||
#exp = '((class %s*)%s)->%s(%s)' % (type_name, value.laddress, function, arg)
|
||||
addr = value.address()
|
||||
if addr is None:
|
||||
addr = self.pokeValue(value)
|
||||
#DumperBase.warn('PTR: %s -> %s(%s)' % (value, function, addr))
|
||||
exp = '((%s*)0x%x)->%s(%s)' % (typeName, addr, function, arg)
|
||||
#DumperBase.warn('CALL: %s' % exp)
|
||||
#self.warn('PTR: %s -> %s(%s)' % (value, function, addr))
|
||||
exp = '((%s*)0x%x)->%s(%s)' % (type_name, addr, function, arg)
|
||||
#self.warn('CALL: %s' % exp)
|
||||
result = gdb.parse_and_eval(exp)
|
||||
#DumperBase.warn(' -> %s' % result)
|
||||
#self.warn(' -> %s' % result)
|
||||
res = self.fromNativeValue(result)
|
||||
if value.address() is None:
|
||||
self.releaseValue(addr)
|
||||
@@ -765,9 +753,9 @@ class Dumper(DumperBase):
|
||||
|
||||
def makeExpression(self, value):
|
||||
typename = '::' + value.type.name
|
||||
#DumperBase.warn(' TYPE: %s' % typename)
|
||||
#self.warn(' TYPE: %s' % typename)
|
||||
exp = '(*(%s*)(0x%x))' % (typename, value.address())
|
||||
#DumperBase.warn(' EXP: %s' % exp)
|
||||
#self.warn(' EXP: %s' % exp)
|
||||
return exp
|
||||
|
||||
def makeStdString(init):
|
||||
@@ -785,14 +773,14 @@ class Dumper(DumperBase):
|
||||
size = value.type.size()
|
||||
data = value.data()
|
||||
h = self.hexencode(data)
|
||||
#DumperBase.warn('DATA: %s' % h)
|
||||
#self.warn('DATA: %s' % h)
|
||||
string = ''.join('\\x' + h[2 * i:2 * i + 2] for i in range(size))
|
||||
exp = '(%s*)memcpy(calloc(1, %d), "%s", %d)' \
|
||||
% (value.type.name, size, string, size)
|
||||
#DumperBase.warn('EXP: %s' % exp)
|
||||
#self.warn('EXP: %s' % exp)
|
||||
res = gdb.parse_and_eval(exp)
|
||||
#DumperBase.warn('RES: %s' % res)
|
||||
return toInteger(res)
|
||||
#self.warn('RES: %s' % res)
|
||||
return int(res)
|
||||
|
||||
def releaseValue(self, address):
|
||||
gdb.parse_and_eval('free(0x%x)' % address)
|
||||
@@ -819,7 +807,7 @@ class Dumper(DumperBase):
|
||||
return self.cachedInferior
|
||||
|
||||
def readRawMemory(self, address, size):
|
||||
#DumperBase.warn('READ: %s FROM 0x%x' % (size, address))
|
||||
#self.warn('READ: %s FROM 0x%x' % (size, address))
|
||||
if address == 0 or size == 0:
|
||||
return bytes()
|
||||
res = self.selectedInferior().read_memory(address, size)
|
||||
@@ -832,7 +820,7 @@ class Dumper(DumperBase):
|
||||
return 0
|
||||
try:
|
||||
# Older GDB ~7.4 don't have gdb.Symbol.value()
|
||||
return toInteger(symbol.value().address)
|
||||
return int(symbol.value().address)
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -1020,7 +1008,7 @@ class Dumper(DumperBase):
|
||||
|
||||
def findSymbol(self, symbolName):
|
||||
try:
|
||||
return toInteger(gdb.parse_and_eval("(size_t)&'%s'" % symbolName))
|
||||
return int(gdb.parse_and_eval("(size_t)&'%s'" % symbolName))
|
||||
except:
|
||||
return 0
|
||||
|
||||
@@ -1052,30 +1040,24 @@ class Dumper(DumperBase):
|
||||
def handleQtCoreLoaded(self, objfile):
|
||||
fd, tmppath = tempfile.mkstemp()
|
||||
os.close(fd)
|
||||
try:
|
||||
cmd = 'maint print msymbols -objfile "%s" -- %s' % (objfile.filename, tmppath)
|
||||
symbols = gdb.execute(cmd, to_string=True)
|
||||
except:
|
||||
try:
|
||||
# command syntax depends on gdb version - below is gdb < 8
|
||||
cmd = 'maint print msymbols %s "%s"' % (tmppath, objfile.filename)
|
||||
symbols = gdb.execute(cmd, to_string=True)
|
||||
except:
|
||||
pass
|
||||
ns = ''
|
||||
with open(tmppath) as f:
|
||||
ns1re = re.compile(r'_ZN?(\d*)(\w*)L17msgHandlerGrabbedE? ')
|
||||
ns2re = re.compile(r'_ZN?(\d*)(\w*)L17currentThreadDataE? ')
|
||||
for line in f:
|
||||
if line.find('msgHandlerGrabbed ') >= 0:
|
||||
if 'msgHandlerGrabbed ' in line:
|
||||
# [11] b 0x7ffff683c000 _ZN4MynsL17msgHandlerGrabbedE
|
||||
# section .tbss Myns::msgHandlerGrabbed qlogging.cpp
|
||||
ns = re.split(r'_ZN?(\d*)(\w*)L17msgHandlerGrabbedE? ', line)[2]
|
||||
ns = ns1re.split(line)[2]
|
||||
if len(ns):
|
||||
ns += '::'
|
||||
break
|
||||
if line.find('currentThreadData ') >= 0:
|
||||
if 'currentThreadData ' in line:
|
||||
# [ 0] b 0x7ffff67d3000 _ZN2UUL17currentThreadDataE
|
||||
# section .tbss UU::currentThreadData qthread_unix.cpp\\n
|
||||
ns = re.split(r'_ZN?(\d*)(\w*)L17currentThreadDataE? ', line)[2]
|
||||
ns = ns2re.split(line)[2]
|
||||
if len(ns):
|
||||
ns += '::'
|
||||
break
|
||||
@@ -1104,21 +1086,21 @@ class Dumper(DumperBase):
|
||||
self.qtPropertyFunc = self.findSymbol(sym)
|
||||
|
||||
def assignValue(self, args):
|
||||
typeName = self.hexdecode(args['type'])
|
||||
type_name = self.hexdecode(args['type'])
|
||||
expr = self.hexdecode(args['expr'])
|
||||
value = self.hexdecode(args['value'])
|
||||
simpleType = int(args['simpleType'])
|
||||
ns = self.qtNamespace()
|
||||
if typeName.startswith(ns):
|
||||
typeName = typeName[len(ns):]
|
||||
typeName = typeName.replace('::', '__')
|
||||
pos = typeName.find('<')
|
||||
if type_name.startswith(ns):
|
||||
type_name = type_name[len(ns):]
|
||||
type_name = type_name.replace('::', '__')
|
||||
pos = type_name.find('<')
|
||||
if pos != -1:
|
||||
typeName = typeName[0:pos]
|
||||
if typeName in self.qqEditable and not simpleType:
|
||||
#self.qqEditable[typeName](self, expr, value)
|
||||
type_name = type_name[0:pos]
|
||||
if type_name in self.qqEditable and not simpleType:
|
||||
#self.qqEditable[type_name](self, expr, value)
|
||||
expr = self.parseAndEvaluate(expr)
|
||||
self.qqEditable[typeName](self, expr, value)
|
||||
self.qqEditable[type_name](self, expr, value)
|
||||
else:
|
||||
cmd = 'set variable (%s)=%s' % (expr, value)
|
||||
gdb.execute(cmd)
|
||||
@@ -1152,63 +1134,28 @@ class Dumper(DumperBase):
|
||||
nativeValue = value.nativeValue
|
||||
return self.fromNativeValue(nativeValue.cast(nativeValue.type.target()))
|
||||
|
||||
def nativeDynamicTypeName(self, address, baseType):
|
||||
def nativeDynamicType(self, address, base_typeid):
|
||||
# Needed for Gdb13393 test.
|
||||
nativeType = self.lookupNativeType(baseType.name)
|
||||
nativeType = self.type_nativetype_cache.get(base_typeid, None)
|
||||
if nativeType is None:
|
||||
return None
|
||||
return base_typeid
|
||||
nativeTypePointer = nativeType.pointer()
|
||||
nativeValue = gdb.Value(address).cast(nativeTypePointer).dereference()
|
||||
val = nativeValue.cast(nativeValue.dynamic_type)
|
||||
return str(val.type)
|
||||
#try:
|
||||
# vtbl = gdb.execute('info symbol {%s*}0x%x' % (baseType.name, address), to_string = True)
|
||||
#except:
|
||||
# return None
|
||||
#pos1 = vtbl.find('vtable ')
|
||||
#if pos1 == -1:
|
||||
# return None
|
||||
#pos1 += 11
|
||||
#pos2 = vtbl.find(' +', pos1)
|
||||
#if pos2 == -1:
|
||||
# return None
|
||||
#return vtbl[pos1 : pos2]
|
||||
|
||||
def nativeDynamicType(self, address, baseType):
|
||||
# Needed for Gdb13393 test.
|
||||
nativeType = self.lookupNativeType(baseType.name)
|
||||
if nativeType is None:
|
||||
return baseType
|
||||
nativeTypePointer = nativeType.pointer()
|
||||
nativeValue = gdb.Value(address).cast(nativeTypePointer).dereference()
|
||||
return self.fromNativeType(nativeValue.dynamic_type)
|
||||
return self.from_native_type(nativeValue.dynamic_type)
|
||||
|
||||
def enumExpression(self, enumType, enumValue):
|
||||
return self.qtNamespace() + 'Qt::' + enumValue
|
||||
|
||||
def lookupNativeType(self, typeName):
|
||||
nativeType = self.lookupNativeTypeHelper(typeName)
|
||||
if nativeType is not None:
|
||||
self.check(isinstance(nativeType, gdb.Type))
|
||||
return nativeType
|
||||
|
||||
def lookupNativeTypeHelper(self, typeName):
|
||||
typeobj = self.typeCache.get(typeName)
|
||||
#DumperBase.warn('LOOKUP 1: %s -> %s' % (typeName, typeobj))
|
||||
if typeobj is not None:
|
||||
return typeobj
|
||||
|
||||
if typeName == 'void':
|
||||
typeobj = gdb.lookup_type(typeName)
|
||||
self.typeCache[typeName] = typeobj
|
||||
self.typesToReport[typeName] = typeobj
|
||||
def lookupNativeType(self, type_name):
|
||||
if type_name == 'void':
|
||||
typeobj = gdb.lookup_type(type_name)
|
||||
self.typesToReport[type_name] = typeobj
|
||||
return typeobj
|
||||
|
||||
#try:
|
||||
# typeobj = gdb.parse_and_eval('{%s}&main' % typeName).typeobj
|
||||
# typeobj = gdb.parse_and_eval('{%s}&main' % type_name).typeobj
|
||||
# if not typeobj is None:
|
||||
# self.typeCache[typeName] = typeobj
|
||||
# self.typesToReport[typeName] = typeobj
|
||||
# self.typesToReport[type_name] = typeobj
|
||||
# return typeobj
|
||||
#except:
|
||||
# pass
|
||||
@@ -1217,22 +1164,21 @@ class Dumper(DumperBase):
|
||||
# gcc produces '{anonymous}', gdb '(anonymous namespace)'
|
||||
# '<unnamed>' has been seen too. The only thing gdb
|
||||
# understands when reading things back is '(anonymous namespace)'
|
||||
if typeName.find('{anonymous}') != -1:
|
||||
ts = typeName
|
||||
if type_name.find('{anonymous}') != -1:
|
||||
ts = type_name
|
||||
ts = ts.replace('{anonymous}', '(anonymous namespace)')
|
||||
typeobj = self.lookupNativeType(ts)
|
||||
if typeobj is not None:
|
||||
self.typeCache[typeName] = typeobj
|
||||
self.typesToReport[typeName] = typeobj
|
||||
self.typesToReport[type_name] = typeobj
|
||||
return typeobj
|
||||
|
||||
#DumperBase.warn(" RESULT FOR 7.2: '%s': %s" % (typeName, typeobj))
|
||||
#self.warn(" RESULT FOR 7.2: '%s': %s" % (type_name, typeobj))
|
||||
|
||||
# This part should only trigger for
|
||||
# gdb 7.1 for types with namespace separators.
|
||||
# And anonymous namespaces.
|
||||
|
||||
ts = typeName
|
||||
ts = type_name
|
||||
while True:
|
||||
if ts.startswith('class '):
|
||||
ts = ts[6:]
|
||||
@@ -1259,36 +1205,32 @@ class Dumper(DumperBase):
|
||||
typeobj = self.lookupNativeType(ts[0:-1])
|
||||
if typeobj is not None:
|
||||
typeobj = typeobj.pointer()
|
||||
self.typeCache[typeName] = typeobj
|
||||
self.typesToReport[typeName] = typeobj
|
||||
self.typesToReport[type_name] = typeobj
|
||||
return typeobj
|
||||
|
||||
try:
|
||||
#DumperBase.warn("LOOKING UP 1 '%s'" % ts)
|
||||
#self.warn("LOOKING UP 1 '%s'" % ts)
|
||||
typeobj = gdb.lookup_type(ts)
|
||||
except RuntimeError as error:
|
||||
#DumperBase.warn("LOOKING UP 2 '%s' ERROR %s" % (ts, error))
|
||||
#self.warn("LOOKING UP '%s' FAILED" % ts)
|
||||
pass
|
||||
#self.warn("LOOKING UP 2 '%s' ERROR %s" % (ts, error))
|
||||
# See http://sourceware.org/bugzilla/show_bug.cgi?id=11912
|
||||
exp = "(class '%s'*)0" % ts
|
||||
try:
|
||||
typeobj = self.parse_and_eval(exp).type.target()
|
||||
#DumperBase.warn("LOOKING UP 3 '%s'" % typeobj)
|
||||
#self.warn("LOOKING UP 3 '%s'" % typeobj)
|
||||
except:
|
||||
# Can throw 'RuntimeError: No type named class Foo.'
|
||||
pass
|
||||
except:
|
||||
#DumperBase.warn("LOOKING UP '%s' FAILED" % ts)
|
||||
pass
|
||||
|
||||
if typeobj is not None:
|
||||
#DumperBase.warn('CACHING: %s' % typeobj)
|
||||
self.typeCache[typeName] = typeobj
|
||||
self.typesToReport[typeName] = typeobj
|
||||
#self.warn('CACHING: %s' % typeobj)
|
||||
self.typesToReport[type_name] = typeobj
|
||||
|
||||
# This could still be None as gdb.lookup_type('char[3]') generates
|
||||
# 'RuntimeError: No type named char[3]'
|
||||
#self.typeCache[typeName] = typeobj
|
||||
#self.typesToReport[typeName] = typeobj
|
||||
#self.typesToReport[type_name] = typeobj
|
||||
return typeobj
|
||||
|
||||
def doContinue(self):
|
||||
@@ -1332,7 +1274,7 @@ class Dumper(DumperBase):
|
||||
if typeobj.code == gdb.TYPE_CODE_PTR:
|
||||
dereftype = typeobj.target().unqualified()
|
||||
if dereftype.name == needle:
|
||||
addr = toInteger(value)
|
||||
addr = int(value)
|
||||
res = None
|
||||
for pat in pats:
|
||||
try:
|
||||
@@ -1442,14 +1384,6 @@ class Dumper(DumperBase):
|
||||
def reportResult(self, result, args):
|
||||
print('result={token="%s",%s}' % (args.get("token", 0), result))
|
||||
|
||||
def profile1(self, args):
|
||||
'''Internal profiling'''
|
||||
import cProfile
|
||||
tempDir = tempfile.gettempdir() + '/bbprof'
|
||||
cProfile.run('theDumper.fetchVariables(%s)' % args, tempDir)
|
||||
import pstats
|
||||
pstats.Stats(tempDir).sort_stats('time').print_stats()
|
||||
|
||||
def profile2(self, args):
|
||||
import timeit
|
||||
print(timeit.repeat('theDumper.fetchVariables(%s)' % args,
|
||||
|
@@ -116,33 +116,29 @@ class Dumper(DumperBase):
|
||||
self.isInterrupting_ = False
|
||||
self.interpreterBreakpointResolvers = []
|
||||
|
||||
DumperBase.warn = Dumper.warn_impl
|
||||
self.report('lldbversion=\"%s\"' % lldb.SBDebugger.GetVersionString())
|
||||
|
||||
@staticmethod
|
||||
def warn_impl(message):
|
||||
if message[-1:] == '\n':
|
||||
message += '\n'
|
||||
def warn(self, msg):
|
||||
#self.put('{name="%s",value="",type="",numchild="0"},' % toCString(msg))
|
||||
if msg[-1:] == '\n':
|
||||
msg += '\n'
|
||||
print('@\nbridgemessage={msg="%s",channel="%s"}\n@'
|
||||
% (message.replace('"', '$'), LogChannel.AppError))
|
||||
|
||||
def fromNativeFrameValue(self, nativeValue):
|
||||
return self.fromNativeValue(nativeValue)
|
||||
% (msg.replace('"', '$'), LogChannel.AppError))
|
||||
|
||||
def fromNativeValue(self, nativeValue):
|
||||
self.check(isinstance(nativeValue, lldb.SBValue))
|
||||
nativeType = nativeValue.GetType()
|
||||
typeName = nativeType.GetName()
|
||||
type_name = nativeType.GetName()
|
||||
code = nativeType.GetTypeClass()
|
||||
|
||||
# Display the result of GetSummary() for Core Foundation string
|
||||
# and string-like types.
|
||||
summary = None
|
||||
if self.useFancy:
|
||||
if (typeName.startswith('CF')
|
||||
or typeName.startswith('__CF')
|
||||
or typeName.startswith('NS')
|
||||
or typeName.startswith('__NSCF')):
|
||||
if (type_name.startswith('CF')
|
||||
or type_name.startswith('__CF')
|
||||
or type_name.startswith('NS')
|
||||
or type_name.startswith('__NSCF')):
|
||||
if code == lldb.eTypeClassPointer:
|
||||
summary = nativeValue.Dereference().GetSummary()
|
||||
elif code == lldb.eTypeClassReference:
|
||||
@@ -156,26 +152,26 @@ class Dumper(DumperBase):
|
||||
nativeTargetType = nativeType.GetDereferencedType()
|
||||
if not nativeTargetType.IsPointerType():
|
||||
nativeTargetType = nativeTargetType.GetUnqualifiedType()
|
||||
targetType = self.fromNativeType(nativeTargetType)
|
||||
val = self.createReferenceValue(nativeValue.GetValueAsUnsigned(), targetType)
|
||||
target_typeid = self.from_native_type(nativeTargetType)
|
||||
target_address = nativeValue.GetValueAsUnsigned()
|
||||
val = self.Value(self)
|
||||
val.ldata = target_address.to_bytes(self.ptrSize(), 'little')
|
||||
if self.useDynamicType:
|
||||
target_typeid = self.dynamic_typeid_at_address(target_typeid, target_address)
|
||||
val.typeid = self.create_reference_typeid(target_typeid)
|
||||
val.laddress = nativeValue.AddressOf().GetValueAsUnsigned()
|
||||
#DumperBase.warn('CREATED REF: %s' % val)
|
||||
#self.warn('CREATED REF: %s' % val)
|
||||
|
||||
elif code == lldb.eTypeClassPointer:
|
||||
nativeTargetType = nativeType.GetPointeeType()
|
||||
if not nativeTargetType.IsPointerType():
|
||||
nativeTargetType = nativeTargetType.GetUnqualifiedType()
|
||||
targetType = self.fromNativeType(nativeTargetType)
|
||||
val = self.createPointerValue(nativeValue.GetValueAsUnsigned(), targetType)
|
||||
#DumperBase.warn('CREATED PTR 1: %s' % val)
|
||||
target_typeid = self.from_native_type(nativeTargetType)
|
||||
val = self.Value(self)
|
||||
val.ldata = nativeValue.GetValueAsUnsigned()
|
||||
val.typeid = self.create_pointer_typeid(target_typeid)
|
||||
val.laddress = nativeValue.AddressOf().GetValueAsUnsigned()
|
||||
#DumperBase.warn('CREATED PTR 2: %s' % val)
|
||||
elif code == lldb.eTypeClassTypedef:
|
||||
nativeTargetType = nativeType.GetUnqualifiedType()
|
||||
if hasattr(nativeTargetType, 'GetCanonicalType'):
|
||||
nativeTargetType = nativeTargetType.GetCanonicalType()
|
||||
val = self.fromNativeValue(nativeValue.Cast(nativeTargetType))
|
||||
val._type = self.fromNativeType(nativeType)
|
||||
#DumperBase.warn('CREATED TYPEDEF: %s' % val)
|
||||
|
||||
else:
|
||||
val = self.Value(self)
|
||||
address = nativeValue.GetLoadAddress()
|
||||
@@ -193,7 +189,7 @@ class Dumper(DumperBase):
|
||||
except:
|
||||
pass
|
||||
|
||||
val._type = self.fromNativeType(nativeType)
|
||||
val.typeid = self.from_native_type(nativeType)
|
||||
|
||||
if code == lldb.eTypeClassEnumeration:
|
||||
intval = nativeValue.GetValueAsSigned()
|
||||
@@ -209,43 +205,32 @@ class Dumper(DumperBase):
|
||||
val.ldisplay = str(nativeValue.GetValue())
|
||||
#elif code == lldb.eTypeClassArray:
|
||||
# if hasattr(nativeType, 'GetArrayElementType'): # New in 3.8(?) / 350.x
|
||||
# val.type.ltarget = self.fromNativeType(nativeType.GetArrayElementType())
|
||||
# val.type.ltarget = self.from_native_type(nativeType.GetArrayElementType())
|
||||
# else:
|
||||
# fields = nativeType.get_fields_array()
|
||||
# if len(fields):
|
||||
# val.type.ltarget = self.fromNativeType(fields[0])
|
||||
# val.type.ltarget = self.from_native_type(fields[0])
|
||||
#elif code == lldb.eTypeClassVector:
|
||||
# val.type.ltarget = self.fromNativeType(nativeType.GetVectorElementType())
|
||||
# val.type.ltarget = self.from_native_type(nativeType.GetVectorElementType())
|
||||
|
||||
val.summary = summary
|
||||
val.lIsInScope = nativeValue.IsInScope()
|
||||
val.name = nativeValue.GetName()
|
||||
return val
|
||||
|
||||
def nativeStructAlignment(self, nativeType):
|
||||
def handleItem(nativeFieldType, align):
|
||||
a = self.fromNativeType(nativeFieldType).alignment()
|
||||
return a if a > align else align
|
||||
align = 1
|
||||
for i in range(nativeType.GetNumberOfDirectBaseClasses()):
|
||||
base = nativeType.GetDirectBaseClassAtIndex(i)
|
||||
align = handleItem(base.GetType(), align)
|
||||
for i in range(nativeType.GetNumberOfFields()):
|
||||
child = nativeType.GetFieldAtIndex(i)
|
||||
align = handleItem(child.GetType(), align)
|
||||
return align
|
||||
|
||||
def listMembers(self, value, nativeType):
|
||||
#DumperBase.warn("ADDR: 0x%x" % self.fakeAddress_)
|
||||
def nativeListMembers(self, value, nativeType, include_base):
|
||||
#self.warn("ADDR: 0x%x" % self.fakeAddress_)
|
||||
nativeValue = value.nativeValue
|
||||
if nativeValue is None:
|
||||
if value.laddress:
|
||||
fakeAddress = lldb.SBAddress(value.laddress, self.target)
|
||||
fakeLAddress = value.laddress
|
||||
else:
|
||||
fakeAddress = self.fakeAddress_
|
||||
fakeLAddress = self.fakeLAddress_
|
||||
nativeValue = self.target.CreateValueFromAddress('x', fakeAddress, nativeType)
|
||||
|
||||
fakeValue = self.target.CreateValueFromAddress('x', fakeAddress, nativeType)
|
||||
fakeValue.SetPreferSyntheticValue(False)
|
||||
nativeValue.SetPreferSyntheticValue(False)
|
||||
|
||||
baseNames = {}
|
||||
for i in range(nativeType.GetNumberOfDirectBaseClasses()):
|
||||
@@ -262,45 +247,62 @@ class Dumper(DumperBase):
|
||||
|
||||
# Normal members and non-empty base classes.
|
||||
anonNumber = 0
|
||||
for i in range(fakeValue.GetNumChildren()):
|
||||
nativeField = fakeValue.GetChildAtIndex(i)
|
||||
|
||||
fields = []
|
||||
for i in range(nativeValue.GetNumChildren()):
|
||||
nativeField = nativeValue.GetChildAtIndex(i)
|
||||
nativeField.SetPreferSyntheticValue(False)
|
||||
|
||||
fieldName = nativeField.GetName()
|
||||
nativeFieldType = nativeField.GetType()
|
||||
|
||||
if fieldName in fieldBits:
|
||||
(fieldBitsize, fieldBitpos, isBitfield) = fieldBits[fieldName]
|
||||
(bitsize, bitpos, isBitfield) = fieldBits[fieldName]
|
||||
else:
|
||||
fieldBitsize = nativeFieldType.GetByteSize() * 8
|
||||
fieldBitpos = None
|
||||
bitsize = nativeFieldType.GetByteSize() * 8
|
||||
bitpos = None
|
||||
isBitfield = False
|
||||
|
||||
if isBitfield: # Bit fields
|
||||
fieldType = self.createBitfieldType(
|
||||
self.createType(self.typeName(nativeFieldType)), fieldBitsize)
|
||||
yield self.Field(self, name=fieldName, type=fieldType,
|
||||
bitsize=fieldBitsize, bitpos=fieldBitpos)
|
||||
field_typeid = self.create_bitfield_typeid(
|
||||
self.create_typeid(nativeFieldType.GetName()), bitsize)
|
||||
val = self.Value(self)
|
||||
val.name = fieldName
|
||||
val.isBaseClass = False
|
||||
val.typeid = field_typeid
|
||||
val.ldata = self.value_extract_bits(value, bitpos, bitsize)
|
||||
val.laddress = None
|
||||
fields.append(val)
|
||||
|
||||
elif fieldName is None: # Anon members
|
||||
anonNumber += 1
|
||||
fieldName = '#%s' % anonNumber
|
||||
fakeMember = fakeValue.GetChildAtIndex(i)
|
||||
fakeMember = nativeValue.GetChildAtIndex(i)
|
||||
fakeMemberAddress = fakeMember.GetLoadAddress()
|
||||
offset = fakeMemberAddress - fakeLAddress
|
||||
yield self.Field(self, name=fieldName, type=self.fromNativeType(nativeFieldType),
|
||||
bitsize=fieldBitsize, bitpos=8 * offset)
|
||||
val = self.Value(self)
|
||||
val.name = fieldName
|
||||
val.isBaseClass = False
|
||||
val.typeid = typeid=self.from_native_type(nativeFieldType)
|
||||
field_offset = fakeMemberAddress - fakeLAddress
|
||||
if value.laddress is not None:
|
||||
val.laddress = value.laddress + field_offset
|
||||
if value.ldata is not None:
|
||||
field_size = (bitsize + 7) // 8
|
||||
val.ldata = value.ldata[field_offset:field_offset + field_size]
|
||||
fields.append(val)
|
||||
|
||||
elif fieldName in baseNames: # Simple bases
|
||||
member = self.fromNativeValue(fakeValue.GetChildAtIndex(i))
|
||||
member = self.fromNativeValue(nativeValue.GetChildAtIndex(i))
|
||||
member.isBaseClass = True
|
||||
yield member
|
||||
fields.append(member)
|
||||
|
||||
else: # Normal named members
|
||||
member = self.fromNativeValue(fakeValue.GetChildAtIndex(i))
|
||||
member = self.fromNativeValue(nativeValue.GetChildAtIndex(i))
|
||||
member.name = nativeField.GetName()
|
||||
yield member
|
||||
fields.append(member)
|
||||
|
||||
|
||||
if include_base:
|
||||
# Empty bases are not covered above.
|
||||
for i in range(nativeType.GetNumberOfDirectBaseClasses()):
|
||||
fieldObj = nativeType.GetDirectBaseClassAtIndex(i)
|
||||
@@ -309,39 +311,35 @@ class Dumper(DumperBase):
|
||||
if fieldType.GetNumberOfDirectBaseClasses() == 0:
|
||||
member = self.Value(self)
|
||||
fieldName = fieldObj.GetName()
|
||||
member._type = self.fromNativeType(fieldType)
|
||||
member.typeid = self.from_native_type(fieldType)
|
||||
member.name = fieldName
|
||||
member.fields = []
|
||||
if False:
|
||||
# This would be correct if we came here only for
|
||||
# truly empty base classes. Alas, we don't, see below.
|
||||
member.ldata = bytes()
|
||||
member.lbitsize = fieldType.GetByteSize() * 8
|
||||
else:
|
||||
# This is a hack. LLDB 3.8 reports declared but not defined
|
||||
# types as having no fields and(!) size == 1. At least
|
||||
# for the common case of a single base class we can
|
||||
# fake the contents by using the whole derived object's
|
||||
# data as base class data.
|
||||
data = fakeValue.GetData()
|
||||
data = nativeValue.GetData()
|
||||
size = nativeType.GetByteSize()
|
||||
member.lbitsize = size * 8
|
||||
error = lldb.SBError()
|
||||
member.laddress = value.laddress
|
||||
member.ldata = data.ReadRawData(error, 0, size)
|
||||
member.isBaseClass = True
|
||||
member.ltype = self.fromNativeType(fieldType)
|
||||
member.name = fieldName
|
||||
yield member
|
||||
fields.append(member)
|
||||
return fields
|
||||
|
||||
def ptrSize(self):
|
||||
result = self.target.GetAddressByteSize()
|
||||
self.ptrSize = lambda: result
|
||||
return result
|
||||
|
||||
def fromNativeType(self, nativeType):
|
||||
def from_native_type(self, nativeType):
|
||||
self.check(isinstance(nativeType, lldb.SBType))
|
||||
code = nativeType.GetTypeClass()
|
||||
|
||||
# eTypeClassInvalid = (0u),
|
||||
# eTypeClassArray = (1u << 0),
|
||||
@@ -367,43 +365,41 @@ class Dumper(DumperBase):
|
||||
# // Define a mask that can be used for any type when finding types
|
||||
# eTypeClassAny = (0xffffffffu)
|
||||
|
||||
#DumperBase.warn('CURRENT: %s' % self.typeData.keys())
|
||||
#DumperBase.warn('FROM NATIVE TYPE: %s' % nativeType.GetName())
|
||||
#self.warn('CURRENT: %s' % self.typeData.keys())
|
||||
#self.warn('FROM NATIVE TYPE: %s' % nativeType.GetName())
|
||||
|
||||
typeid_str = self.native_type_key(nativeType)
|
||||
known_typeid = self.typeid_from_typekey.get(typeid_str, None)
|
||||
if known_typeid is not None:
|
||||
return known_typeid
|
||||
|
||||
code = nativeType.GetTypeClass()
|
||||
|
||||
if code == lldb.eTypeClassInvalid:
|
||||
return None
|
||||
typeid = 0
|
||||
|
||||
if code == lldb.eTypeClassBuiltin:
|
||||
nativeType = nativeType.GetUnqualifiedType()
|
||||
elif code == lldb.eTypeClassPointer:
|
||||
#self.warn('PTR: %s' % nativeTargetType.name)
|
||||
target_typeid = self.from_native_type(nativeType.GetPointeeType())
|
||||
typeid = self.create_pointer_typeid(target_typeid)
|
||||
|
||||
if code == lldb.eTypeClassPointer:
|
||||
#DumperBase.warn('PTR')
|
||||
nativeTargetType = nativeType.GetPointeeType()
|
||||
if not nativeTargetType.IsPointerType():
|
||||
nativeTargetType = nativeTargetType.GetUnqualifiedType()
|
||||
#DumperBase.warn('PTR: %s' % nativeTargetType.name)
|
||||
return self.createPointerType(self.fromNativeType(nativeTargetType))
|
||||
|
||||
if code == lldb.eTypeClassReference:
|
||||
elif code == lldb.eTypeClassReference:
|
||||
#DumperBase.warn('REF')
|
||||
nativeTargetType = nativeType.GetDereferencedType()
|
||||
if not nativeTargetType.IsPointerType():
|
||||
nativeTargetType = nativeTargetType.GetUnqualifiedType()
|
||||
#DumperBase.warn('REF: %s' % nativeTargetType.name)
|
||||
return self.createReferenceType(self.fromNativeType(nativeTargetType))
|
||||
target_typeid = self.from_native_type(nativeType.GetDereferencedType())
|
||||
typeid = self.create_reference_typeid(target_typeid)
|
||||
|
||||
if code == lldb.eTypeClassTypedef:
|
||||
elif code == lldb.eTypeClassTypedef:
|
||||
#DumperBase.warn('TYPEDEF')
|
||||
nativeTargetType = nativeType.GetUnqualifiedType()
|
||||
if hasattr(nativeTargetType, 'GetCanonicalType'):
|
||||
nativeTargetType = nativeTargetType.GetCanonicalType()
|
||||
targetType = self.fromNativeType(nativeTargetType)
|
||||
return self.createTypedefedType(targetType, nativeType.GetName(),
|
||||
self.nativeTypeId(nativeType))
|
||||
target_typeid = self.from_native_type(nativeTargetType)
|
||||
typeid = self.create_typedefed_typeid(target_typeid, nativeType.GetName(),
|
||||
typeid_str)
|
||||
|
||||
elif code in (lldb.eTypeClassArray, lldb.eTypeClassVector):
|
||||
nativeType = nativeType.GetUnqualifiedType()
|
||||
typeName = self.typeName(nativeType)
|
||||
|
||||
if code in (lldb.eTypeClassArray, lldb.eTypeClassVector):
|
||||
type_name = nativeType.GetName()
|
||||
#DumperBase.warn('ARRAY: %s' % nativeType.GetName())
|
||||
if hasattr(nativeType, 'GetArrayElementType'): # New in 3.8(?) / 350.x
|
||||
nativeTargetType = nativeType.GetArrayElementType()
|
||||
@@ -412,82 +408,82 @@ class Dumper(DumperBase):
|
||||
#DumperBase.warn('BAD: %s ' % nativeTargetType.get_fields_array())
|
||||
nativeTargetType = nativeType.GetVectorElementType()
|
||||
count = nativeType.GetByteSize() // nativeTargetType.GetByteSize()
|
||||
targetTypeName = nativeTargetType.GetName()
|
||||
if targetTypeName.startswith('(anon'):
|
||||
typeName = nativeType.GetName()
|
||||
pos1 = typeName.rfind('[')
|
||||
targetTypeName = typeName[0:pos1].strip()
|
||||
#DumperBase.warn("TARGET TYPENAME: %s" % targetTypeName)
|
||||
targetType = self.fromNativeType(nativeTargetType)
|
||||
targetType.setTdata(targetType.tdata.copy())
|
||||
targetType.tdata.name = targetTypeName
|
||||
return self.createArrayType(targetType, count)
|
||||
if hasattr(nativeType, 'GetVectorElementType'): # New in 3.8(?) / 350.x
|
||||
target_typename = nativeTargetType.GetName()
|
||||
if target_typename.startswith('(anon'):
|
||||
type_name = nativeType.GetName()
|
||||
pos1 = type_name.rfind('[')
|
||||
target_typename = type_name[0:pos1].strip()
|
||||
#DumperBase.warn("TARGET TYPENAME: %s" % target_typename)
|
||||
target_typeid = self.from_native_type(nativeTargetType)
|
||||
#target_typeid.setTdata(target_typeid.tdata.copy())
|
||||
#target_typeid.tdata.name = target_typename
|
||||
typeid = self.create_array_typeid(target_typeid, count)
|
||||
elif hasattr(nativeType, 'GetVectorElementType'): # New in 3.8(?) / 350.x
|
||||
nativeTargetType = nativeType.GetVectorElementType()
|
||||
count = nativeType.GetByteSize() // nativeTargetType.GetByteSize()
|
||||
targetType = self.fromNativeType(nativeTargetType)
|
||||
return self.createArrayType(targetType, count)
|
||||
return self.createType(nativeType.GetName())
|
||||
target_typeid = self.from_native_type(nativeTargetType)
|
||||
typeid = self.create_array_typeid(target_typeid, count)
|
||||
else:
|
||||
typeid = self.create_type(nativeType.GetName())
|
||||
|
||||
typeId = self.nativeTypeId(nativeType)
|
||||
res = self.typeData.get(typeId, None)
|
||||
if res is None:
|
||||
else:
|
||||
nativeType = nativeType.GetUnqualifiedType()
|
||||
type_name = nativeType.GetName()
|
||||
|
||||
typeid = self.typeid_for_string(typeid_str)
|
||||
#if not typeid in self.typeid_cache:
|
||||
# # This strips typedefs for pointers. We don't want that.
|
||||
# typeobj.nativeType = nativeType.GetUnqualifiedType()
|
||||
tdata = self.TypeData(self, typeId)
|
||||
tdata.name = typeName
|
||||
tdata.lbitsize = nativeType.GetByteSize() * 8
|
||||
self.type_name_cache[typeid] = type_name
|
||||
self.type_size_cache[typeid] = nativeType.GetByteSize()
|
||||
type_code = None
|
||||
if code == lldb.eTypeClassBuiltin:
|
||||
if utils.isFloatingPointTypeName(typeName):
|
||||
tdata.code = TypeCode.Float
|
||||
elif utils.isIntegralTypeName(typeName):
|
||||
tdata.code = TypeCode.Integral
|
||||
elif typeName in ('__int128', 'unsigned __int128'):
|
||||
tdata.code = TypeCode.Integral
|
||||
elif typeName == 'void':
|
||||
tdata.code = TypeCode.Void
|
||||
elif typeName == 'wchar_t':
|
||||
tdata.code = TypeCode.Integral
|
||||
elif typeName in ("char16_t", "char32_t", "char8_t"):
|
||||
tdata.code = TypeCode.Integral
|
||||
if utils.isFloatingPointTypeName(type_name):
|
||||
type_code = TypeCode.Float
|
||||
elif utils.isIntegralTypeName(type_name):
|
||||
type_code = TypeCode.Integral
|
||||
elif type_name in ('__int128', 'unsigned __int128'):
|
||||
type_code = TypeCode.Integral
|
||||
elif type_name == 'void':
|
||||
type_code = TypeCode.Void
|
||||
elif type_name == 'wchar_t':
|
||||
type_code = TypeCode.Integral
|
||||
elif type_name in ("char16_t", "char32_t", "char8_t"):
|
||||
type_code = TypeCode.Integral
|
||||
else:
|
||||
self.warn('UNKNOWN TYPE KEY: %s: %s' % (typeName, code))
|
||||
self.warn('UNKNOWN TYPE KEY: %s: %s' % (type_name, code))
|
||||
elif code == lldb.eTypeClassEnumeration:
|
||||
tdata.code = TypeCode.Enum
|
||||
tdata.enumDisplay = lambda intval, addr, form: \
|
||||
type_code = TypeCode.Enum
|
||||
self.type_enum_display_cache[typeid] = lambda intval, addr, form: \
|
||||
self.nativeTypeEnumDisplay(nativeType, intval, form)
|
||||
elif code in (lldb.eTypeClassComplexInteger, lldb.eTypeClassComplexFloat):
|
||||
tdata.code = TypeCode.Complex
|
||||
type_code = TypeCode.Complex
|
||||
elif code in (lldb.eTypeClassClass, lldb.eTypeClassStruct, lldb.eTypeClassUnion):
|
||||
tdata.code = TypeCode.Struct
|
||||
tdata.lalignment = lambda: \
|
||||
self.nativeStructAlignment(nativeType)
|
||||
tdata.lfields = lambda value: \
|
||||
self.listMembers(value, nativeType)
|
||||
tdata.templateArguments = lambda: \
|
||||
self.listTemplateParametersHelper(nativeType)
|
||||
type_code = TypeCode.Struct
|
||||
elif code == lldb.eTypeClassFunction:
|
||||
tdata.code = TypeCode.Function
|
||||
type_code = TypeCode.Function
|
||||
elif code == lldb.eTypeClassMemberPointer:
|
||||
tdata.code = TypeCode.MemberPointer
|
||||
# warn('CREATE TYPE: %s' % typeId)
|
||||
#else:
|
||||
# warn('REUSE TYPE: %s' % typeId)
|
||||
return self.Type(self, typeId)
|
||||
type_code = TypeCode.MemberPointer
|
||||
|
||||
def listTemplateParametersHelper(self, nativeType):
|
||||
stringArgs = self.listTemplateParameters(nativeType.GetName())
|
||||
n = nativeType.GetNumberOfTemplateArguments()
|
||||
if n != len(stringArgs):
|
||||
# Something wrong in the debug info.
|
||||
# Should work in theory, doesn't work in practice.
|
||||
# Items like std::allocator<std::pair<unsigned int const, float> report 0
|
||||
# for nativeType.GetNumberOfTemplateArguments() with LLDB 3.8
|
||||
return stringArgs
|
||||
if code is not None:
|
||||
self.type_code_cache[typeid] = type_code
|
||||
|
||||
targs = []
|
||||
for i in range(nativeType.GetNumberOfTemplateArguments()):
|
||||
kind = nativeType.GetTemplateArgumentKind(i)
|
||||
self.type_nativetype_cache[typeid] = nativeType
|
||||
self.typeid_from_typekey[typeid_str] = typeid
|
||||
|
||||
# self.warn('REUSE TYPE: %s' % typeid)
|
||||
return typeid
|
||||
|
||||
def nativeTemplateParameter(self, typeid, index, nativeType):
|
||||
#n = nativeType.GetNumberOfTemplateArguments()
|
||||
#if n != len(stringArgs):
|
||||
# # Something wrong in the debug info.
|
||||
# # Should work in theory, doesn't work in practice.
|
||||
# # Items like std::allocator<std::pair<unsigned int const, float> report 0
|
||||
# # for nativeType.GetNumberOfTemplateArguments() with LLDB 3.8
|
||||
# return stringArgs
|
||||
|
||||
kind = nativeType.GetTemplateArgumentKind(index)
|
||||
# eTemplateArgumentKindNull = 0,
|
||||
# eTemplateArgumentKindType,
|
||||
# eTemplateArgumentKindDeclaration,
|
||||
@@ -497,9 +493,9 @@ class Dumper(DumperBase):
|
||||
# eTemplateArgumentKindExpression,
|
||||
# eTemplateArgumentKindPack
|
||||
if kind == lldb.eTemplateArgumentKindType:
|
||||
innerType = nativeType.GetTemplateArgumentType(
|
||||
i).GetUnqualifiedType().GetCanonicalType()
|
||||
targs.append(self.fromNativeType(innerType))
|
||||
innerType = nativeType.GetTemplateArgumentType(index) \
|
||||
.GetUnqualifiedType().GetCanonicalType()
|
||||
return self.Type(self, self.from_native_type(innerType))
|
||||
#elif kind == lldb.eTemplateArgumentKindIntegral:
|
||||
# innerType = nativeType.GetTemplateArgumentType(i).GetUnqualifiedType().GetCanonicalType()
|
||||
# #DumperBase.warn('INNER TYP: %s' % innerType)
|
||||
@@ -517,36 +513,34 @@ class Dumper(DumperBase):
|
||||
# value -= 0x100000000
|
||||
# #DumperBase.warn('KIND: %s' % kind)
|
||||
# targs.append(value)
|
||||
else:
|
||||
#DumperBase.warn('UNHANDLED TEMPLATE TYPE : %s' % kind)
|
||||
targs.append(stringArgs[i]) # Best we can do.
|
||||
#else:
|
||||
# #DumperBase.warn('UNHANDLED TEMPLATE TYPE : %s' % kind)
|
||||
# targs.append(stringArgs[i]) # Best we can do.
|
||||
#DumperBase.warn('TARGS: %s %s' % (nativeType.GetName(), [str(x) for x in targs]))
|
||||
return targs
|
||||
#return targs
|
||||
return None
|
||||
|
||||
def typeName(self, nativeType):
|
||||
# Don't use GetDisplayTypeName since LLDB removed the inline namespace __1
|
||||
# https://reviews.llvm.org/D74478
|
||||
return nativeType.GetName()
|
||||
|
||||
def nativeTypeId(self, nativeType):
|
||||
if nativeType and (nativeType.GetTypeClass() == lldb.eTypeClassTypedef):
|
||||
def native_type_key(self, nativeType):
|
||||
code = nativeType.GetTypeClass()
|
||||
if nativeType and code == lldb.eTypeClassTypedef:
|
||||
nativeTargetType = nativeType.GetUnqualifiedType()
|
||||
if hasattr(nativeTargetType, 'GetCanonicalType'):
|
||||
nativeTargetType = nativeTargetType.GetCanonicalType()
|
||||
return '%s{%s}' % (nativeType.name, nativeTargetType.name)
|
||||
name = self.typeName(nativeType)
|
||||
# Don't use GetDisplayTypeName since LLDB removed the inline namespace __1
|
||||
# https://reviews.llvm.org/D74478
|
||||
name = nativeType.GetName()
|
||||
if name is None or len(name) == 0:
|
||||
c = '0'
|
||||
elif name == '(anonymous struct)' and nativeType.GetTypeClass() == lldb.eTypeClassStruct:
|
||||
c = 's'
|
||||
elif name == '(anonymous struct)' and nativeType.GetTypeClass() == lldb.eTypeClassUnion:
|
||||
c = 'u'
|
||||
elif name == '(anonymous struct)':
|
||||
c = 's' if code == lldb.eTypeClassStruct else 'u'
|
||||
else:
|
||||
return name
|
||||
fields = nativeType.get_fields_array()
|
||||
typeId = c + ''.join(['{%s:%s}' % (f.name, self.nativeTypeId(f.GetType())) for f in fields])
|
||||
#DumperBase.warn('NATIVE TYPE ID FOR %s IS %s' % (name, typeId))
|
||||
return typeId
|
||||
id_str = c + ''.join(['{%s:%s}' %
|
||||
(f.name, self.typeid_for_string(self.native_type_key(f.GetType())))
|
||||
for f in fields])
|
||||
return id_str
|
||||
|
||||
def nativeTypeEnumDisplay(self, nativeType, intval, form):
|
||||
if hasattr(nativeType, 'get_enum_members_array'):
|
||||
@@ -575,12 +569,82 @@ class Dumper(DumperBase):
|
||||
return '(' + ' | '.join(flags) + ') (' + (form % intval) + ')'
|
||||
return form % intval
|
||||
|
||||
def nativeDynamicTypeName(self, address, baseType):
|
||||
return None # FIXME: Seems sufficient, no idea why.
|
||||
addr = self.target.ResolveLoadAddress(address)
|
||||
ctx = self.target.ResolveSymbolContextForAddress(addr, 0)
|
||||
sym = ctx.GetSymbol()
|
||||
return sym.GetName()
|
||||
def nativeDynamicType(self, address, base_typeid):
|
||||
return self.nativeDynamicType_2(address, base_typeid)
|
||||
|
||||
def nativeDynamicType_1(self, address, base_typeid):
|
||||
# Solutions 1: Breaks StdUniquePtr and QVariant1 test
|
||||
return base_typeid
|
||||
|
||||
def nativeDynamicType_2(self, address, base_typeid):
|
||||
# Solution 2: ~10% slower in total than Solution 1
|
||||
typename = self.type_name(base_typeid)
|
||||
#self.warn("LOOKING FOR DYN TYPE: 0x%x %s" % (address, typename))
|
||||
#self.warn(" PRETTY: 0x%x %s" % (address, self.prettySymbolByAddress(address)))
|
||||
|
||||
expr = '(void*)%s' % address
|
||||
value = self.target.EvaluateExpression(expr)
|
||||
|
||||
#self.warn("VALUE: %s" % value)
|
||||
if value.GetType().GetName() == "void *":
|
||||
#self.warn("NO DYN TYPE: %s" % value)
|
||||
return base_typeid
|
||||
|
||||
dvalue = value.Dereference()
|
||||
#self.warn("DVALUE: %s" % value)
|
||||
sbtype = dvalue.GetType()
|
||||
#self.warn("TYPE: %s" % sbtype)
|
||||
|
||||
#self.warn("OUTPUT: %s" % output)
|
||||
#self.warn("DYNTYPE: %s" % dyn_typename)
|
||||
return self.from_native_type(sbtype)
|
||||
|
||||
def nativeDynamicType_3(self, address, base_typeid):
|
||||
# Solution 3: Doesn't improve over 1
|
||||
typename = self.type_name(base_typeid)
|
||||
self.warn("LOOKING FOR DYN TYPE: 0x%x %s" % (address, typename))
|
||||
#self.warn(" PRETTY: 0x%x %s" % (address, self.prettySymbolByAddress(address)))
|
||||
nativeType = self.type_nativetype_cache.get(base_typeid, None)
|
||||
#self.warn(" NATIVE BASE %s" % nativeType)
|
||||
if nativeType is None:
|
||||
return base_typeid
|
||||
#versionValue = self.target.EvaluateExpression('qtHookData[2]').GetNonSyntheticValue()
|
||||
addr = lldb.SBAddress(address, self.target)
|
||||
value = self.target.CreateValueFromAddress('x', addr, nativeType)
|
||||
self.warn(" VALUE %s" % value)
|
||||
return base_typeid
|
||||
|
||||
def nativeDynamicType_4(self, address, base_typeid):
|
||||
#self.warn("RESULT: %s" % result)
|
||||
#self.warn("ADDRESS: 0x%x" % address)
|
||||
|
||||
#thread = self.currentThread()
|
||||
#frame = thread.GetFrameAtIndex(0)
|
||||
#expr = '(void*)%s' % address
|
||||
#value = self.target.EvaluateExpression(expr)
|
||||
#sbtype = self.lookupNativeType(typename)
|
||||
#addr = self.target.ResolveLoadAddress(address)
|
||||
#addr = lldb.SBAddress(address, self.target)
|
||||
#value = self.target.CreateValueFromAddress('x', addr, sbtype)
|
||||
#x = lldb::DynamicValueType()
|
||||
#lldb.eNoDynamicValues
|
||||
#lldb.eDynamicCanRunTarget
|
||||
#lldb.eDynamicDontRunTarget
|
||||
#dyn_value = value.GetDynamicValue(lldb.eDynamicDontRunTarget)
|
||||
#typ = dyn_value.GetType()
|
||||
self.warn("GOT DYN VALUE: %s" % dyn_value)
|
||||
#self.warn("GOT TYPE: %s FOR OBJECT AT 0x%x" % (typ, address))
|
||||
return self.from_native_type(typ)
|
||||
|
||||
#result = lldb.SBCommandReturnObject()
|
||||
#cmd = 'p (void*)%s' % address
|
||||
#self.debugger.GetCommandInterpreter().HandleCommand(cmd, result)
|
||||
#if not result.Succeeded():
|
||||
# return self.Type(self, typeid)
|
||||
#output = result.GetOutput().strip()
|
||||
#dyn_typename = output[1:output.find('$') - 4]
|
||||
#sbtype = self.lookupNativeType(dyn_typename)
|
||||
|
||||
|
||||
def stateName(self, s):
|
||||
try:
|
||||
@@ -638,11 +702,11 @@ class Dumper(DumperBase):
|
||||
#DumperBase.warn(' -> %s' % result)
|
||||
return self.fromNativeValue(result)
|
||||
|
||||
def pokeValue(self, typeName, *args):
|
||||
def pokeValue(self, type_name, *args):
|
||||
thread = self.currentThread()
|
||||
frame = thread.GetFrameAtIndex(0)
|
||||
inner = ','.join(args)
|
||||
value = frame.EvaluateExpression(typeName + '{' + inner + '}')
|
||||
value = frame.EvaluateExpression(type_name + '{' + inner + '}')
|
||||
#DumperBase.warn(' TYPE: %s' % value.type)
|
||||
#DumperBase.warn(' ADDR: 0x%x' % value.address)
|
||||
#DumperBase.warn(' VALUE: %s' % value)
|
||||
@@ -830,8 +894,6 @@ class Dumper(DumperBase):
|
||||
#DumperBase.warn('RECURSE PTR')
|
||||
typeobj = self.lookupNativeType(name[:-1].strip())
|
||||
if typeobj is not None:
|
||||
#DumperBase.warn('RECURSE RESULT X: %s' % typeobj)
|
||||
self.fromNativeType(typeobj.GetPointerType())
|
||||
#DumperBase.warn('RECURSE RESULT: %s' % typeobj.GetPointerType())
|
||||
return typeobj.GetPointerType()
|
||||
|
||||
@@ -1289,14 +1351,12 @@ class Dumper(DumperBase):
|
||||
def findSymbol(self, symbolName):
|
||||
return self.target.FindFirstGlobalVariable(symbolName)
|
||||
|
||||
def warn(self, msg):
|
||||
self.put('{name="%s",value="",type="",numchild="0"},' % toCString(msg))
|
||||
|
||||
def fetchVariables(self, args):
|
||||
(ok, res) = self.tryFetchInterpreterVariables(args)
|
||||
if ok:
|
||||
self.reportResult(res, args)
|
||||
return
|
||||
start_time = time.perf_counter()
|
||||
#(ok, res) = self.tryFetchInterpreterVariables(args)
|
||||
#if ok:
|
||||
# self.reportResult(res, args)
|
||||
# return
|
||||
|
||||
self.setVariableFetchingOptions(args)
|
||||
|
||||
@@ -1360,13 +1420,15 @@ class Dumper(DumperBase):
|
||||
# This can happen for unnamed function parameters with
|
||||
# default values: void foo(int = 0)
|
||||
continue
|
||||
value = self.fromNativeFrameValue(val)
|
||||
value = self.fromNativeValue(val)
|
||||
variables.append(value)
|
||||
|
||||
self.handleLocals(variables)
|
||||
self.handleWatches(args)
|
||||
|
||||
self.put('],partial="%d"' % isPartial)
|
||||
run_time = time.perf_counter() - start_time
|
||||
|
||||
self.put('],partial="%d",runtime="%s"' % (isPartial, run_time))
|
||||
self.reportResult(self.takeOutput(), args)
|
||||
|
||||
|
||||
@@ -1987,14 +2049,14 @@ class Dumper(DumperBase):
|
||||
value = self.hexdecode(args['value'])
|
||||
simpleType = int(args['simpleType'])
|
||||
lhs = self.findValueByExpression(expr)
|
||||
typeName = lhs.GetType().GetName()
|
||||
typeName = typeName.replace('::', '__')
|
||||
pos = typeName.find('<')
|
||||
type_name = lhs.GetType().GetName()
|
||||
type_name = type_name.replace('::', '__')
|
||||
pos = type_name.find('<')
|
||||
if pos != -1:
|
||||
typeName = typeName[0:pos]
|
||||
if typeName in self.qqEditable and not simpleType:
|
||||
type_name = type_name[0:pos]
|
||||
if type_name in self.qqEditable and not simpleType:
|
||||
expr = self.parseAndEvaluate(expr)
|
||||
self.qqEditable[typeName](self, expr, value)
|
||||
self.qqEditable[type_name](self, expr, value)
|
||||
else:
|
||||
self.parseAndEvaluate(expr + '=' + value)
|
||||
self.reportResult(self.describeError(error), args)
|
||||
@@ -2098,10 +2160,10 @@ class Tester(Dumper):
|
||||
|
||||
if 'QT_CREATOR_LLDB_PROCESS' in os.environ:
|
||||
# Initialize Qt Creator dumper
|
||||
try:
|
||||
#try:
|
||||
theDumper = Dumper()
|
||||
except Exception as error:
|
||||
print('@\nstate="enginesetupfailed",error="{}"@\n'.format(error))
|
||||
#except Exception as error:
|
||||
# print('@\nstate="enginesetupfailed",error="{}"@\n'.format(error))
|
||||
|
||||
# ------------------------------ For use in LLDB ------------------------------
|
||||
|
||||
|
@@ -221,15 +221,15 @@ def qdump__Qt__ItemDataRole(d, value):
|
||||
|
||||
|
||||
def qdump__QStandardItemData(d, value):
|
||||
d.createType('@Qt::ItemDataRole') # warm up cache
|
||||
#d.createType('@Qt::ItemDataRole') # warm up cache
|
||||
role, pad, val = value.split('{@Qt::ItemDataRole}@{@QVariant}')
|
||||
d.putPairContents(role.value(), (role, val), 'role', 'value')
|
||||
|
||||
|
||||
def qdump__QStandardItem(d, value):
|
||||
d.createType('@QStandardItemData') # warm up cache
|
||||
d.createType('@QStandardItem')
|
||||
d.createType('@QStandardItem*')
|
||||
#d.createType('@QStandardItemData') # warm up cache
|
||||
#d.createType('@QStandardItem')
|
||||
#d.createType('@QStandardItem*')
|
||||
|
||||
vtable, dptr = value.split('pp')
|
||||
if d.qtVersion() >= 0x060000:
|
||||
@@ -549,14 +549,11 @@ def qdump__QDir(d, value):
|
||||
#d.putCallItem('absolutePath', '@QString', value, 'absolutePath')
|
||||
#d.putCallItem('canonicalPath', '@QString', value, 'canonicalPath')
|
||||
with SubItem(d, 'absolutePath'):
|
||||
typ = d.lookupType(ns + 'QString')
|
||||
d.putItem(d.createValue(privAddress + absoluteDirEntryOffset, typ))
|
||||
d.putItem(d.createValue(privAddress + absoluteDirEntryOffset, '@QString'))
|
||||
with SubItem(d, 'entryInfoList'):
|
||||
typ = d.lookupType(ns + 'QFileInfo')
|
||||
qdumpHelper_QList(d, privAddress + fileInfosOffset, typ)
|
||||
qdumpHelper_QList(d, privAddress + fileInfosOffset, '@QFileInfo')
|
||||
with SubItem(d, 'entryList'):
|
||||
typ = d.lookupType(ns + 'QStringList')
|
||||
d.putItem(d.createValue(privAddress + filesOffset, typ))
|
||||
d.putItem(d.createValue(privAddress + filesOffset, '@QStringList'))
|
||||
d.putFields(value)
|
||||
|
||||
|
||||
@@ -1095,14 +1092,15 @@ def qform__QList():
|
||||
|
||||
|
||||
def qdump__QList(d, value):
|
||||
return qdumpHelper_QList(d, value, d.createType(value.type[0]))
|
||||
return qdumpHelper_QList(d, value, value.type[0])
|
||||
|
||||
|
||||
def qdump__QVariantList(d, value):
|
||||
qdumpHelper_QList(d, value, d.createType('@QVariant'))
|
||||
qdumpHelper_QList(d, value, '@QVariant')
|
||||
|
||||
|
||||
def qdumpHelper_QList(d, value, innerType):
|
||||
def qdumpHelper_QList(d, value, inner_typish):
|
||||
innerType = d.createType(inner_typish)
|
||||
data, size = d.listData(value, check=True)
|
||||
d.putItemCount(size)
|
||||
|
||||
@@ -1224,7 +1222,8 @@ def qdump__QLocale(d, value):
|
||||
# index = int(value['d']['d']['m_data']...)
|
||||
#d.check(index >= 0)
|
||||
#d.check(index <= qqLocalesCount)
|
||||
if d.qtVersion() < 0x50000:
|
||||
qtVersion = d.qtVersion()
|
||||
if qtVersion < 0x50000:
|
||||
d.putStringValue(d.call('const char *', value, 'name'))
|
||||
d.putPlainChildren(value)
|
||||
return
|
||||
@@ -1238,14 +1237,20 @@ def qdump__QLocale(d, value):
|
||||
= d.split('2s{short}2s'
|
||||
+ '{@QChar}{@QChar}{short}{@QChar}{@QChar}'
|
||||
+ '{@QChar}{@QChar}{@QChar}', data)
|
||||
|
||||
prefix = ns + 'QLocale::'
|
||||
try:
|
||||
d.putStringValue(d.call('const char *', value, 'name'))
|
||||
if qtVersion >= 0x060700:
|
||||
res = d.call('const char *', value, 'name', prefix + 'TagSeparator::Underscore')
|
||||
else:
|
||||
res = d.call('const char *', value, 'name')
|
||||
d.putStringValue(res)
|
||||
except:
|
||||
pass
|
||||
|
||||
d.putExpandable()
|
||||
if d.isExpanded():
|
||||
with Children(d):
|
||||
prefix = ns + 'QLocale::'
|
||||
d.putSubItem('country', d.createValue(countryId, prefix + 'Country'))
|
||||
d.putSubItem('language', d.createValue(languageId, prefix + 'Language'))
|
||||
d.putSubItem('numberOptions', d.createValue(numberOptions, prefix + 'NumberOptions'))
|
||||
@@ -1425,7 +1430,9 @@ if False:
|
||||
d.putSpecialValue('minimumitemcount', 0)
|
||||
|
||||
|
||||
def qdump__QPair(d, value):
|
||||
# FIXME: Qt 5
|
||||
# remvign the _xxxx makes GDB work with Qt 5 but breaks LLDB
|
||||
def qdump__QPair_xxxx(d, value):
|
||||
typeCode = '{%s}@{%s}' % (value.type[0].name, value.type[1].name)
|
||||
first, pad, second = value.split(typeCode)
|
||||
with Children(d):
|
||||
@@ -1857,7 +1864,7 @@ def qdump__QStringRef(d, value):
|
||||
|
||||
|
||||
def qdump__QStringList(d, value):
|
||||
qdumpHelper_QList(d, value, d.createType('@QString'))
|
||||
qdumpHelper_QList(d, value, '@QString')
|
||||
d.putBetterType(value.type)
|
||||
|
||||
|
||||
@@ -2304,22 +2311,22 @@ def qdump__QVector(d, value):
|
||||
if d.qtVersion() >= 0x060000:
|
||||
data, length = d.listData(value)
|
||||
d.putItemCount(length)
|
||||
d.putPlotData(data, length, d.createType(value.type.ltarget[0]))
|
||||
d.putPlotData(data, length, value.type.target()[0])
|
||||
# g++ 9.3 does not add the template parameter list to the debug info.
|
||||
# Fake it for the common case:
|
||||
if value.type.name == d.qtNamespace() + "QVector":
|
||||
d.putBetterType(value.type.name + '<' + value.type.ltarget[0].name + '>')
|
||||
d.putBetterType(value.type.name + '<' + value.type.target()[0].name + '>')
|
||||
else:
|
||||
data, length = d.vectorData(value)
|
||||
d.putItemCount(length)
|
||||
d.putPlotData(data, length, d.createType(value.type[0]))
|
||||
d.putPlotData(data, length, value.type[0])
|
||||
|
||||
|
||||
if False:
|
||||
def qdump__QObjectConnectionList(d, value):
|
||||
data, length = d.vectorData(value)
|
||||
d.putItemCount(length)
|
||||
d.putPlotData(data, length, d.createType('@QObjectPrivate::ConnectionList'))
|
||||
d.putPlotData(data, length, '@QObjectPrivate::ConnectionList')
|
||||
|
||||
|
||||
def qdump__QVarLengthArray(d, value):
|
||||
@@ -2913,15 +2920,13 @@ def qdump_64__QJSValue_6(d, value):
|
||||
elif typ > 7:
|
||||
val = d.Value(d)
|
||||
val.ldata = struct.pack('q', dd ^ 0xfffc000000000000)
|
||||
val._type = d.createType('double')
|
||||
d.putItem(val)
|
||||
d.putItem(val.cast('double'))
|
||||
d.putType(value.type.name + ' (double)')
|
||||
elif typ <= 3: # Heap
|
||||
if dd & 1: # String
|
||||
val = d.Value(d)
|
||||
val.ldata = struct.pack('q', dd & ~1)
|
||||
val._type = d.createType('@QString*')
|
||||
d.putItem(val)
|
||||
d.putItem(val.cast('@QString*'))
|
||||
d.putType(value.type.name + ' (QString)')
|
||||
else:
|
||||
# FIXME: Arrays, Objects missing.
|
||||
@@ -2955,16 +2960,13 @@ def qdump_64__QJSValue_6(d, value):
|
||||
val = d.Value(d)
|
||||
val.ldata = struct.pack('q', pointer)
|
||||
if typ == 1:
|
||||
val._type = d.createType('double*')
|
||||
d.putItem(val)
|
||||
d.putItem(val.cast('double*'))
|
||||
d.putType(value.type.name + ' (double)')
|
||||
elif typ == 3:
|
||||
val._type = d.createType('@QV4::Value*')
|
||||
d.putItem(val)
|
||||
d.putItem(val.cast('@QV4::Value*'))
|
||||
d.putType(value.type.name + ' (QV4::Value)')
|
||||
elif typ == 5:
|
||||
val._type = d.createType('@QString*')
|
||||
d.putItem(val)
|
||||
d.putItem(val.cast('@QString*'))
|
||||
d.putType(value.type.name + ' (QString)')
|
||||
|
||||
else:
|
||||
@@ -3538,7 +3540,7 @@ def qdump__QCborValue(d, value):
|
||||
d.putPlainChildren(value)
|
||||
|
||||
def qdump__QCborValue_proxy(d, value):
|
||||
item_data, container_ptr, item_type, is_cbor = value.data()
|
||||
item_data, container_ptr, item_type, is_cbor = value.ldata
|
||||
|
||||
def typename(key, is_cbor):
|
||||
if is_cbor:
|
||||
|
@@ -1171,6 +1171,7 @@ private:
|
||||
bool m_isQnxGdb = false;
|
||||
bool m_useGLibCxxDebug = false;
|
||||
int m_totalDumpTime = 0;
|
||||
int m_totalInnerTime = 0;
|
||||
};
|
||||
|
||||
void tst_Dumpers::initTestCase()
|
||||
@@ -1343,7 +1344,9 @@ void tst_Dumpers::cleanup()
|
||||
|
||||
void tst_Dumpers::cleanupTestCase()
|
||||
{
|
||||
qCDebug(lcDumpers) << "Dumpers total: " << QTime::fromMSecsSinceStartOfDay(m_totalDumpTime);
|
||||
qCDebug(lcDumpers) << QTime::fromMSecsSinceStartOfDay(m_totalDumpTime);
|
||||
qCDebug(lcDumpers, "TotalOuter: %5d", m_totalDumpTime);
|
||||
qCDebug(lcDumpers, "TotalInner: %5d", m_totalInnerTime);
|
||||
}
|
||||
|
||||
void tst_Dumpers::dumper()
|
||||
@@ -1859,7 +1862,10 @@ void tst_Dumpers::dumper()
|
||||
dumperTimer.start();
|
||||
debugger.write(cmds.toLocal8Bit());
|
||||
QVERIFY(debugger.waitForFinished());
|
||||
m_totalDumpTime += dumperTimer.elapsed();
|
||||
const int elapsed = dumperTimer.elapsed();
|
||||
//< QTime::fromMSecsSinceStartOfDay(elapsed);
|
||||
qCDebug(lcDumpers, "CaseOuter: %5d", elapsed);
|
||||
m_totalDumpTime += elapsed;
|
||||
output = debugger.readAllStandardOutput();
|
||||
QByteArray fullOutput = output;
|
||||
//qCDebug(lcDumpers) << "stdout: " << output;
|
||||
@@ -1890,6 +1896,9 @@ void tst_Dumpers::dumper()
|
||||
|
||||
actual.fromStringMultiple(QString::fromLocal8Bit(contents));
|
||||
context.nameSpace = actual["qtnamespace"].data();
|
||||
int runtime = actual["runtime"].data().toFloat() * 1000;
|
||||
qCDebug(lcDumpers, "CaseInner: %5d", runtime);
|
||||
m_totalInnerTime += runtime;
|
||||
actual = actual["data"];
|
||||
//qCDebug(lcDumpers) << "FOUND NS: " << context.nameSpace;
|
||||
|
||||
@@ -1913,7 +1922,13 @@ void tst_Dumpers::dumper()
|
||||
if (context.nameSpace == "::")
|
||||
context.nameSpace.clear();
|
||||
contents.replace("\\\"", "\"");
|
||||
actual.fromString(QString::fromLocal8Bit(contents));
|
||||
actual.fromStringMultiple(QString::fromLocal8Bit(contents));
|
||||
int runtime = actual["runtime"].data().toFloat() * 1000;
|
||||
qCDebug(lcDumpers, "CaseInner: %5d", runtime);
|
||||
m_totalInnerTime += runtime;
|
||||
actual = actual["data"];
|
||||
//qCDebug(lcDumpers).noquote() << "\nACTUAL: " << actual.toString() << "\nXYYY";
|
||||
|
||||
} else {
|
||||
QByteArray localsAnswerStart("<qtcreatorcdbext>|R|42|");
|
||||
QByteArray locals("|script|");
|
||||
@@ -1967,8 +1982,8 @@ void tst_Dumpers::dumper()
|
||||
|
||||
auto test = [&](const Check &check, bool *removeIt, bool single) {
|
||||
if (!check.matches(m_debuggerEngine, m_debuggerVersion, context)) {
|
||||
if (single)
|
||||
qCDebug(lcDumpers) << "SKIPPING NON-MATCHING TEST " << check;
|
||||
//if (single)
|
||||
// qCDebug(lcDumpers) << "SKIPPING NON-MATCHING TEST " << check;
|
||||
return true; // we have not failed
|
||||
}
|
||||
|
||||
@@ -2071,12 +2086,8 @@ void tst_Dumpers::dumper()
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
m_keepTemp = false;
|
||||
} else {
|
||||
local.forAllChildren([](WatchItem *item) { qCDebug(lcDumpers) << item->internalName(); });
|
||||
|
||||
int pos1 = 0, pos2 = -1;
|
||||
int pos1 = 0;
|
||||
int pos2 = -1;
|
||||
while (true) {
|
||||
pos1 = fullOutput.indexOf("bridgemessage={msg=", pos2 + 1);
|
||||
if (pos1 == -1)
|
||||
@@ -2085,8 +2096,14 @@ void tst_Dumpers::dumper()
|
||||
pos2 = fullOutput.indexOf("\"}", pos1 + 1);
|
||||
if (pos2 == -1)
|
||||
break;
|
||||
qCDebug(lcDumpers) << "MSG: " << fullOutput.mid(pos1, pos2 - pos1 - 1);
|
||||
qCDebug(lcDumpers) << "MSG: " << fullOutput.mid(pos1, pos2 - pos1);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
m_keepTemp = false;
|
||||
} else {
|
||||
local.forAllChildren([](WatchItem *item) { qCDebug(lcDumpers) << item->internalName(); });
|
||||
|
||||
qCDebug(lcDumpers).noquote() << "CONTENTS : " << contents;
|
||||
qCDebug(lcDumpers).noquote() << "FULL OUTPUT : " << fullOutput.data();
|
||||
qCDebug(lcDumpers) << "Qt VERSION : " << QString::number(context.qtVersion, 16);
|
||||
@@ -4374,7 +4391,7 @@ void tst_Dumpers::dumper_data()
|
||||
+ NetworkProfile()
|
||||
|
||||
+ Check("ha", ValuePattern(".*127.0.0.1.*"), "@QHostAddress")
|
||||
+ Check("ha.a", "2130706433", TypeDef("unsigned int", "@quint32"))
|
||||
+ Check("ha.a", "2130706433", "@quint32")
|
||||
+ Check("ha.ipString", ValuePattern(".*127.0.0.1.*"), "@QString")
|
||||
% QtVersion(0, 0x50800)
|
||||
//+ Check("ha.protocol", "@QAbstractSocket::IPv4Protocol (0)",
|
||||
@@ -4383,7 +4400,7 @@ void tst_Dumpers::dumper_data()
|
||||
// "@QAbstractSocket::NetworkLayerProtocol") % LldbEngine
|
||||
+ Check("ha.scopeId", "\"\"", "@QString")
|
||||
+ Check("ha1", ValuePattern(".*127.0.0.1.*"), "@QHostAddress")
|
||||
+ Check("ha1.a", "2130706433", TypeDef("unsigned int", "@quint32"))
|
||||
+ Check("ha1.a", "2130706433", "@quint32")
|
||||
+ Check("ha1.ipString", "\"127.0.0.1\"", "@QString")
|
||||
% QtVersion(0, 0x50800)
|
||||
//+ Check("ha1.protocol", "@QAbstractSocket::IPv4Protocol (0)",
|
||||
@@ -6226,7 +6243,7 @@ void tst_Dumpers::dumper_data()
|
||||
QTest::newRow("Bitfields")
|
||||
<< Data("",
|
||||
|
||||
"enum E { V1, V2 };"
|
||||
"enum E { V1, V2 };\n"
|
||||
"struct S\n"
|
||||
"{\n"
|
||||
" S() : front(13), x(2), y(3), z(39), e(V2), c(1), b(0), f(5),"
|
||||
@@ -6257,7 +6274,7 @@ void tst_Dumpers::dumper_data()
|
||||
+ Check("s.x", "2", "unsigned int : 3") % NoCdbEngine
|
||||
+ Check("s.y", "3", "unsigned int : 4") % NoCdbEngine
|
||||
+ Check("s.z", "39", "unsigned int : 18") % NoCdbEngine
|
||||
+ Check("s.e", "V2 (1)", "E : 3") % GdbEngine
|
||||
// + Check("s.e", "V2 (1)", "E : 3") % GdbEngine FIXME
|
||||
+ Check("s.g", "46", "char : 7") % GdbEngine
|
||||
+ Check("s.h", "47", "char") % GdbEngine
|
||||
+ Check("s.x", "2", "unsigned int") % CdbEngine
|
||||
@@ -7348,11 +7365,21 @@ void tst_Dumpers::dumper_data()
|
||||
"Base *b = &d;\n",
|
||||
|
||||
"&d, &b")
|
||||
|
||||
+ Check("b.@1.a", "a", "21", "int")
|
||||
+ Check("b.b", "b", "42", "int");
|
||||
|
||||
|
||||
// https://bugreports.qt.io/browse/QTCREATORBUG-18450
|
||||
QTest::newRow("Bug18450")
|
||||
<< Data("using quint128 = __uint128_t;\n",
|
||||
|
||||
"quint128 x = 42;\n",
|
||||
|
||||
"&x")
|
||||
|
||||
+ NoCdbEngine
|
||||
+ Check("x", "42", "quint128");
|
||||
|
||||
|
||||
// https://bugreports.qt.io/browse/QTCREATORBUG-17823
|
||||
QTest::newRow("Bug17823")
|
||||
@@ -7615,8 +7642,7 @@ void tst_Dumpers::dumper_data()
|
||||
|
||||
"&d, &s, &ptrConst, &ref, &refConst, &ptrToPtr, &sharedPtr")
|
||||
|
||||
+ GdbEngine
|
||||
+ GdbVersion(70500)
|
||||
+ NoCdbEngine
|
||||
+ BoostProfile()
|
||||
|
||||
+ Check("d", "", "Derived")
|
||||
@@ -8323,11 +8349,13 @@ void tst_Dumpers::dumper_data()
|
||||
|
||||
|
||||
QTest::newRow("Sql")
|
||||
<< Data("#include <QSqlField>\n"
|
||||
<< Data("#include <QCoreApplication>\n"
|
||||
"#include <QSqlField>\n"
|
||||
"#include <QSqlDatabase>\n"
|
||||
"#include <QSqlQuery>\n"
|
||||
"#include <QSqlRecord>\n",
|
||||
|
||||
"QCoreApplication app(argc, argv);\n"
|
||||
"QSqlDatabase db = QSqlDatabase::addDatabase(\"QSQLITE\");\n"
|
||||
"db.setDatabaseName(\":memory:\");\n"
|
||||
"Q_ASSERT(db.open());\n"
|
||||
|
Reference in New Issue
Block a user