File indexing completed on 2024-05-12 04:39:56
0001 # -*- coding: iso-8859-1 -*- 0002 # Pretty-printers for Qt 4 and Qt 5. 0003 0004 # SPDX-FileCopyrightText: 2009 Niko Sams <niko.sams@gmail.com> 0005 # 0006 # SPDX-License-Identifier: GPL-2.0-or-later 0007 0008 import gdb 0009 import itertools 0010 import re 0011 import time 0012 0013 from helper import * 0014 0015 class QStringPrinter: 0016 0017 def __init__(self, val): 0018 self.val = val 0019 0020 def to_string(self): 0021 ret = "" 0022 0023 # The QString object may not be initialized yet. In this case 'size' is a bogus value 0024 # or in case of Qt5, 'd' is an invalid pointer and the following lines might throw memory 0025 # access error. Hence the try/catch. 0026 try: 0027 size = self.val['d']['size'] 0028 if size == 0: 0029 return ret 0030 isQt4 = has_field(self.val['d'], 'data') # Qt4 has d->data, Qt5 doesn't. 0031 isQt6 = has_field(self.val['d'], 'ptr') # Qt6 has d->ptr, Qt5 doesn't. 0032 if isQt4: 0033 dataAsCharPointer = self.val['d']['data'].cast(gdb.lookup_type("char").pointer()) 0034 elif isQt6: 0035 dataAsCharPointer = self.val['d']['ptr'].cast(gdb.lookup_type("char").pointer()) 0036 else: 0037 dataAsCharPointer = (self.val['d'] + 1).cast(gdb.lookup_type("char").pointer()) 0038 ret = dataAsCharPointer.string(encoding = 'UTF-16', length = size * 2) 0039 except Exception: 0040 # swallow the exception and return empty string 0041 pass 0042 return ret 0043 0044 def display_hint (self): 0045 return 'string' 0046 0047 class QByteArrayPrinter: 0048 0049 def __init__(self, val): 0050 self.val = val 0051 # Qt4 has 'data', Qt5 doesn't 0052 self.isQt4 = has_field(self.val['d'], 'data') 0053 # Qt6 has d.ptr, Qt5 doesn't 0054 self.isQt6 = has_field(self.val['d'], 'ptr') 0055 0056 class _iterator(Iterator): 0057 def __init__(self, data, size): 0058 self.data = data 0059 self.size = size 0060 self.count = 0 0061 0062 def __iter__(self): 0063 return self 0064 0065 def __next__(self): 0066 if self.count >= self.size: 0067 raise StopIteration 0068 count = self.count 0069 self.count = self.count + 1 0070 return ('[%d]' % count, self.data[count]) 0071 0072 def stringData(self): 0073 if self.isQt4: 0074 return self.val['d']['data'] 0075 elif self.isQt6: 0076 return self.val['d']['ptr'].cast(gdb.lookup_type("char").pointer()) 0077 else: 0078 return self.val['d'].cast(gdb.lookup_type("char").const().pointer()) + self.val['d']['offset'] 0079 0080 def children(self): 0081 return self._iterator(self.stringData(), self.val['d']['size']) 0082 0083 def to_string(self): 0084 #todo: handle charset correctly 0085 return self.stringData() 0086 0087 def display_hint (self): 0088 return 'string' 0089 0090 class QListPrinter: 0091 "Print a QList" 0092 0093 class _iterator(Iterator): 0094 def __init__(self, nodetype, d): 0095 self.nodetype = nodetype 0096 self.d = d 0097 self.count = 0 0098 0099 #from QTypeInfo::isLarge 0100 isLarge = self.nodetype.sizeof > gdb.lookup_type('void').pointer().sizeof 0101 0102 isPointer = self.nodetype.code == gdb.TYPE_CODE_PTR 0103 0104 #unfortunately we can't use QTypeInfo<T>::isStatic as it's all inlined, so use 0105 #this list of types that use Q_DECLARE_TYPEINFO(T, Q_MOVABLE_TYPE) 0106 #(obviously it won't work for custom types) 0107 movableTypes = ['QRect', 'QRectF', 'QString', 'QMargins', 'QLocale', 'QChar', 'QDate', 'QTime', 'QDateTime', 'QVector', 0108 'QRegExpr', 'QPoint', 'QPointF', 'QByteArray', 'QSize', 'QSizeF', 'QBitArray', 'QLine', 'QLineF', 'QModelIndex', 'QPersitentModelIndex', 0109 'QVariant', 'QFileInfo', 'QUrl', 'QXmlStreamAttribute', 'QXmlStreamNamespaceDeclaration', 'QXmlStreamNotationDeclaration', 0110 'QXmlStreamEntityDeclaration', 'QPair<int, int>'] 0111 #this list of types that use Q_DECLARE_TYPEINFO(T, Q_PRIMITIVE_TYPE) (from qglobal.h) 0112 primitiveTypes = ['bool', 'char', 'signed char', 'unsigned char', 'short', 'unsigned short', 'int', 'unsigned int', 'long', 'unsigned long', 'long long', 'unsigned long long', 'float', 'double'] 0113 0114 if movableTypes.count(self.nodetype.tag) or primitiveTypes.count(str(self.nodetype)): 0115 isStatic = False 0116 else: 0117 isStatic = not isPointer 0118 0119 self.externalStorage = isLarge or isStatic #see QList::Node::t() 0120 0121 0122 def __iter__(self): 0123 return self 0124 0125 def __next__(self): 0126 isQt6 = has_field(self.d, 'size') 0127 if isQt6: 0128 size = self.d['size'] 0129 else: 0130 size = self.d['end'] - self.d['begin'] 0131 0132 if self.count >= size: 0133 raise StopIteration 0134 count = self.count 0135 0136 if isQt6: 0137 value = self.d['ptr'] + count 0138 else: 0139 array = self.d['array'].address + self.d['begin'] + count 0140 if self.externalStorage: 0141 value = array.cast(gdb.lookup_type('QList<%s>::Node' % self.nodetype).pointer())['v'] 0142 else: 0143 value = array 0144 self.count = self.count + 1 0145 return ('[%d]' % count, value.cast(self.nodetype.pointer()).dereference()) 0146 0147 def __init__(self, val, container, itype): 0148 self.d = val['d'] 0149 self.container = container 0150 self.isQt6 = has_field(self.d, 'size') 0151 0152 if self.isQt6: 0153 self.size = self.d['size'] 0154 else: 0155 self.size = self.d['end'] - self.d['begin'] 0156 0157 if itype == None: 0158 self.itype = val.type.template_argument(0) 0159 else: 0160 self.itype = gdb.lookup_type(itype) 0161 0162 def children(self): 0163 return self._iterator(self.itype, self.d) 0164 0165 def to_string(self): 0166 return "%s<%s> (size = %s)" % ( self.container, self.itype, self.size ) 0167 0168 class QVectorPrinter: 0169 "Print a QVector" 0170 0171 class _iterator(Iterator): 0172 def __init__(self, nodetype, data, size): 0173 self.nodetype = nodetype 0174 self.data = data 0175 self.size = size 0176 self.count = 0 0177 0178 def __iter__(self): 0179 return self 0180 0181 def __next__(self): 0182 if self.count >= self.size: 0183 raise StopIteration 0184 count = self.count 0185 0186 self.count = self.count + 1 0187 return ('[%d]' % count, self.data[count]) 0188 0189 def __init__(self, val, container): 0190 self.val = val 0191 self.container = container 0192 self.itype = self.val.type.template_argument(0) 0193 0194 def children(self): 0195 isQt4 = has_field(self.val['d'], 'p') # Qt4 has 'p', Qt5 doesn't 0196 if isQt4: 0197 return self._iterator(self.itype, self.val['p']['array'], self.val['p']['size']) 0198 else: 0199 data = self.val['d'].cast(gdb.lookup_type("char").const().pointer()) + self.val['d']['offset'] 0200 return self._iterator(self.itype, data.cast(self.itype.pointer()), self.val['d']['size']) 0201 0202 def to_string(self): 0203 size = self.val['d']['size'] 0204 0205 return "%s<%s> (size = %s)" % ( self.container, self.itype, size ) 0206 0207 class QLinkedListPrinter: 0208 "Print a QLinkedList" 0209 0210 class _iterator(Iterator): 0211 def __init__(self, nodetype, begin, size): 0212 self.nodetype = nodetype 0213 self.it = begin 0214 self.pos = 0 0215 self.size = size 0216 0217 def __iter__(self): 0218 return self 0219 0220 def __next__(self): 0221 if self.pos >= self.size: 0222 raise StopIteration 0223 0224 pos = self.pos 0225 val = self.it['t'] 0226 self.it = self.it['n'] 0227 self.pos = self.pos + 1 0228 return ('[%d]' % pos, val) 0229 0230 def __init__(self, val): 0231 self.val = val 0232 self.itype = self.val.type.template_argument(0) 0233 0234 def children(self): 0235 return self._iterator(self.itype, self.val['e']['n'], self.val['d']['size']) 0236 0237 def to_string(self): 0238 size = self.val['d']['size'] 0239 0240 return "QLinkedList<%s> (size = %s)" % ( self.itype, size ) 0241 0242 class QMapPrinter: 0243 "Print a QMap" 0244 0245 class _iteratorQt4(Iterator): 0246 def __init__(self, val): 0247 self.val = val 0248 self.ktype = self.val.type.template_argument(0) 0249 self.vtype = self.val.type.template_argument(1) 0250 self.data_node = self.val['e']['forward'][0] 0251 self.count = 0 0252 0253 def __iter__(self): 0254 return self 0255 0256 def payload (self): 0257 if gdb.parse_and_eval: 0258 ret = int(gdb.parse_and_eval('QMap<%s, %s>::payload()' % (self.ktype, self.vtype))) 0259 if (ret): return ret; 0260 0261 #if the inferior function call didn't work, let's try to calculate ourselves 0262 0263 #we can't use QMapPayloadNode as it's inlined 0264 #as a workaround take the sum of sizeof(members) 0265 ret = self.ktype.sizeof 0266 ret += self.vtype.sizeof 0267 ret += gdb.lookup_type('void').pointer().sizeof 0268 0269 #but because of data alignment the value can be higher 0270 #so guess it's aliged by sizeof(void*) 0271 #TODO: find a real solution for this problem 0272 ret += ret % gdb.lookup_type('void').pointer().sizeof 0273 0274 #for some reason booleans are different 0275 if str(self.vtype) == 'bool': 0276 ret += 2 0277 0278 ret -= gdb.lookup_type('void').pointer().sizeof 0279 0280 return ret 0281 0282 def concrete (self, data_node): 0283 node_type = gdb.lookup_type('QMapNode<%s, %s>' % (self.ktype, self.vtype)).pointer() 0284 return (data_node.cast(gdb.lookup_type('char').pointer()) - self.payload()).cast(node_type) 0285 0286 def __next__(self): 0287 if self.data_node == self.val['e']: 0288 raise StopIteration 0289 node = self.concrete(self.data_node).dereference() 0290 if self.count % 2 == 0: 0291 item = node['key'] 0292 else: 0293 item = node['value'] 0294 self.data_node = node['forward'][0] 0295 0296 result = ('[%d]' % self.count, item) 0297 self.count = self.count + 1 0298 return result 0299 0300 class _iteratorQt5: 0301 def __init__(self, val): 0302 realtype = val.type.strip_typedefs() 0303 keytype = realtype.template_argument(0) 0304 valtype = realtype.template_argument(1) 0305 node_type = gdb.lookup_type('QMapData<' + keytype.name + ',' + valtype.name + '>::Node') 0306 self.node_p_type = node_type.pointer() 0307 self.root = val['d']['header'] 0308 self.current = None 0309 self.next_is_key = True 0310 self.i = -1 0311 # we store the path here to avoid keeping re-fetching 0312 # values from the inferior (also, skips the pointer 0313 # arithmetic involved in using the parent pointer) 0314 self.path = [] 0315 0316 def __iter__(self): 0317 return self 0318 0319 def moveToNextNode(self): 0320 if self.current is None: 0321 # find the leftmost node 0322 if not self.root['left']: 0323 return False 0324 self.current = self.root 0325 while self.current['left']: 0326 self.path.append(self.current) 0327 self.current = self.current['left'] 0328 elif self.current['right']: 0329 self.path.append(self.current) 0330 self.current = self.current['right'] 0331 while self.current['left']: 0332 self.path.append(self.current) 0333 self.current = self.current['left'] 0334 else: 0335 last = self.current 0336 self.current = self.path.pop() 0337 while self.current['right'] == last: 0338 last = self.current 0339 self.current = self.path.pop() 0340 # if there are no more parents, we are at the root 0341 if len(self.path) == 0: 0342 return False 0343 return True 0344 0345 def __next__(self): 0346 if self.next_is_key: 0347 if not self.moveToNextNode(): 0348 raise StopIteration 0349 self.current_typed = self.current.reinterpret_cast(self.node_p_type) 0350 self.next_is_key = False 0351 self.i += 1 0352 return ('key' + str(self.i), self.current_typed['key']) 0353 else: 0354 self.next_is_key = True 0355 return ('value' + str(self.i), self.current_typed['value']) 0356 0357 def next(self): 0358 return self.__next__() 0359 0360 def __init__(self, val, container): 0361 self.val = val 0362 self.container = container 0363 0364 def children(self): 0365 if self.val['d']['size'] == 0: 0366 return [] 0367 0368 isQt4 = has_field(self.val, 'e') # Qt4 has 'e', Qt5 doesn't 0369 if isQt4: 0370 return self._iteratorQt4(self.val) 0371 else: 0372 return self._iteratorQt5(self.val) 0373 0374 def to_string(self): 0375 size = self.val['d']['size'] 0376 0377 return "%s<%s, %s> (size = %s)" % ( self.container, self.val.type.template_argument(0), self.val.type.template_argument(1), size ) 0378 0379 def display_hint (self): 0380 return 'map' 0381 0382 class QHashPrinter: 0383 "Print a QHash" 0384 0385 class _iterator(Iterator): 0386 def __init__(self, val): 0387 self.val = val 0388 self.d = self.val['d'] 0389 self.ktype = self.val.type.template_argument(0) 0390 self.vtype = self.val.type.template_argument(1) 0391 self.end_node = self.d.cast(gdb.lookup_type('QHashData::Node').pointer()) 0392 self.data_node = self.firstNode() 0393 self.count = 0 0394 0395 def __iter__(self): 0396 return self 0397 0398 def hashNode (self): 0399 "Casts the current QHashData::Node to a QHashNode and returns the result. See also QHash::concrete()" 0400 return self.data_node.cast(gdb.lookup_type('QHashNode<%s, %s>' % (self.ktype, self.vtype)).pointer()) 0401 0402 def firstNode (self): 0403 "Get the first node, See QHashData::firstNode()." 0404 e = self.d.cast(gdb.lookup_type('QHashData::Node').pointer()) 0405 #print "QHashData::firstNode() e %s" % e 0406 bucketNum = 0 0407 bucket = self.d['buckets'][bucketNum] 0408 #print "QHashData::firstNode() *bucket %s" % bucket 0409 n = self.d['numBuckets'] 0410 #print "QHashData::firstNode() n %s" % n 0411 while n: 0412 #print "QHashData::firstNode() in while, n %s" % n; 0413 if bucket != e: 0414 #print "QHashData::firstNode() in while, return *bucket %s" % bucket 0415 return bucket 0416 bucketNum += 1 0417 bucket = self.d['buckets'][bucketNum] 0418 #print "QHashData::firstNode() in while, new bucket %s" % bucket 0419 n -= 1 0420 #print "QHashData::firstNode() return e %s" % e 0421 return e 0422 0423 0424 def nextNode (self, node): 0425 "Get the nextNode after the current, see also QHashData::nextNode()." 0426 #print "******************************** nextNode" 0427 #print "nextNode: node %s" % node 0428 next = node['next'].cast(gdb.lookup_type('QHashData::Node').pointer()) 0429 e = next 0430 0431 #print "nextNode: next %s" % next 0432 if next['next']: 0433 #print "nextNode: return next" 0434 return next 0435 0436 #print "nextNode: node->h %s" % node['h'] 0437 #print "nextNode: numBuckets %s" % self.d['numBuckets'] 0438 start = (node['h'] % self.d['numBuckets']) + 1 0439 bucketNum = start 0440 #print "nextNode: start %s" % start 0441 bucket = self.d['buckets'][start] 0442 #print "nextNode: bucket %s" % bucket 0443 n = self.d['numBuckets'] - start 0444 #print "nextNode: n %s" % n 0445 while n: 0446 #print "nextNode: in while; n %s" % n 0447 #print "nextNode: in while; e %s" % e 0448 #print "nextNode: in while; *bucket %s" % bucket 0449 if bucket != e: 0450 #print "nextNode: in while; return bucket %s" % bucket 0451 return bucket 0452 bucketNum += 1 0453 bucket = self.d['buckets'][bucketNum] 0454 n -= 1 0455 #print "nextNode: return e %s" % e 0456 return e 0457 0458 def __next__(self): 0459 "GDB iteration, first call returns key, second value and then jumps to the next hash node." 0460 if self.data_node == self.end_node: 0461 raise StopIteration 0462 0463 node = self.hashNode() 0464 0465 if self.count % 2 == 0: 0466 item = node['key'] 0467 else: 0468 item = node['value'] 0469 self.data_node = self.nextNode(self.data_node) 0470 0471 self.count = self.count + 1 0472 return ('[%d]' % self.count, item) 0473 0474 def __init__(self, val, container): 0475 self.val = val 0476 self.container = container 0477 0478 def children(self): 0479 return self._iterator(self.val) 0480 0481 def to_string(self): 0482 size = self.val['d']['size'] 0483 0484 return "%s<%s, %s> (size = %s)" % ( self.container, self.val.type.template_argument(0), self.val.type.template_argument(1), size ) 0485 0486 def display_hint (self): 0487 return 'map' 0488 0489 class QDatePrinter: 0490 0491 def __init__(self, val): 0492 self.val = val 0493 0494 def to_string(self): 0495 julianDay = self.val['jd'] 0496 0497 if julianDay == 0: 0498 return "invalid QDate" 0499 0500 # Copied from Qt sources 0501 if julianDay >= 2299161: 0502 # Gregorian calendar starting from October 15, 1582 0503 # This algorithm is from Henry F. Fliegel and Thomas C. Van Flandern 0504 ell = julianDay + 68569; 0505 n = (4 * ell) / 146097; 0506 ell = ell - (146097 * n + 3) / 4; 0507 i = (4000 * (ell + 1)) / 1461001; 0508 ell = ell - (1461 * i) / 4 + 31; 0509 j = (80 * ell) / 2447; 0510 d = ell - (2447 * j) / 80; 0511 ell = j / 11; 0512 m = j + 2 - (12 * ell); 0513 y = 100 * (n - 49) + i + ell; 0514 else: 0515 # Julian calendar until October 4, 1582 0516 # Algorithm from Frequently Asked Questions about Calendars by Claus Toendering 0517 julianDay += 32082; 0518 dd = (4 * julianDay + 3) / 1461; 0519 ee = julianDay - (1461 * dd) / 4; 0520 mm = ((5 * ee) + 2) / 153; 0521 d = ee - (153 * mm + 2) / 5 + 1; 0522 m = mm + 3 - 12 * (mm / 10); 0523 y = dd - 4800 + (mm / 10); 0524 if y <= 0: 0525 --y; 0526 return "%d-%02d-%02d" % (y, m, d) 0527 0528 class QTimePrinter: 0529 0530 def __init__(self, val): 0531 self.val = val 0532 0533 def to_string(self): 0534 ds = self.val['mds'] 0535 0536 if ds == -1: 0537 return "invalid QTime" 0538 0539 MSECS_PER_HOUR = 3600000 0540 SECS_PER_MIN = 60 0541 MSECS_PER_MIN = 60000 0542 0543 hour = ds / MSECS_PER_HOUR 0544 minute = (ds % MSECS_PER_HOUR) / MSECS_PER_MIN 0545 second = (ds / 1000)%SECS_PER_MIN 0546 msec = ds % 1000 0547 return "%02d:%02d:%02d.%03d" % (hour, minute, second, msec) 0548 0549 class QDateTimePrinter: 0550 0551 def __init__(self, val): 0552 self.val = val 0553 0554 def to_string(self): 0555 time_t = gdb.parse_and_eval("reinterpret_cast<const QDateTime*>(%s)->toSecsSinceEpoch()" % self.val.address) 0556 return time.ctime(int(time_t)) 0557 0558 class QUrlPrinter: 0559 0560 def __init__(self, val): 0561 self.val = val 0562 0563 def to_string(self): 0564 # first try to access the Qt 5 data 0565 try: 0566 int_type = gdb.lookup_type('int') 0567 string_type = gdb.lookup_type('QString') 0568 string_pointer = string_type.pointer() 0569 0570 addr = self.val['d'].cast(gdb.lookup_type('char').pointer()) 0571 if not addr: 0572 return "<invalid>" 0573 # skip QAtomicInt ref 0574 addr += int_type.sizeof 0575 # handle int port 0576 port = addr.cast(int_type.pointer()).dereference() 0577 addr += int_type.sizeof 0578 # handle QString scheme 0579 scheme = QStringPrinter(addr.cast(string_pointer).dereference()).to_string() 0580 addr += string_type.sizeof 0581 # handle QString username 0582 username = QStringPrinter(addr.cast(string_pointer).dereference()).to_string() 0583 addr += string_type.sizeof 0584 # skip QString password 0585 addr += string_type.sizeof 0586 # handle QString host 0587 host = QStringPrinter(addr.cast(string_pointer).dereference()).to_string() 0588 addr += string_type.sizeof 0589 # handle QString path 0590 path = QStringPrinter(addr.cast(string_pointer).dereference()).to_string() 0591 addr += string_type.sizeof 0592 # handle QString query 0593 query = QStringPrinter(addr.cast(string_pointer).dereference()).to_string() 0594 addr += string_type.sizeof 0595 # handle QString fragment 0596 fragment = QStringPrinter(addr.cast(string_pointer).dereference()).to_string() 0597 0598 url = "" 0599 if len(scheme) > 0: 0600 # TODO: always adding // is apparently not compliant in all cases 0601 url += scheme + "://" 0602 if len(host) > 0: 0603 if len(username) > 0: 0604 url += username + "@" 0605 url += host 0606 if port != -1: 0607 url += ":" + str(port) 0608 url += path 0609 if len(query) > 0: 0610 url += "?" + query 0611 if len(fragment) > 0: 0612 url += "#" + fragment 0613 0614 return url 0615 except: 0616 pass 0617 # then try to print directly, but that might lead to issues (see http://sourceware-org.1504.n7.nabble.com/help-Calling-malloc-from-a-Python-pretty-printer-td284031.html) 0618 try: 0619 return gdb.parse_and_eval("reinterpret_cast<const QUrl*>(%s)->toString((QUrl::FormattingOptions)QUrl::PrettyDecoded)" % self.val.address) 0620 except: 0621 pass 0622 # if everything fails, maybe we deal with Qt 4 code 0623 try: 0624 return self.val['d']['encodedOriginal'] 0625 except RuntimeError: 0626 #if no debug information is available for Qt, try guessing the correct address for encodedOriginal 0627 #problem with this is that if QUrlPrivate members get changed, this fails 0628 offset = gdb.lookup_type('int').sizeof 0629 offset += offset % gdb.lookup_type('void').pointer().sizeof #alignment 0630 offset += gdb.lookup_type('QString').sizeof * 6 0631 offset += gdb.lookup_type('QByteArray').sizeof 0632 encodedOriginal = self.val['d'].cast(gdb.lookup_type('char').pointer()); 0633 encodedOriginal += offset 0634 encodedOriginal = encodedOriginal.cast(gdb.lookup_type('QByteArray').pointer()).dereference(); 0635 encodedOriginal = encodedOriginal['d']['data'].string() 0636 return encodedOriginal 0637 0638 class QSetPrinter: 0639 "Print a QSet" 0640 0641 def __init__(self, val): 0642 self.val = val 0643 0644 class _iterator(Iterator): 0645 def __init__(self, hashIterator): 0646 self.hashIterator = hashIterator 0647 self.count = 0 0648 0649 def __iter__(self): 0650 return self 0651 0652 def __next__(self): 0653 if self.hashIterator.data_node == self.hashIterator.end_node: 0654 raise StopIteration 0655 0656 node = self.hashIterator.hashNode() 0657 0658 item = node['key'] 0659 self.hashIterator.data_node = self.hashIterator.nextNode(self.hashIterator.data_node) 0660 0661 self.count = self.count + 1 0662 return ('[%d]' % (self.count-1), item) 0663 0664 def children(self): 0665 hashPrinter = QHashPrinter(self.val['q_hash'], None) 0666 hashIterator = hashPrinter._iterator(self.val['q_hash']) 0667 return self._iterator(hashIterator) 0668 0669 def to_string(self): 0670 size = self.val['q_hash']['d']['size'] 0671 0672 return "QSet<%s> (size = %s)" % ( self.val.type.template_argument(0), size ) 0673 0674 0675 class QCharPrinter: 0676 0677 def __init__(self, val): 0678 self.val = val 0679 0680 def to_string(self): 0681 return unichr(self.val['ucs']) 0682 0683 def display_hint (self): 0684 return 'string' 0685 0686 class QUuidPrinter: 0687 0688 def __init__(self, val): 0689 self.val = val 0690 0691 def to_string(self): 0692 return "QUuid({%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x})" % (int(self.val['data1']), int(self.val['data2']), int(self.val['data3']), 0693 int(self.val['data4'][0]), int(self.val['data4'][1]), 0694 int(self.val['data4'][2]), int(self.val['data4'][3]), 0695 int(self.val['data4'][4]), int(self.val['data4'][5]), 0696 int(self.val['data4'][6]), int(self.val['data4'][7])) 0697 0698 def display_hint (self): 0699 return 'string' 0700 0701 class QVariantPrinter: 0702 0703 def __init__(self, val): 0704 self.val = val 0705 0706 def to_string(self): 0707 d = self.val['d'] 0708 0709 if d['is_null']: 0710 return "QVariant(NULL)" 0711 0712 data_type = d['type'] 0713 type_str = ("type = %d" % data_type) 0714 try: 0715 typeAsCharPointer = (gdb.parse_and_eval("QVariant::typeToName(%d)" % data_type).cast(gdb.lookup_type("char").pointer())) 0716 if typeAsCharPointer: 0717 type_str = typeAsCharPointer.string(encoding = 'UTF-8') 0718 except Exception as e: 0719 pass 0720 0721 data = d['data'] 0722 is_shared = d['is_shared'] 0723 value_str = "" 0724 if is_shared: 0725 private_shared = data['shared'].dereference() 0726 value_str = "PrivateShared(%s)" % hex(private_shared['ptr']) 0727 elif type_str.startswith("type = "): 0728 value_str = str(data['ptr']) 0729 else: 0730 type_obj = None 0731 try: 0732 type_obj = gdb.lookup_type(type_str) 0733 except Exception as e: 0734 value_str = str(data['ptr']) 0735 if type_obj: 0736 if type_obj.sizeof > type_obj.pointer().sizeof: 0737 value_ptr = data['ptr'].reinterpret_cast(type_obj.const().pointer()) 0738 value_str = str(value_ptr.dereference()) 0739 else: 0740 value_ptr = data['c'].address.reinterpret_cast(type_obj.const().pointer()) 0741 value_str = str(value_ptr.dereference()) 0742 0743 return "QVariant(%s, %s)" % (type_str, value_str) 0744 0745 pretty_printers_dict = {} 0746 0747 def register_qt_printers (obj): 0748 if obj == None: 0749 obj = gdb 0750 0751 obj.pretty_printers.append(FunctionLookup(gdb, pretty_printers_dict)) 0752 0753 def build_dictionary (): 0754 pretty_printers_dict[re.compile('^QString$')] = lambda val: QStringPrinter(val) 0755 pretty_printers_dict[re.compile('^QByteArray$')] = lambda val: QByteArrayPrinter(val) 0756 pretty_printers_dict[re.compile('^QList<.*>$')] = lambda val: QListPrinter(val, 'QList', None) 0757 pretty_printers_dict[re.compile('^QStringList$')] = lambda val: QListPrinter(val, 'QStringList', 'QString') 0758 pretty_printers_dict[re.compile('^QQueue')] = lambda val: QListPrinter(val, 'QQueue', None) 0759 pretty_printers_dict[re.compile('^QVector<.*>$')] = lambda val: QVectorPrinter(val, 'QVector') 0760 pretty_printers_dict[re.compile('^QStack<.*>$')] = lambda val: QVectorPrinter(val, 'QStack') 0761 pretty_printers_dict[re.compile('^QLinkedList<.*>$')] = lambda val: QLinkedListPrinter(val) 0762 pretty_printers_dict[re.compile('^QMap<.*>$')] = lambda val: QMapPrinter(val, 'QMap') 0763 pretty_printers_dict[re.compile('^QMultiMap<.*>$')] = lambda val: QMapPrinter(val, 'QMultiMap') 0764 pretty_printers_dict[re.compile('^QHash<.*>$')] = lambda val: QHashPrinter(val, 'QHash') 0765 pretty_printers_dict[re.compile('^QMultiHash<.*>$')] = lambda val: QHashPrinter(val, 'QMultiHash') 0766 pretty_printers_dict[re.compile('^QDate$')] = lambda val: QDatePrinter(val) 0767 pretty_printers_dict[re.compile('^QTime$')] = lambda val: QTimePrinter(val) 0768 pretty_printers_dict[re.compile('^QDateTime$')] = lambda val: QDateTimePrinter(val) 0769 pretty_printers_dict[re.compile('^QUrl$')] = lambda val: QUrlPrinter(val) 0770 pretty_printers_dict[re.compile('^QSet<.*>$')] = lambda val: QSetPrinter(val) 0771 pretty_printers_dict[re.compile('^QChar$')] = lambda val: QCharPrinter(val) 0772 pretty_printers_dict[re.compile('^QUuid')] = lambda val: QUuidPrinter(val) 0773 pretty_printers_dict[re.compile('^QVariant')] = lambda val: QVariantPrinter(val) 0774 0775 0776 build_dictionary ()