1############################################################################ 2# 3# Copyright (C) 2016 The Qt Company Ltd. 4# Contact: https://www.qt.io/licensing/ 5# 6# This file is part of Qt Creator. 7# 8# Commercial License Usage 9# Licensees holding valid commercial Qt licenses may use this file in 10# accordance with the commercial license agreement provided with the 11# Software or, alternatively, in accordance with the terms contained in 12# a written agreement between you and The Qt Company. For licensing terms 13# and conditions see https://www.qt.io/terms-conditions. For further 14# information use the contact form at https://www.qt.io/contact-us. 15# 16# GNU General Public License Usage 17# Alternatively, this file may be used under the terms of the GNU 18# General Public License version 3 as published by the Free Software 19# Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20# included in the packaging of this file. Please review the following 21# information to ensure the GNU General Public License requirements will 22# be met: https://www.gnu.org/licenses/gpl-3.0.html. 23# 24############################################################################ 25 26from dumper import Children, SubItem 27from utils import TypeCode, DisplayFormat 28import re 29 30####################################################################### 31# 32# SSE 33# 34####################################################################### 35 36 37def qdump____m128(d, value): 38 d.putEmptyValue() 39 d.putExpandable() 40 if d.isExpanded(): 41 d.putArrayData(value.address(), 4, d.lookupType('float')) 42 43 44def qdump____m256(d, value): 45 d.putEmptyValue() 46 d.putExpandable() 47 if d.isExpanded(): 48 d.putArrayData(value.address(), 8, d.lookupType('float')) 49 50 51def qdump____m512(d, value): 52 d.putEmptyValue() 53 d.putExpandable() 54 if d.isExpanded(): 55 d.putArrayData(value.address(), 16, d.lookupType('float')) 56 57 58def qdump____m128d(d, value): 59 d.putEmptyValue() 60 d.putExpandable() 61 if d.isExpanded(): 62 d.putArrayData(value.address(), 2, d.lookupType('double')) 63 64 65def qdump____m256d(d, value): 66 d.putEmptyValue() 67 d.putExpandable() 68 if d.isExpanded(): 69 d.putArrayData(value.address(), 4, d.lookupType('double')) 70 71 72def qdump____m512d(d, value): 73 d.putEmptyValue() 74 d.putExpandable() 75 if d.isExpanded(): 76 d.putArrayData(value.address(), 8, d.lookupType('double')) 77 78 79def qdump____m128i(d, value): 80 data = d.hexencode(value.data(16)) 81 d.putValue(':'.join('%04x' % int(data[i:i + 4], 16) for i in range(0, 32, 4))) 82 d.putExpandable() 83 if d.isExpanded(): 84 with Children(d): 85 addr = value.address() 86 d.putArrayItem('uint8x16', addr, 16, 'unsigned char') 87 d.putArrayItem('uint16x8', addr, 8, 'unsigned short') 88 d.putArrayItem('uint32x4', addr, 4, 'unsigned int') 89 d.putArrayItem('uint64x2', addr, 2, 'unsigned long long') 90 91 92def qdump____m256i(d, value): 93 data = d.hexencode(value.data(32)) 94 d.putValue(':'.join('%04x' % int(data[i:i + 4], 16) for i in range(0, 64, 4))) 95 d.putExpandable() 96 if d.isExpanded(): 97 with Children(d): 98 addr = value.address() 99 d.putArrayItem('uint8x32', addr, 32, 'unsigned char') 100 d.putArrayItem('uint16x16', addr, 16, 'unsigned short') 101 d.putArrayItem('uint32x8', addr, 8, 'unsigned int') 102 d.putArrayItem('uint64x4', addr, 4, 'unsigned long long') 103 104 105def qdump____m512i(d, value): 106 data = d.hexencode(value.data(64)) 107 d.putValue(':'.join('%04x' % int(data[i:i + 4], 16) for i in range(0, 64, 4)) 108 + ', ' + ':'.join('%04x' % int(data[i:i + 4], 16) for i in range(64, 128, 4))) 109 d.putExpandable() 110 if d.isExpanded(): 111 with Children(d): 112 d.putArrayItem('uint32x16', value.address(), 16, 'unsigned int') 113 d.putArrayItem('uint64x8', value.address(), 8, 'unsigned long long') 114 115####################################################################### 116# 117# GSL 118# 119####################################################################### 120 121 122def qform__std__array(): 123 return [DisplayFormat.ArrayPlot] 124 125 126def qdump__gsl__span(d, value): 127 size, pointer = value.split('pp') 128 d.putItemCount(size) 129 if d.isExpanded(): 130 d.putPlotData(pointer, size, value.type[0]) 131 132 133def qdump__gsl__byte(d, value): 134 d.putValue(value.integer()) 135 136####################################################################### 137# 138# Eigen 139# 140####################################################################### 141 142#def qform__Eigen__Matrix(): 143# return 'Transposed' 144 145 146def qdump__Eigen__Matrix(d, value): 147 innerType = value.type[0] 148 argRow = value.type[1] 149 argCol = value.type[2] 150 options = value.type[3] 151 rowMajor = (int(options) & 0x1) 152 # The magic dimension value is -1 in Eigen3, but 10000 in Eigen2. 153 # 10000 x 10000 matrices are rare, vectors of dim 10000 less so. 154 # So 'fix' only the matrix case: 155 if argCol == 10000 and argRow == 10000: 156 argCol = -1 157 argRow = -1 158 if argCol != -1 and argRow != -1: 159 nrows = argRow 160 ncols = argCol 161 p = value.address() 162 else: 163 storage = value['m_storage'] 164 nrows = storage['m_rows'].integer() if argRow == -1 else argRow 165 ncols = storage['m_cols'].integer() if argCol == -1 else argCol 166 p = storage['m_data'].pointer() 167 innerSize = innerType.size() 168 d.putValue('(%s x %s), %s' % (nrows, ncols, ['ColumnMajor', 'RowMajor'][rowMajor])) 169 d.putField('keeporder', '1') 170 d.putNumChild(nrows * ncols) 171 172 limit = 10000 173 nncols = min(ncols, limit) 174 nnrows = min(nrows, limit * limit / nncols) 175 if d.isExpanded(): 176 #format = d.currentItemFormat() # format == 1 is 'Transposed' 177 with Children(d, nrows * ncols, childType=innerType): 178 if ncols == 1 or nrows == 1: 179 for i in range(0, min(nrows * ncols, 10000)): 180 d.putSubItem(i, d.createValue(p + i * innerSize, innerType)) 181 elif rowMajor == 1: 182 s = 0 183 for i in range(0, nnrows): 184 for j in range(0, nncols): 185 v = d.createValue(p + (i * ncols + j) * innerSize, innerType) 186 d.putNamedSubItem(s, v, '[%d,%d]' % (i, j)) 187 s = s + 1 188 else: 189 s = 0 190 for j in range(0, nncols): 191 for i in range(0, nnrows): 192 v = d.createValue(p + (i + j * nrows) * innerSize, innerType) 193 d.putNamedSubItem(s, v, '[%d,%d]' % (i, j)) 194 s = s + 1 195 196 197####################################################################### 198# 199# Nim 200# 201####################################################################### 202 203def qdump__NimStringDesc(d, value): 204 size, reserved = value.split('pp') 205 data = value.address() + 2 * d.ptrSize() 206 d.putBetterType('string') 207 d.putCharArrayHelper(data, size, d.createType('char'), 'utf8') 208 209 210def qdump__NimGenericSequence__(d, value, regex=r'^TY[\d]+$'): 211 code = value.type.stripTypedefs().code 212 if code == TypeCode.Struct: 213 size, reserved = d.split('pp', value) 214 data = value.address() + 2 * d.ptrSize() 215 typeobj = value['data'].type.dereference() 216 d.putItemCount(size) 217 d.putArrayData(data, size, typeobj) 218 d.putBetterType('%s (%s[%s])' % (value.type.name, typeobj.name, size)) 219 else: 220 d.putEmptyValue() 221 d.putPlainChildren(value) 222 223 224def qdump__TNimNode(d, value): 225 name = value['name'].pointer() 226 d.putSimpleCharArray(name) if name != 0 else d.putEmptyValue() 227 if d.isExpanded(): 228 with Children(d): 229 sons = value['sons'].pointer() 230 size = value['len'].integer() 231 for i in range(size): 232 val = d.createValue(d.extractPointer(sons + i * d.ptrSize()), value.type) 233 with SubItem(d, '[%d]' % i): 234 d.putItem(val) 235 with SubItem(d, '[raw]'): 236 d.putPlainChildren(value) 237 238 239####################################################################### 240# 241# D 242# 243####################################################################### 244 245def cleanDType(type): 246 return str(type).replace('uns long long', 'string') 247 248 249def qdump_Array(d, value): 250 n = value['length'] 251 p = value['ptr'] 252 t = cleanDType(value.type)[7:] 253 d.putType('%s[%d]' % (t, n)) 254 if t == 'char': 255 d.putValue(encodeCharArray(p, 100), 'local8bit') 256 else: 257 d.putEmptyValue() 258 d.putNumChild(n) 259 innerType = p.type 260 if d.isExpanded(): 261 with Children(d, n, childType=innerType): 262 for i in range(0, n): 263 d.putSubItem(i, p.dereference()) 264 p = p + 1 265 266 267def qdump_AArray(d, value): 268 #n = value['length'] 269 # This ends up as _AArray_<key>_<value> with a single .ptr 270 # member of type void *. Not much that can be done here. 271 p = value['ptr'] 272 t = cleanDType(value.type)[8:] 273 d.putType('%s]' % t.replace('_', '[')) 274 d.putEmptyValue() 275 if d.isExpanded(): 276 with Children(d, 1): 277 d.putSubItem('ptr', p) 278 279 280####################################################################### 281# 282# MPI 283# 284####################################################################### 285 286if False: 287 288 def qdump__tree_entry(d, value): 289 d.putValue('len: %s, offset: %s, type: %s' % 290 (value['blocklength'], value['offset'], value['type'])) 291 292 def qdump__tree(d, value): 293 count = value['count'] 294 entries = value['entries'] 295 base = value['base'].pointer() 296 d.putItemCount(count) 297 if d.isExpanded(): 298 with Children(d): 299 with SubItem(d, 'tree'): 300 d.putEmptyValue() 301 d.putNoType() 302 if d.isExpanded(): 303 with Children(d): 304 for i in range(count): 305 d.putSubItem(Item(entries[i], iname)) 306 with SubItem(d, 'data'): 307 d.putEmptyValue() 308 d.putNoType() 309 if d.isExpanded(): 310 with Children(d): 311 for i in range(count): 312 with SubItem(d, i): 313 entry = entries[i] 314 mpitype = str(entry['type']) 315 d.putType(mpitype) 316 length = int(entry['blocklength']) 317 offset = int(entry['offset']) 318 d.putValue('%s items at %s' % (length, offset)) 319 if mpitype == 'MPI_INT': 320 innerType = 'int' 321 elif mpitype == 'MPI_CHAR': 322 innerType = 'char' 323 elif mpitype == 'MPI_DOUBLE': 324 innerType = 'double' 325 else: 326 length = 0 327 d.putNumChild(length) 328 if d.isExpanded(): 329 with Children(d): 330 t = d.lookupType(innerType).pointer() 331 p = (base + offset).cast(t) 332 for j in range(length): 333 d.putSubItem(j, p.dereference()) 334 335 336####################################################################### 337# 338# KDSoap 339# 340####################################################################### 341 342def qdump__KDSoapValue1(d, value): 343 inner = value['d']['d'].dereference() 344 d.putStringValue(inner['m_name']) 345 d.putPlainChildren(inner) 346 347 348def qdump__KDSoapValue(d, value): 349 p = (value.cast(d.lookupType('char*')) + 4).dereference().cast(d.lookupType('QString')) 350 d.putStringValue(p) 351 d.putPlainChildren(value['d']['d'].dereference()) 352 353 354####################################################################### 355# 356# Webkit 357# 358####################################################################### 359 360def qdump__WTF__String(d, value): 361 # WTF::String -> WTF::RefPtr<WTF::StringImpl> -> WTF::StringImpl* 362 data = value['m_impl']['m_ptr'] 363 d.checkPointer(data) 364 365 stringLength = int(data['m_length']) 366 d.check(0 <= stringLength and stringLength <= 100000000) 367 368 # WTF::StringImpl* -> WTF::StringImpl -> sizeof(WTF::StringImpl) 369 offsetToData = data.type.target().size() 370 bufferPtr = data.pointer() + offsetToData 371 372 is8Bit = data['m_is8Bit'] 373 charSize = 1 374 if not is8Bit: 375 charSize = 2 376 377 d.putCharArrayHelper(bufferPtr, stringLength, charSize) 378 379 380####################################################################### 381# 382# Python 383# 384####################################################################### 385 386def get_python_interpreter_major_version(d): 387 key = 'python_interpreter_major_version' 388 if key in d.generalCache: 389 return d.generalCache[key] 390 391 e = "(char*)Py_GetVersion()" 392 result = d.nativeParseAndEvaluate(e) 393 result_str = str(result) 394 matches = re.search(r'(\d+?)\.(\d+?)\.(\d+?)', result_str) 395 if matches: 396 result_str = matches.group(1) 397 d.generalCache[key] = result_str 398 return result_str 399 400 401def is_python_3(d): 402 return get_python_interpreter_major_version(d) == '3' 403 404 405def repr_cache_decorator(namespace): 406 def real_decorator(func_to_decorate): 407 def wrapper(d, address): 408 if namespace in d.perStepCache and address in d.perStepCache[namespace]: 409 return d.perStepCache[namespace][address] 410 411 if namespace not in d.perStepCache: 412 d.perStepCache[namespace] = {} 413 414 if address == 0: 415 result_str = d.perStepCache[namespace][address] = "<nullptr>" 416 return result_str 417 418 result = func_to_decorate(d, address) 419 d.perStepCache[namespace][address] = result 420 return result 421 return wrapper 422 return real_decorator 423 424 425@repr_cache_decorator('py_object') 426def get_py_object_repr_helper(d, address): 427 # The code below is a long way to evaluate: 428 # ((PyBytesObject *)PyUnicode_AsEncodedString(PyObject_Repr( 429 # (PyObject*){}), \"utf-8\", \"backslashreplace\"))->ob_sval" 430 # But with proper object cleanup. 431 432 e_decref = "Py_DecRef((PyObject *){})" 433 434 e = "PyObject_Repr((PyObject*){})" 435 repr_object_value = d.parseAndEvaluate(e.format(address)) 436 repr_object_address = d.fromPointerData(repr_object_value.ldata)[0] 437 438 if is_python_3(d): 439 # Try to get a UTF-8 encoded string from the repr object. 440 e = "PyUnicode_AsEncodedString((PyObject*){}, \"utf-8\", \"backslashreplace\")" 441 string_object_value = d.parseAndEvaluate(e.format(repr_object_address)) 442 string_object_address = d.fromPointerData(string_object_value.ldata)[0] 443 444 e = "(char*)(((PyBytesObject *){})->ob_sval)" 445 result = d.nativeParseAndEvaluate(e.format(string_object_address)) 446 447 # It's important to stringify the result before any other evaluations happen. 448 result_str = str(result) 449 450 # Clean up. 451 d.nativeParseAndEvaluate(e_decref.format(string_object_address)) 452 453 else: 454 # Retrieve non-unicode string. 455 e = "(char*)(PyString_AsString((PyObject*){}))" 456 result = d.nativeParseAndEvaluate(e.format(repr_object_address)) 457 458 # It's important to stringify the result before any other evaluations happen. 459 result_str = str(result) 460 461 # Do some string stripping. 462 # FIXME when using cdb engine. 463 matches = re.search(r'.+?"(.+)"$', result_str) 464 if matches: 465 result_str = matches.group(1) 466 467 # Clean up. 468 d.nativeParseAndEvaluate(e_decref.format(repr_object_address)) 469 470 return result_str 471 472 473@repr_cache_decorator('py_object_type') 474def get_py_object_type(d, object_address): 475 e = "((PyObject *){})->ob_type" 476 type_value = d.parseAndEvaluate(e.format(object_address)) 477 type_address = d.fromPointerData(type_value.ldata)[0] 478 type_repr = get_py_object_repr_helper(d, type_address) 479 return type_repr 480 481 482@repr_cache_decorator('py_object_meta_type') 483def get_py_object_meta_type(d, object_address): 484 # The python3 object layout has a few more indirections. 485 if is_python_3(d): 486 e = "((PyObject *){})->ob_type->ob_base->ob_base->ob_type" 487 else: 488 e = "((PyObject *){})->ob_type->ob_type" 489 type_value = d.parseAndEvaluate(e.format(object_address)) 490 type_address = d.fromPointerData(type_value.ldata)[0] 491 type_repr = get_py_object_repr_helper(d, type_address) 492 return type_repr 493 494 495@repr_cache_decorator('py_object_base_class') 496def get_py_object_base_class(d, object_address): 497 e = "((PyObject *){})->ob_type->tp_base" 498 base_value = d.parseAndEvaluate(e.format(object_address)) 499 base_address = d.fromPointerData(base_value.ldata)[0] 500 base_repr = get_py_object_repr_helper(d, base_address) 501 return base_repr 502 503 504def get_py_object_repr(d, value): 505 address = value.address() 506 repr_available = False 507 try: 508 result = get_py_object_repr_helper(d, address) 509 d.putValue(d.hexencode(result), encoding='utf8') 510 repr_available = True 511 except: 512 d.putEmptyValue() 513 514 def sub_item(name, functor, address): 515 with SubItem(d, '[{}]'.format(name)): 516 sub_value = functor(d, address) 517 d.putValue(d.hexencode(sub_value), encoding='utf8') 518 519 d.putExpandable() 520 if d.isExpanded(): 521 with Children(d): 522 if repr_available: 523 sub_item('class', get_py_object_type, address) 524 sub_item('super class', get_py_object_base_class, address) 525 sub_item('meta type', get_py_object_meta_type, address) 526 d.putFields(value) 527 528 529def qdump__PyTypeObject(d, value): 530 get_py_object_repr(d, value) 531 532 533def qdump___typeobject(d, value): 534 get_py_object_repr(d, value) 535 536 537def qdump__PyObject(d, value): 538 get_py_object_repr(d, value) 539 540 541def qdump__PyVarObject(d, value): 542 get_py_object_repr(d, value) 543 544 545####################################################################### 546# 547# Internal test 548# 549####################################################################### 550 551def qdump__QtcDumperTest_FieldAccessByIndex(d, value): 552 d.putValue(value["d"][2].integer()) 553 554 555def qdump__QtcDumperTest_PointerArray(d, value): 556 foos = value["foos"] 557 d.putItemCount(10) 558 if d.isExpanded(): 559 with Children(d, 10): 560 for i in d.childRange(): 561 d.putSubItem(i, foos[i]) 562 563 564def qdump__QtcDumperTest_BufArray(d, value): 565 maxItems = 1000 566 buffer = value['buffer'] 567 count = int(value['count']) 568 objsize = int(value['objSize']) 569 valueType = value.type.templateArgument(0) 570 d.putItemCount(count, maxItems) 571 d.putNumChild(count) 572 if d.isExpanded(): 573 with Children(d, count, maxNumChild=maxItems, childType=valueType): 574 for i in d.childRange(): 575 d.putSubItem(i, (buffer + (i * objsize)).dereference().cast(valueType)) 576 577 578def qdump__QtcDumperTest_List__NodeX(d, value): 579 typename = value.type.unqualified().name 580 pos0 = typename.find('<') 581 pos1 = typename.find('>') 582 tName = typename[pos0 + 1:pos1] 583 d.putBetterType('QtcDumperTest_List<' + tName + '>::Node') 584 d.putExpandable() 585 if d.isExpanded(): 586 obj_type = d.lookupType(tName) 587 with Children(d): 588 d.putSubItem("this", value.cast(obj_type)) 589 d.putFields(value) 590 #d.putPlainChildren(value) 591 592 593def qdump__QtcDumperTest_List(d, value): 594 innerType = value.type[0] 595 d.putExpandable() 596 p = value['root'] 597 if d.isExpanded(): 598 with Children(d): 599 d.putSubItem("[p]", p) 600 d.putSubItem("[root]", value["root"].cast(innerType)) 601 d.putFields(value) 602 #d.putPlainChildren(value) 603 604 605def qdump__QtcDumperTest_String(d, value): 606 with Children(d): 607 first = d.hexdecode(d.putSubItem('first', value['first']).value) 608 second = d.hexdecode(d.putSubItem('second', value['second']).value) 609 third = d.hexdecode(d.putSubItem('third', value['third']).value)[:-1] 610 d.putValue(first + ', ' + second + ', ' + third) 611