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 26import inspect 27import os 28import platform 29import re 30import sys 31import threading 32import time 33import lldb 34import utils 35from utils import DebuggerStartMode, BreakpointType, TypeCode, LogChannel 36 37from contextlib import contextmanager 38 39sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) 40 41# Simplify development of this module by reloading deps 42if 'dumper' in sys.modules: 43 if sys.version_info[0] >= 3: 44 if sys.version_info[1] > 3: 45 from importlib import reload 46 else: 47 def reload(m): print('Unsupported Python version - not reloading %s' % str(m)) 48 reload(sys.modules['dumper']) 49 50from dumper import DumperBase, SubItem, Children, TopLevelItem 51 52####################################################################### 53# 54# Helpers 55# 56####################################################################### 57 58qqWatchpointOffset = 10000 59_c_str_trans = None 60 61if sys.version_info[0] >= 3: 62 _c_str_trans = str.maketrans({"\n": "\\n", '"':'\\"', "\\":"\\\\"}) 63 64def toCString(s): 65 if _c_str_trans is not None: 66 return str(s).translate(_c_str_trans) 67 else: 68 return str(s).replace('\\', '\\\\').replace('\n', '\\n').replace('"', '\\"') 69 70def fileNameAsString(file): 71 return toCString(file) if file.IsValid() else '' 72 73 74def check(exp): 75 if not exp: 76 raise RuntimeError('Check failed') 77 78 79class Dumper(DumperBase): 80 def __init__(self, debugger=None): 81 DumperBase.__init__(self) 82 lldb.theDumper = self 83 84 self.isLldb = True 85 self.typeCache = {} 86 87 self.outputLock = threading.Lock() 88 89 if debugger: 90 # Re-use existing debugger 91 self.debugger = debugger 92 else: 93 self.debugger = lldb.SBDebugger.Create() 94 #self.debugger.SetLoggingCallback(loggingCallback) 95 #def loggingCallback(args): 96 # s = args.strip() 97 # s = s.replace('"', "'") 98 # sys.stdout.write('log="%s"@\n' % s) 99 #Same as: self.debugger.HandleCommand('log enable lldb dyld step') 100 #self.debugger.EnableLog('lldb', ['dyld', 'step', 'process', 'state', 101 # 'thread', 'events', 102 # 'communication', 'unwind', 'commands']) 103 #self.debugger.EnableLog('lldb', ['all']) 104 self.debugger.Initialize() 105 self.debugger.SetAsync(True) 106 self.debugger.HandleCommand('settings set auto-confirm on') 107 108 # FIXME: warn('DISABLING DEFAULT FORMATTERS') 109 # It doesn't work at all with 179.5 and we have some bad 110 # interaction in 300 111 # if not hasattr(lldb.SBType, 'GetCanonicalType'): # 'Test' for 179.5 112 #self.debugger.HandleCommand('type category delete gnu-libstdc++') 113 #self.debugger.HandleCommand('type category delete libcxx') 114 #self.debugger.HandleCommand('type category delete default') 115 self.debugger.DeleteCategory('gnu-libstdc++') 116 self.debugger.DeleteCategory('libcxx') 117 self.debugger.DeleteCategory('default') 118 self.debugger.DeleteCategory('cplusplus') 119 #for i in range(self.debugger.GetNumCategories()): 120 # self.debugger.GetCategoryAtIndex(i).SetEnabled(False) 121 122 self.process = None 123 self.target = None 124 self.fakeAddress_ = None 125 self.fakeLAddress_ = None 126 self.eventState = lldb.eStateInvalid 127 128 self.executable_ = None 129 self.symbolFile_ = None 130 self.startMode_ = None 131 self.processArgs_ = None 132 self.attachPid_ = None 133 self.dyldImageSuffix = None 134 self.dyldLibraryPath = None 135 self.dyldFrameworkPath = None 136 137 self.isShuttingDown_ = False 138 self.isInterrupting_ = False 139 self.interpreterBreakpointResolvers = [] 140 141 DumperBase.warn = Dumper.warn_impl 142 self.report('lldbversion=\"%s\"' % lldb.SBDebugger.GetVersionString()) 143 144 @staticmethod 145 def warn_impl(message): 146 if message[-1:] == '\n': 147 message += '\n' 148 print('@\nbridgemessage={msg="%s",channel="%s"}\n@' 149 % (message.replace('"', '$'), LogChannel.AppError)) 150 151 def fromNativeFrameValue(self, nativeValue): 152 return self.fromNativeValue(nativeValue) 153 154 def fromNativeValue(self, nativeValue): 155 self.check(isinstance(nativeValue, lldb.SBValue)) 156 nativeType = nativeValue.GetType() 157 typeName = nativeType.GetName() 158 code = nativeType.GetTypeClass() 159 160 # Display the result of GetSummary() for Core Foundation string 161 # and string-like types. 162 summary = None 163 if self.useFancy: 164 if (typeName.startswith('CF') 165 or typeName.startswith('__CF') 166 or typeName.startswith('NS') 167 or typeName.startswith('__NSCF')): 168 if code == lldb.eTypeClassPointer: 169 summary = nativeValue.Dereference().GetSummary() 170 elif code == lldb.eTypeClassReference: 171 summary = nativeValue.Dereference().GetSummary() 172 else: 173 summary = nativeValue.GetSummary() 174 175 nativeValue.SetPreferSyntheticValue(False) 176 177 if code == lldb.eTypeClassReference: 178 nativeTargetType = nativeType.GetDereferencedType() 179 if not nativeTargetType.IsPointerType(): 180 nativeTargetType = nativeTargetType.GetUnqualifiedType() 181 targetType = self.fromNativeType(nativeTargetType) 182 val = self.createReferenceValue(nativeValue.GetValueAsUnsigned(), targetType) 183 val.laddress = nativeValue.AddressOf().GetValueAsUnsigned() 184 #DumperBase.warn('CREATED REF: %s' % val) 185 elif code == lldb.eTypeClassPointer: 186 nativeTargetType = nativeType.GetPointeeType() 187 if not nativeTargetType.IsPointerType(): 188 nativeTargetType = nativeTargetType.GetUnqualifiedType() 189 targetType = self.fromNativeType(nativeTargetType) 190 val = self.createPointerValue(nativeValue.GetValueAsUnsigned(), targetType) 191 #DumperBase.warn('CREATED PTR 1: %s' % val) 192 val.laddress = nativeValue.AddressOf().GetValueAsUnsigned() 193 #DumperBase.warn('CREATED PTR 2: %s' % val) 194 elif code == lldb.eTypeClassTypedef: 195 nativeTargetType = nativeType.GetUnqualifiedType() 196 if hasattr(nativeTargetType, 'GetCanonicalType'): 197 nativeTargetType = nativeTargetType.GetCanonicalType() 198 val = self.fromNativeValue(nativeValue.Cast(nativeTargetType)) 199 val._type = self.fromNativeType(nativeType) 200 #DumperBase.warn('CREATED TYPEDEF: %s' % val) 201 else: 202 val = self.Value(self) 203 address = nativeValue.GetLoadAddress() 204 if address is not None: 205 val.laddress = address 206 if True: 207 data = nativeValue.GetData() 208 error = lldb.SBError() 209 size = nativeValue.GetType().GetByteSize() 210 if size > 1: 211 # 0 happens regularly e.g. for cross-shared-object types. 212 # 1 happens on Linux e.g. for QObject uses outside of QtCore. 213 try: 214 val.ldata = data.ReadRawData(error, 0, size) 215 except: 216 pass 217 218 val._type = self.fromNativeType(nativeType) 219 220 if code == lldb.eTypeClassEnumeration: 221 intval = nativeValue.GetValueAsSigned() 222 display = str(nativeValue).split(' = ') 223 if len(display) == 2: 224 verbose = display[1] 225 if '|' in verbose and not verbose.startswith('('): 226 verbose = '(' + verbose + ')' 227 else: 228 verbose = intval 229 val.ldisplay = '%s (%d)' % (verbose, intval) 230 elif code in (lldb.eTypeClassComplexInteger, lldb.eTypeClassComplexFloat): 231 val.ldisplay = str(nativeValue.GetValue()) 232 #elif code == lldb.eTypeClassArray: 233 # if hasattr(nativeType, 'GetArrayElementType'): # New in 3.8(?) / 350.x 234 # val.type.ltarget = self.fromNativeType(nativeType.GetArrayElementType()) 235 # else: 236 # fields = nativeType.get_fields_array() 237 # if len(fields): 238 # val.type.ltarget = self.fromNativeType(fields[0]) 239 #elif code == lldb.eTypeClassVector: 240 # val.type.ltarget = self.fromNativeType(nativeType.GetVectorElementType()) 241 242 val.summary = summary 243 val.lIsInScope = nativeValue.IsInScope() 244 val.name = nativeValue.GetName() 245 return val 246 247 def nativeStructAlignment(self, nativeType): 248 def handleItem(nativeFieldType, align): 249 a = self.fromNativeType(nativeFieldType).alignment() 250 return a if a > align else align 251 align = 1 252 for i in range(nativeType.GetNumberOfDirectBaseClasses()): 253 base = nativeType.GetDirectBaseClassAtIndex(i) 254 align = handleItem(base.GetType(), align) 255 for i in range(nativeType.GetNumberOfFields()): 256 child = nativeType.GetFieldAtIndex(i) 257 align = handleItem(child.GetType(), align) 258 return align 259 260 def listMembers(self, value, nativeType): 261 #DumperBase.warn("ADDR: 0x%x" % self.fakeAddress_) 262 if value.laddress: 263 fakeAddress = lldb.SBAddress(value.laddress, self.target) 264 fakeLAddress = value.laddress 265 else: 266 fakeAddress = self.fakeAddress_ 267 fakeLAddress = self.fakeLAddress_ 268 269 fakeValue = self.target.CreateValueFromAddress('x', fakeAddress, nativeType) 270 fakeValue.SetPreferSyntheticValue(False) 271 272 baseNames = {} 273 for i in range(nativeType.GetNumberOfDirectBaseClasses()): 274 base = nativeType.GetDirectBaseClassAtIndex(i) 275 baseNames[base.GetName()] = i 276 277 fieldBits = {} 278 for f in nativeType.get_fields_array(): 279 bitsize = f.GetBitfieldSizeInBits() 280 if bitsize == 0: 281 bitsize = f.GetType().GetByteSize() * 8 282 bitpos = f.GetOffsetInBits() 283 fieldBits[f.name] = (bitsize, bitpos, f.IsBitfield()) 284 285 # Normal members and non-empty base classes. 286 anonNumber = 0 287 for i in range(fakeValue.GetNumChildren()): 288 nativeField = fakeValue.GetChildAtIndex(i) 289 nativeField.SetPreferSyntheticValue(False) 290 291 fieldName = nativeField.GetName() 292 nativeFieldType = nativeField.GetType() 293 294 if fieldName in fieldBits: 295 (fieldBitsize, fieldBitpos, isBitfield) = fieldBits[fieldName] 296 else: 297 fieldBitsize = nativeFieldType.GetByteSize() * 8 298 fieldBitpos = None 299 isBitfield = False 300 301 if isBitfield: # Bit fields 302 fieldType = self.createBitfieldType( 303 self.createType(self.typeName(nativeFieldType)), fieldBitsize) 304 yield self.Field(self, name=fieldName, type=fieldType, 305 bitsize=fieldBitsize, bitpos=fieldBitpos) 306 307 elif fieldName is None: # Anon members 308 anonNumber += 1 309 fieldName = '#%s' % anonNumber 310 fakeMember = fakeValue.GetChildAtIndex(i) 311 fakeMemberAddress = fakeMember.GetLoadAddress() 312 offset = fakeMemberAddress - fakeLAddress 313 yield self.Field(self, name=fieldName, type=self.fromNativeType(nativeFieldType), 314 bitsize=fieldBitsize, bitpos=8 * offset) 315 316 elif fieldName in baseNames: # Simple bases 317 member = self.fromNativeValue(fakeValue.GetChildAtIndex(i)) 318 member.isBaseClass = True 319 yield member 320 321 else: # Normal named members 322 member = self.fromNativeValue(fakeValue.GetChildAtIndex(i)) 323 member.name = nativeField.GetName() 324 yield member 325 326 # Empty bases are not covered above. 327 for i in range(nativeType.GetNumberOfDirectBaseClasses()): 328 fieldObj = nativeType.GetDirectBaseClassAtIndex(i) 329 fieldType = fieldObj.GetType() 330 if fieldType.GetNumberOfFields() == 0: 331 if fieldType.GetNumberOfDirectBaseClasses() == 0: 332 member = self.Value(self) 333 fieldName = fieldObj.GetName() 334 member._type = self.fromNativeType(fieldType) 335 member.name = fieldName 336 member.fields = [] 337 if False: 338 # This would be correct if we came here only for 339 # truly empty base classes. Alas, we don't, see below. 340 member.ldata = bytes() 341 member.lbitsize = fieldType.GetByteSize() * 8 342 else: 343 # This is a hack. LLDB 3.8 reports declared but not defined 344 # types as having no fields and(!) size == 1. At least 345 # for the common case of a single base class we can 346 # fake the contents by using the whole derived object's 347 # data as base class data. 348 data = fakeValue.GetData() 349 size = nativeType.GetByteSize() 350 member.lbitsize = size * 8 351 error = lldb.SBError() 352 member.laddress = value.laddress 353 member.ldata = data.ReadRawData(error, 0, size) 354 member.isBaseClass = True 355 member.ltype = self.fromNativeType(fieldType) 356 member.name = fieldName 357 yield member 358 359 def ptrSize(self): 360 result = self.target.GetAddressByteSize() 361 self.ptrSize = lambda: result 362 return result 363 364 def fromNativeType(self, nativeType): 365 self.check(isinstance(nativeType, lldb.SBType)) 366 code = nativeType.GetTypeClass() 367 368 # eTypeClassInvalid = (0u), 369 # eTypeClassArray = (1u << 0), 370 # eTypeClassBlockPointer = (1u << 1), 371 # eTypeClassBuiltin = (1u << 2), 372 # eTypeClassClass = (1u << 3), 373 # eTypeClassComplexFloat = (1u << 4), 374 # eTypeClassComplexInteger = (1u << 5), 375 # eTypeClassEnumeration = (1u << 6), 376 # eTypeClassFunction = (1u << 7), 377 # eTypeClassMemberPointer = (1u << 8), 378 # eTypeClassObjCObject = (1u << 9), 379 # eTypeClassObjCInterface = (1u << 10), 380 # eTypeClassObjCObjectPointer = (1u << 11), 381 # eTypeClassPointer = (1u << 12), 382 # eTypeClassReference = (1u << 13), 383 # eTypeClassStruct = (1u << 14), 384 # eTypeClassTypedef = (1u << 15), 385 # eTypeClassUnion = (1u << 16), 386 # eTypeClassVector = (1u << 17), 387 # // Define the last type class as the MSBit of a 32 bit value 388 # eTypeClassOther = (1u << 31), 389 # // Define a mask that can be used for any type when finding types 390 # eTypeClassAny = (0xffffffffu) 391 392 #DumperBase.warn('CURRENT: %s' % self.typeData.keys()) 393 #DumperBase.warn('FROM NATIVE TYPE: %s' % nativeType.GetName()) 394 if code == lldb.eTypeClassInvalid: 395 return None 396 397 if code == lldb.eTypeClassBuiltin: 398 nativeType = nativeType.GetUnqualifiedType() 399 400 if code == lldb.eTypeClassPointer: 401 #DumperBase.warn('PTR') 402 nativeTargetType = nativeType.GetPointeeType() 403 if not nativeTargetType.IsPointerType(): 404 nativeTargetType = nativeTargetType.GetUnqualifiedType() 405 #DumperBase.warn('PTR: %s' % nativeTargetType.name) 406 return self.createPointerType(self.fromNativeType(nativeTargetType)) 407 408 if code == lldb.eTypeClassReference: 409 #DumperBase.warn('REF') 410 nativeTargetType = nativeType.GetDereferencedType() 411 if not nativeTargetType.IsPointerType(): 412 nativeTargetType = nativeTargetType.GetUnqualifiedType() 413 #DumperBase.warn('REF: %s' % nativeTargetType.name) 414 return self.createReferenceType(self.fromNativeType(nativeTargetType)) 415 416 if code == lldb.eTypeClassTypedef: 417 #DumperBase.warn('TYPEDEF') 418 nativeTargetType = nativeType.GetUnqualifiedType() 419 if hasattr(nativeTargetType, 'GetCanonicalType'): 420 nativeTargetType = nativeTargetType.GetCanonicalType() 421 targetType = self.fromNativeType(nativeTargetType) 422 return self.createTypedefedType(targetType, nativeType.GetName(), 423 self.nativeTypeId(nativeType)) 424 425 nativeType = nativeType.GetUnqualifiedType() 426 typeName = self.typeName(nativeType) 427 428 if code in (lldb.eTypeClassArray, lldb.eTypeClassVector): 429 #DumperBase.warn('ARRAY: %s' % nativeType.GetName()) 430 if hasattr(nativeType, 'GetArrayElementType'): # New in 3.8(?) / 350.x 431 nativeTargetType = nativeType.GetArrayElementType() 432 if not nativeTargetType.IsValid(): 433 if hasattr(nativeType, 'GetVectorElementType'): # New in 3.8(?) / 350.x 434 #DumperBase.warn('BAD: %s ' % nativeTargetType.get_fields_array()) 435 nativeTargetType = nativeType.GetVectorElementType() 436 count = nativeType.GetByteSize() // nativeTargetType.GetByteSize() 437 targetTypeName = nativeTargetType.GetName() 438 if targetTypeName.startswith('(anon'): 439 typeName = nativeType.GetName() 440 pos1 = typeName.rfind('[') 441 targetTypeName = typeName[0:pos1].strip() 442 #DumperBase.warn("TARGET TYPENAME: %s" % targetTypeName) 443 targetType = self.fromNativeType(nativeTargetType) 444 tdata = targetType.typeData().copy() 445 tdata.name = targetTypeName 446 targetType.typeData = lambda: tdata 447 return self.createArrayType(targetType, count) 448 if hasattr(nativeType, 'GetVectorElementType'): # New in 3.8(?) / 350.x 449 nativeTargetType = nativeType.GetVectorElementType() 450 count = nativeType.GetByteSize() // nativeTargetType.GetByteSize() 451 targetType = self.fromNativeType(nativeTargetType) 452 return self.createArrayType(targetType, count) 453 return self.createType(nativeType.GetName()) 454 455 typeId = self.nativeTypeId(nativeType) 456 res = self.typeData.get(typeId, None) 457 if res is None: 458 # # This strips typedefs for pointers. We don't want that. 459 # typeobj.nativeType = nativeType.GetUnqualifiedType() 460 tdata = self.TypeData(self) 461 tdata.typeId = typeId 462 tdata.name = typeName 463 tdata.lbitsize = nativeType.GetByteSize() * 8 464 if code == lldb.eTypeClassBuiltin: 465 if utils.isFloatingPointTypeName(typeName): 466 tdata.code = TypeCode.Float 467 elif utils.isIntegralTypeName(typeName): 468 tdata.code = TypeCode.Integral 469 elif typeName in ('__int128', 'unsigned __int128'): 470 tdata.code = TypeCode.Integral 471 elif typeName == 'void': 472 tdata.code = TypeCode.Void 473 elif typeName == 'wchar_t': 474 tdata.code = TypeCode.Integral 475 else: 476 self.warn('UNKNOWN TYPE KEY: %s: %s' % (typeName, code)) 477 elif code == lldb.eTypeClassEnumeration: 478 tdata.code = TypeCode.Enum 479 tdata.enumDisplay = lambda intval, addr, form: \ 480 self.nativeTypeEnumDisplay(nativeType, intval, form) 481 elif code in (lldb.eTypeClassComplexInteger, lldb.eTypeClassComplexFloat): 482 tdata.code = TypeCode.Complex 483 elif code in (lldb.eTypeClassClass, lldb.eTypeClassStruct, lldb.eTypeClassUnion): 484 tdata.code = TypeCode.Struct 485 tdata.lalignment = lambda: \ 486 self.nativeStructAlignment(nativeType) 487 tdata.lfields = lambda value: \ 488 self.listMembers(value, nativeType) 489 tdata.templateArguments = self.listTemplateParametersHelper(nativeType) 490 elif code == lldb.eTypeClassFunction: 491 tdata.code = TypeCode.Function 492 elif code == lldb.eTypeClassMemberPointer: 493 tdata.code = TypeCode.MemberPointer 494 495 self.registerType(typeId, tdata) # Fix up fields and template args 496 # warn('CREATE TYPE: %s' % typeId) 497 #else: 498 # warn('REUSE TYPE: %s' % typeId) 499 return self.Type(self, typeId) 500 501 def listTemplateParametersHelper(self, nativeType): 502 stringArgs = self.listTemplateParameters(nativeType.GetName()) 503 n = nativeType.GetNumberOfTemplateArguments() 504 if n != len(stringArgs): 505 # Something wrong in the debug info. 506 # Should work in theory, doesn't work in practice. 507 # Items like std::allocator<std::pair<unsigned int const, float> report 0 508 # for nativeType.GetNumberOfTemplateArguments() with LLDB 3.8 509 return stringArgs 510 511 targs = [] 512 for i in range(nativeType.GetNumberOfTemplateArguments()): 513 kind = nativeType.GetTemplateArgumentKind(i) 514 # eTemplateArgumentKindNull = 0, 515 # eTemplateArgumentKindType, 516 # eTemplateArgumentKindDeclaration, 517 # eTemplateArgumentKindIntegral, 518 # eTemplateArgumentKindTemplate, 519 # eTemplateArgumentKindTemplateExpansion, 520 # eTemplateArgumentKindExpression, 521 # eTemplateArgumentKindPack 522 if kind == lldb.eTemplateArgumentKindType: 523 innerType = nativeType.GetTemplateArgumentType( 524 i).GetUnqualifiedType().GetCanonicalType() 525 targs.append(self.fromNativeType(innerType)) 526 #elif kind == lldb.eTemplateArgumentKindIntegral: 527 # innerType = nativeType.GetTemplateArgumentType(i).GetUnqualifiedType().GetCanonicalType() 528 # #DumperBase.warn('INNER TYP: %s' % innerType) 529 # basicType = innerType.GetBasicType() 530 # #DumperBase.warn('IBASIC TYP: %s' % basicType) 531 # inner = self.extractTemplateArgument(nativeType.GetName(), i) 532 # exp = '(%s)%s' % (innerType.GetName(), inner) 533 # #DumperBase.warn('EXP : %s' % exp) 534 # val = self.nativeParseAndEvaluate('(%s)%s' % (innerType.GetName(), inner)) 535 # # Clang writes 'int' and '0xfffffff' into the debug info 536 # # LLDB manages to read a value of 0xfffffff... 537 # #if basicType == lldb.eBasicTypeInt: 538 # value = val.GetValueAsUnsigned() 539 # if value >= 0x8000000: 540 # value -= 0x100000000 541 # #DumperBase.warn('KIND: %s' % kind) 542 # targs.append(value) 543 else: 544 #DumperBase.warn('UNHANDLED TEMPLATE TYPE : %s' % kind) 545 targs.append(stringArgs[i]) # Best we can do. 546 #DumperBase.warn('TARGS: %s %s' % (nativeType.GetName(), [str(x) for x in targs])) 547 return targs 548 549 def typeName(self, nativeType): 550 # Don't use GetDisplayTypeName since LLDB removed the inline namespace __1 551 # https://reviews.llvm.org/D74478 552 return nativeType.GetName() 553 554 def nativeTypeId(self, nativeType): 555 if nativeType and (nativeType.GetTypeClass() == lldb.eTypeClassTypedef): 556 nativeTargetType = nativeType.GetUnqualifiedType() 557 if hasattr(nativeTargetType, 'GetCanonicalType'): 558 nativeTargetType = nativeTargetType.GetCanonicalType() 559 return '%s{%s}' % (nativeType.name, nativeTargetType.name) 560 name = self.typeName(nativeType) 561 if name is None or len(name) == 0: 562 c = '0' 563 elif name == '(anonymous struct)' and nativeType.GetTypeClass() == lldb.eTypeClassStruct: 564 c = 's' 565 elif name == '(anonymous struct)' and nativeType.GetTypeClass() == lldb.eTypeClassUnion: 566 c = 'u' 567 else: 568 return name 569 fields = nativeType.get_fields_array() 570 typeId = c + ''.join(['{%s:%s}' % (f.name, self.nativeTypeId(f.GetType())) for f in fields]) 571 #DumperBase.warn('NATIVE TYPE ID FOR %s IS %s' % (name, typeId)) 572 return typeId 573 574 def nativeTypeEnumDisplay(self, nativeType, intval, form): 575 if hasattr(nativeType, 'get_enum_members_array'): 576 enumerators = [] 577 flags = [] 578 found = False 579 for enumMember in nativeType.get_enum_members_array(): 580 # Even when asking for signed we get unsigned with LLDB 3.8. 581 value = enumMember.GetValueAsSigned() 582 name = nativeType.GetName().split('::') 583 name[-1] = enumMember.GetName() 584 if value == intval: 585 return '::'.join(name) + ' (' + (form % intval) + ')' 586 enumerators.append(('::'.join(name), value)) 587 588 given = intval 589 for (name, value) in enumerators: 590 if value & given != 0: 591 flags.append(name) 592 given = given & ~value 593 found = True 594 595 if not found or given != 0: 596 flags.append('unknown: %d' % given) 597 598 return '(' + ' | '.join(flags) + ') (' + (form % intval) + ')' 599 return form % intval 600 601 def nativeDynamicTypeName(self, address, baseType): 602 return None # FIXME: Seems sufficient, no idea why. 603 addr = self.target.ResolveLoadAddress(address) 604 ctx = self.target.ResolveSymbolContextForAddress(addr, 0) 605 sym = ctx.GetSymbol() 606 return sym.GetName() 607 608 def stateName(self, s): 609 try: 610 # See db.StateType 611 return ( 612 'invalid', 613 'unloaded', # Process is object is valid, but not currently loaded 614 'connected', # Process is connected to remote debug services, 615 # but not launched or attached to anything yet 616 'attaching', # Process is currently trying to attach 617 'launching', # Process is in the process of launching 618 'stopped', # Process or thread is stopped and can be examined. 619 'running', # Process or thread is running and can't be examined. 620 'stepping', # Process or thread is in the process of stepping 621 # and can not be examined. 622 'crashed', # Process or thread has crashed and can be examined. 623 'detached', # Process has been detached and can't be examined. 624 'exited', # Process has exited and can't be examined. 625 'suspended' # Process or thread is in a suspended state as far 626 )[s] 627 except: 628 return 'unknown(%s)' % s 629 630 def stopReason(self, s): 631 try: 632 return ( 633 'invalid', 634 'none', 635 'trace', 636 'breakpoint', 637 'watchpoint', 638 'signal', 639 'exception', 640 'exec', 641 'plancomplete', 642 'threadexiting', 643 'instrumentation', 644 )[s] 645 except: 646 return 'unknown(%s)' % s 647 648 def enumExpression(self, enumType, enumValue): 649 ns = self.qtNamespace() 650 return ns + 'Qt::' + enumType + '(' \ 651 + ns + 'Qt::' + enumType + '::' + enumValue + ')' 652 653 def callHelper(self, rettype, value, func, args): 654 # args is a tuple. 655 arg = ','.join(args) 656 #DumperBase.warn('PRECALL: %s -> %s(%s)' % (value.address(), func, arg)) 657 typename = value.type.name 658 exp = '((%s*)0x%x)->%s(%s)' % (typename, value.address(), func, arg) 659 #DumperBase.warn('CALL: %s' % exp) 660 result = self.currentContextValue.CreateValueFromExpression('', exp) 661 #DumperBase.warn(' -> %s' % result) 662 return self.fromNativeValue(result) 663 664 def pokeValue(self, typeName, *args): 665 thread = self.currentThread() 666 frame = thread.GetFrameAtIndex(0) 667 inner = ','.join(args) 668 value = frame.EvaluateExpression(typeName + '{' + inner + '}') 669 #DumperBase.warn(' TYPE: %s' % value.type) 670 #DumperBase.warn(' ADDR: 0x%x' % value.address) 671 #DumperBase.warn(' VALUE: %s' % value) 672 return value 673 674 def nativeParseAndEvaluate(self, exp): 675 thread = self.currentThread() 676 frame = thread.GetFrameAtIndex(0) 677 val = frame.EvaluateExpression(exp) 678 #options = lldb.SBExpressionOptions() 679 #val = self.target.EvaluateExpression(exp, options) 680 err = val.GetError() 681 if err.Fail(): 682 #DumperBase.warn('FAILING TO EVAL: %s' % exp) 683 return None 684 #DumperBase.warn('NO ERROR.') 685 #DumperBase.warn('EVAL: %s -> %s' % (exp, val.IsValid())) 686 return val 687 688 def parseAndEvaluate(self, exp): 689 val = self.nativeParseAndEvaluate(exp) 690 return None if val is None else self.fromNativeValue(val) 691 692 def isWindowsTarget(self): 693 return False 694 695 def isQnxTarget(self): 696 return False 697 698 def isArmArchitecture(self): 699 return False 700 701 def isMsvcTarget(self): 702 return False 703 704 def prettySymbolByAddress(self, address): 705 try: 706 result = lldb.SBCommandReturnObject() 707 # Cast the address to a function pointer to get the name and location of the function. 708 expression = 'po (void (*)()){}' 709 self.debugger.GetCommandInterpreter().HandleCommand(expression.format(address), result) 710 output = '' 711 if result.Succeeded(): 712 output = result.GetOutput().strip() 713 if output: 714 return output 715 except: 716 pass 717 return '0x%x' % address 718 719 def qtVersionAndNamespace(self): 720 for func in self.target.FindFunctions('qVersion'): 721 name = func.GetSymbol().GetName() 722 if name.endswith('()'): 723 name = name[:-2] 724 if name.count(':') > 2: 725 continue 726 727 qtNamespace = name[:name.find('qVersion')] 728 self.qtNamespace = lambda: qtNamespace 729 730 options = lldb.SBExpressionOptions() 731 res = self.target.EvaluateExpression(name + '()', options) 732 733 if not res.IsValid() or not res.GetType().IsPointerType(): 734 exp = '((const char*())%s)()' % name 735 res = self.target.EvaluateExpression(exp, options) 736 737 if not res.IsValid() or not res.GetType().IsPointerType(): 738 exp = '((const char*())_Z8qVersionv)()' 739 res = self.target.EvaluateExpression(exp, options) 740 741 if not res.IsValid() or not res.GetType().IsPointerType(): 742 continue 743 744 version = str(res) 745 if version.count('.') != 2: 746 continue 747 748 version.replace("'", '"') # Both seem possible 749 version = version[version.find('"') + 1:version.rfind('"')] 750 751 (major, minor, patch) = version.split('.') 752 qtVersion = 0x10000 * int(major) + 0x100 * int(minor) + int(patch) 753 self.qtVersion = lambda: qtVersion 754 755 funcs = self.target.FindFunctions('QObject::customEvent') 756 if len(funcs): 757 symbol = funcs[0].GetSymbol() 758 self.qtCustomEventFunc = symbol.GetStartAddress().GetLoadAddress(self.target) 759 760 funcs = self.target.FindFunctions('QObject::property') 761 if len(funcs): 762 symbol = funcs[0].GetSymbol() 763 self.qtPropertyFunc = symbol.GetStartAddress().GetLoadAddress(self.target) 764 return (qtNamespace, qtVersion) 765 766 return ('', 0x50200) 767 768 def qtNamespace(self): 769 return self.qtVersionAndNamespace()[0] 770 771 def qtVersion(self): 772 self.qtVersionAndNamespace() 773 return self.qtVersionAndNamespace()[1] 774 775 def handleCommand(self, command): 776 result = lldb.SBCommandReturnObject() 777 self.debugger.GetCommandInterpreter().HandleCommand(command, result) 778 success = result.Succeeded() 779 if success: 780 self.report('output="%s"' % toCString(result.GetOutput())) 781 else: 782 self.report('error="%s"' % toCString(result.GetError())) 783 784 def canonicalTypeName(self, name): 785 return re.sub('\\bconst\\b', '', name).replace(' ', '') 786 787 def removeTypePrefix(self, name): 788 return re.sub('^(struct|class|union|enum|typedef) ', '', name) 789 790 def lookupNativeType(self, name): 791 #DumperBase.warn('LOOKUP TYPE NAME: %s' % name) 792 typeobj = self.typeCache.get(name) 793 if typeobj is not None: 794 #DumperBase.warn('CACHED: %s' % name) 795 return typeobj 796 typeobj = self.target.FindFirstType(name) 797 if typeobj.IsValid(): 798 #DumperBase.warn('VALID FIRST : %s' % typeobj) 799 self.typeCache[name] = typeobj 800 return typeobj 801 802 # FindFirstType has a bug (in lldb) that if there are two types with the same base name 803 # but different scope name (e.g. inside different classes) and the searched for type name 804 # would be returned as the second result in a call to FindTypes, FindFirstType would return 805 # an empty result. 806 # Therefore an additional call to FindTypes is done as a fallback. 807 # Note that specifying a prefix like enum or typedef or class will make the call fail to 808 # find the type, thus the prefix is stripped. 809 nonPrefixedName = self.canonicalTypeName(self.removeTypePrefix(name)) 810 if re.match(r'^.+\(.*\)', nonPrefixedName) is not None: 811 return lldb.SBType() 812 813 typeobjlist = self.target.FindTypes(nonPrefixedName) 814 if typeobjlist.IsValid(): 815 for typeobj in typeobjlist: 816 n = self.canonicalTypeName(self.removeTypePrefix(typeobj.GetName())) 817 if n == nonPrefixedName: 818 #DumperBase.warn('FOUND TYPE USING FindTypes : %s' % typeobj) 819 self.typeCache[name] = typeobj 820 return typeobj 821 if name.endswith('*'): 822 #DumperBase.warn('RECURSE PTR') 823 typeobj = self.lookupNativeType(name[:-1].strip()) 824 if typeobj is not None: 825 #DumperBase.warn('RECURSE RESULT X: %s' % typeobj) 826 self.fromNativeType(typeobj.GetPointerType()) 827 #DumperBase.warn('RECURSE RESULT: %s' % typeobj.GetPointerType()) 828 return typeobj.GetPointerType() 829 830 #typeobj = self.target.FindFirstType(name[:-1].strip()) 831 #if typeobj.IsValid(): 832 # self.typeCache[name] = typeobj.GetPointerType() 833 # return typeobj.GetPointerType() 834 835 if name.endswith(' const'): 836 #DumperBase.warn('LOOKUP END CONST') 837 typeobj = self.lookupNativeType(name[:-6]) 838 if typeobj is not None: 839 return typeobj 840 841 if name.startswith('const '): 842 #DumperBase.warn('LOOKUP START CONST') 843 typeobj = self.lookupNativeType(name[6:]) 844 if typeobj is not None: 845 return typeobj 846 847 return lldb.SBType() 848 849 def setupInferior(self, args): 850 """ Set up SBTarget instance """ 851 852 error = lldb.SBError() 853 854 self.executable_ = args['executable'] 855 self.startMode_ = args.get('startmode', 1) 856 self.breakOnMain_ = args.get('breakonmain', 0) 857 self.useTerminal_ = args.get('useterminal', 0) 858 pargs = self.hexdecode(args.get('processargs', '')) 859 self.processArgs_ = pargs.split('\0') if len(pargs) else [] 860 self.environment_ = args.get('environment', []) 861 self.environment_ = list(map(lambda x: self.hexdecode(x), self.environment_)) 862 self.attachPid_ = args.get('attachpid', 0) 863 self.sysRoot_ = args.get('sysroot', '') 864 self.remoteChannel_ = args.get('remotechannel', '') 865 self.platform_ = args.get('platform', '') 866 self.nativeMixed = int(args.get('nativemixed', 0)) 867 self.symbolFile_ = args['symbolfile']; 868 self.workingDirectory_ = args.get('workingdirectory', '') 869 if self.workingDirectory_ == '': 870 try: 871 self.workingDirectory_ = os.getcwd() 872 except: # Could have been deleted in the mean time. 873 pass 874 875 if self.platform_: 876 self.debugger.SetCurrentPlatform(self.platform_) 877 # sysroot has to be set *after* the platform 878 if self.sysRoot_: 879 self.debugger.SetCurrentPlatformSDKRoot(self.sysRoot_) 880 881 # There seems to be some kind of unexpected behavior, or bug in LLDB 882 # such that target.Attach(attachInfo, error) below does not create 883 # a valid process if this symbolFile here is valid. 884 if self.startMode_ == DebuggerStartMode.AttachExternal: 885 self.symbolFile_ = '' 886 887 self.target = self.debugger.CreateTarget( 888 self.symbolFile_, None, self.platform_, True, error) 889 890 if not error.Success(): 891 self.report(self.describeError(error)) 892 self.reportState('enginerunfailed') 893 return 894 895 broadcaster = self.target.GetBroadcaster() 896 listener = self.debugger.GetListener() 897 broadcaster.AddListener(listener, lldb.SBProcess.eBroadcastBitStateChanged) 898 listener.StartListeningForEvents(broadcaster, lldb.SBProcess.eBroadcastBitStateChanged) 899 broadcaster.AddListener(listener, lldb.SBTarget.eBroadcastBitBreakpointChanged) 900 listener.StartListeningForEvents( 901 broadcaster, lldb.SBTarget.eBroadcastBitBreakpointChanged) 902 903 if self.nativeMixed: 904 self.interpreterEventBreakpoint = \ 905 self.target.BreakpointCreateByName('qt_qmlDebugMessageAvailable') 906 907 state = 1 if self.target.IsValid() else 0 908 self.reportResult('success="%s",msg="%s",exe="%s"' 909 % (state, toCString(error), toCString(self.executable_)), args) 910 911 def runEngine(self, args): 912 """ Set up SBProcess instance """ 913 914 error = lldb.SBError() 915 916 if self.startMode_ == DebuggerStartMode.AttachExternal: 917 attach_info = lldb.SBAttachInfo(self.attachPid_) 918 self.process = self.target.Attach(attach_info, error) 919 if not error.Success(): 920 self.reportState('enginerunfailed') 921 else: 922 self.report('pid="%s"' % self.process.GetProcessID()) 923 self.reportState('enginerunandinferiorstopok') 924 925 elif (self.startMode_ == DebuggerStartMode.AttachToRemoteServer 926 and self.platform_ == 'remote-android'): 927 928 connect_options = lldb.SBPlatformConnectOptions(self.remoteChannel_) 929 res = self.target.GetPlatform().ConnectRemote(connect_options) 930 931 DumperBase.warn("CONNECT: %s %s platform: %s %s" % (res, 932 self.remoteChannel_, 933 self.target.GetPlatform().GetName(), 934 self.target.GetPlatform().IsConnected())) 935 if not res.Success(): 936 self.report(self.describeError(error)) 937 self.reportState('enginerunfailed') 938 return 939 940 attach_info = lldb.SBAttachInfo(self.attachPid_) 941 self.process = self.target.Attach(attach_info, error) 942 if not error.Success(): 943 self.report(self.describeError(error)) 944 self.reportState('enginerunfailed') 945 else: 946 self.report('pid="%s"' % self.process.GetProcessID()) 947 self.reportState('enginerunandinferiorstopok') 948 949 elif (self.startMode_ == DebuggerStartMode.AttachToRemoteServer 950 or self.startMode_ == DebuggerStartMode.AttachToRemoteProcess): 951 if self.platform_ == 'remote-ios': 952 self.process = self.target.ConnectRemote( 953 self.debugger.GetListener(), 954 self.remoteChannel_, None, error) 955 else: 956 f = lldb.SBFileSpec() 957 f.SetFilename(self.executable_) 958 959 launchInfo = lldb.SBLaunchInfo(self.processArgs_) 960 #launchInfo.SetWorkingDirectory(self.workingDirectory_) 961 launchInfo.SetWorkingDirectory('/tmp') 962 if self.platform_ == 'remote-android': 963 launchInfo.SetWorkingDirectory('/data/local/tmp') 964 launchInfo.SetEnvironmentEntries(self.environment_, False) 965 launchInfo.SetExecutableFile(f, True) 966 967 DumperBase.warn("TARGET: %s" % self.target) 968 self.process = self.target.Launch(launchInfo, error) 969 DumperBase.warn("PROCESS: %s" % self.process) 970 971 if not error.Success(): 972 self.report(self.describeError(error)) 973 self.reportState('enginerunfailed') 974 return 975 976 # Even if it stops it seems that LLDB assumes it is running 977 # and later detects that it did stop after all, so it is be 978 # better to mirror that and wait for the spontaneous stop. 979 self.reportState('enginerunandinferiorrunok') 980 981 elif self.startMode_ == DebuggerStartMode.AttachCore: 982 coreFile = args.get('coreFile', '') 983 self.process = self.target.LoadCore(coreFile) 984 if self.process.IsValid(): 985 self.reportState('enginerunokandinferiorunrunnable') 986 else: 987 self.reportState('enginerunfailed') 988 else: 989 launchInfo = lldb.SBLaunchInfo(self.processArgs_) 990 launchInfo.SetWorkingDirectory(self.workingDirectory_) 991 launchInfo.SetEnvironmentEntries(self.environment_, False) 992 if self.breakOnMain_: 993 self.createBreakpointAtMain() 994 self.process = self.target.Launch(launchInfo, error) 995 if not error.Success(): 996 self.report(self.describeError(error)) 997 self.reportState('enginerunfailed') 998 return 999 self.report('pid="%s"' % self.process.GetProcessID()) 1000 self.reportState('enginerunandinferiorrunok') 1001 1002 s = threading.Thread(target=self.loop, args=[]) 1003 s.start() 1004 1005 def loop(self): 1006 event = lldb.SBEvent() 1007 #broadcaster = self.target.GetBroadcaster() 1008 listener = self.debugger.GetListener() 1009 1010 while True: 1011 while listener.GetNextEvent(event): 1012 self.handleEvent(event) 1013 time.sleep(0.25) 1014 1015 #if listener.WaitForEventForBroadcaster(0, broadcaster, event): 1016 # self.handleEvent(event) 1017 1018 def describeError(self, error): 1019 desc = lldb.SBStream() 1020 error.GetDescription(desc) 1021 result = 'success="%d",' % int(error.Success()) 1022 result += 'error={type="%s"' % error.GetType() 1023 if error.GetType(): 1024 result += ',status="%s"' % error.GetCString() 1025 result += ',code="%s"' % error.GetError() 1026 result += ',desc="%s"}' % toCString(desc.GetData()) 1027 return result 1028 1029 def describeStatus(self, status): 1030 return 'status="%s",' % toCString(status) 1031 1032 def describeLocation(self, frame): 1033 if int(frame.pc) == 0xffffffffffffffff: 1034 return '' 1035 fileName = fileNameAsString(frame.line_entry.file) 1036 function = frame.GetFunctionName() 1037 line = frame.line_entry.line 1038 return 'location={file="%s",line="%s",address="%s",function="%s"}' \ 1039 % (fileName, line, frame.pc, function) 1040 1041 def currentThread(self): 1042 return None if self.process is None else self.process.GetSelectedThread() 1043 1044 def currentFrame(self): 1045 thread = self.currentThread() 1046 return None if thread is None else thread.GetSelectedFrame() 1047 1048 def firstStoppedThread(self): 1049 for i in range(0, self.process.GetNumThreads()): 1050 thread = self.process.GetThreadAtIndex(i) 1051 reason = thread.GetStopReason() 1052 if (reason == lldb.eStopReasonBreakpoint or 1053 reason == lldb.eStopReasonException or 1054 reason == lldb.eStopReasonPlanComplete or 1055 reason == lldb.eStopReasonSignal or 1056 reason == lldb.eStopReasonWatchpoint): 1057 return thread 1058 return None 1059 1060 def fetchThreads(self, args): 1061 result = 'threads=[' 1062 for i in range(0, self.process.GetNumThreads()): 1063 thread = self.process.GetThreadAtIndex(i) 1064 if thread.is_stopped: 1065 state = 'stopped' 1066 elif thread.is_suspended: 1067 state = 'suspended' 1068 else: 1069 state = 'unknown' 1070 reason = thread.GetStopReason() 1071 result += '{id="%d"' % thread.GetThreadID() 1072 result += ',index="%s"' % i 1073 result += ',details="%s"' % toCString(thread.GetQueueName()) 1074 result += ',stop-reason="%s"' % self.stopReason(thread.GetStopReason()) 1075 result += ',state="%s"' % state 1076 result += ',name="%s"' % toCString(thread.GetName()) 1077 result += ',frame={' 1078 frame = thread.GetFrameAtIndex(0) 1079 result += 'pc="0x%x"' % frame.pc 1080 result += ',addr="0x%x"' % frame.pc 1081 result += ',fp="0x%x"' % frame.fp 1082 result += ',func="%s"' % frame.GetFunctionName() 1083 result += ',line="%s"' % frame.line_entry.line 1084 result += ',fullname="%s"' % fileNameAsString(frame.line_entry.file) 1085 result += ',file="%s"' % fileNameAsString(frame.line_entry.file) 1086 result += '}},' 1087 1088 result += '],current-thread-id="%s"' % self.currentThread().id 1089 self.reportResult(result, args) 1090 1091 def firstUsableFrame(self, thread): 1092 for i in range(10): 1093 frame = thread.GetFrameAtIndex(i) 1094 lineEntry = frame.GetLineEntry() 1095 line = lineEntry.GetLine() 1096 if line != 0: 1097 return i 1098 return None 1099 1100 def fetchStack(self, args): 1101 if not self.process: 1102 self.reportResult('msg="No process"', args) 1103 return 1104 thread = self.currentThread() 1105 if not thread: 1106 self.reportResult('msg="No thread"', args) 1107 return 1108 1109 isNativeMixed = int(args.get('nativemixed', 0)) 1110 extraQml = int(args.get('extraqml', '0')) 1111 1112 limit = args.get('stacklimit', -1) 1113 (n, isLimited) = (limit, True) if limit > 0 else (thread.GetNumFrames(), False) 1114 self.currentCallContext = None 1115 result = 'stack={current-thread="%d"' % thread.GetThreadID() 1116 result += ',frames=[' 1117 1118 ii = 0 1119 if extraQml: 1120 ns = self.qtNamespace() 1121 needle = self.qtNamespace() + 'QV4::ExecutionEngine' 1122 pats = [ 1123 '{0}qt_v4StackTraceForEngine((void*)0x{1:x})', 1124 '{0}qt_v4StackTrace((({0}QV4::ExecutionEngine *)0x{1:x})->currentContext())', 1125 '{0}qt_v4StackTrace((({0}QV4::ExecutionEngine *)0x{1:x})->currentContext)', 1126 ] 1127 done = False 1128 while ii < n and not done: 1129 res = None 1130 frame = thread.GetFrameAtIndex(ii) 1131 if not frame.IsValid(): 1132 break 1133 for variable in frame.GetVariables(True, True, False, True): 1134 if not variable.GetType().IsPointerType(): 1135 continue 1136 derefvar = variable.Dereference() 1137 if derefvar.GetType().GetName() != needle: 1138 continue 1139 addr = derefvar.GetLoadAddress() 1140 for pat in pats: 1141 exp = pat.format(ns, addr) 1142 val = frame.EvaluateExpression(exp) 1143 err = val.GetError() 1144 res = str(val) 1145 if err.Fail(): 1146 continue 1147 pos = res.find('"stack=[') 1148 if pos == -1: 1149 continue 1150 res = res[pos + 8:-2] 1151 res = res.replace('\\\"', '\"') 1152 res = res.replace('func=', 'function=') 1153 result += res 1154 done = True 1155 break 1156 ii += 1 1157 # if we have not found a qml stack do not omit original stack 1158 if not done: 1159 DumperBase.warn("Failed to fetch qml stack - you need Qt debug information") 1160 ii = 0 1161 1162 for i in range(n - ii): 1163 frame = thread.GetFrameAtIndex(i) 1164 if not frame.IsValid(): 1165 isLimited = False 1166 break 1167 1168 lineEntry = frame.GetLineEntry() 1169 lineNumber = lineEntry.GetLine() 1170 1171 pc = frame.GetPC() 1172 level = frame.idx 1173 addr = frame.GetPCAddress().GetLoadAddress(self.target) 1174 1175 functionName = frame.GetFunctionName() 1176 module = frame.GetModule() 1177 1178 if isNativeMixed and functionName == '::qt_qmlDebugMessageAvailable()': 1179 interpreterStack = self.extractInterpreterStack() 1180 for interpreterFrame in interpreterStack.get('frames', []): 1181 function = interpreterFrame.get('function', '') 1182 fileName = toCString(interpreterFrame.get('file', '')) 1183 language = interpreterFrame.get('language', '') 1184 lineNumber = interpreterFrame.get('line', 0) 1185 context = interpreterFrame.get('context', 0) 1186 result += ('frame={function="%s",file="%s",' 1187 'line="%s",language="%s",context="%s"}' 1188 % (function, fileName, lineNumber, language, context)) 1189 1190 fileName = fileNameAsString(lineEntry.file) 1191 result += '{pc="0x%x"' % pc 1192 result += ',level="%d"' % level 1193 result += ',address="0x%x"' % addr 1194 result += ',function="%s"' % functionName 1195 result += ',line="%d"' % lineNumber 1196 result += ',module="%s"' % toCString(module) 1197 result += ',file="%s"},' % fileName 1198 result += ']' 1199 result += ',hasmore="%d"' % isLimited 1200 result += ',limit="%d"' % limit 1201 result += '}' 1202 self.reportResult(result, args) 1203 1204 def reportResult(self, result, args): 1205 self.report('result={token="%s",%s}' % (args.get("token", 0), result)) 1206 1207 def reportToken(self, args): 1208 if "token" in args: 1209 # Unusual syntax intended, to support the double-click in left 1210 # logview pane feature. 1211 self.report('token(\"%s\")' % args["token"]) 1212 1213 def reportBreakpointUpdate(self, bp): 1214 self.report('breakpointmodified={%s}' % self.describeBreakpoint(bp)) 1215 1216 def readRawMemory(self, address, size): 1217 if size == 0: 1218 return bytes() 1219 error = lldb.SBError() 1220 #DumperBase.warn("READ: %s %s" % (address, size)) 1221 res = self.process.ReadMemory(address, size, error) 1222 if res is None or len(res) != size: 1223 # Using code in e.g. readToFirstZero relies on exceptions. 1224 raise RuntimeError("Unreadable %s bytes at 0x%x" % (size, address)) 1225 return res 1226 1227 def findStaticMetaObject(self, type): 1228 symbolName = self.mangleName(type.name + '::staticMetaObject') 1229 symbol = self.target.FindFirstGlobalVariable(symbolName) 1230 return symbol.AddressOf().GetValueAsUnsigned() if symbol.IsValid() else 0 1231 1232 def findSymbol(self, symbolName): 1233 return self.target.FindFirstGlobalVariable(symbolName) 1234 1235 def warn(self, msg): 1236 self.put('{name="%s",value="",type="",numchild="0"},' % toCString(msg)) 1237 1238 def fetchVariables(self, args): 1239 (ok, res) = self.tryFetchInterpreterVariables(args) 1240 if ok: 1241 self.reportResult(res, args) 1242 return 1243 1244 self.setVariableFetchingOptions(args) 1245 1246 # Reset certain caches whenever a step over / into / continue 1247 # happens. 1248 # FIXME: Caches are currently also cleared if currently 1249 # selected frame is changed, that shouldn't happen. 1250 if not self.partialVariable: 1251 self.resetPerStepCaches() 1252 1253 frame = self.currentFrame() 1254 if frame is None: 1255 self.reportResult('error="No frame"', args) 1256 return 1257 1258 self.output = '' 1259 isPartial = len(self.partialVariable) > 0 1260 1261 self.currentIName = 'local' 1262 self.put('data=[') 1263 1264 with SubItem(self, '[statics]'): 1265 self.put('iname="%s",' % self.currentIName) 1266 self.putEmptyValue() 1267 self.putExpandable() 1268 if self.isExpanded(): 1269 with Children(self): 1270 statics = frame.GetVariables(False, False, True, False) 1271 if len(statics): 1272 for i in range(len(statics)): 1273 staticVar = statics[i] 1274 staticVar.SetPreferSyntheticValue(False) 1275 typename = staticVar.GetType().GetName() 1276 name = staticVar.GetName() 1277 with SubItem(self, i): 1278 self.put('name="%s",' % name) 1279 self.put('iname="%s",' % self.currentIName) 1280 self.putItem(self.fromNativeValue(staticVar)) 1281 else: 1282 with SubItem(self, "None"): 1283 self.putEmptyValue() 1284 1285 # FIXME: Implement shortcut for partial updates. 1286 #if isPartial: 1287 # values = [frame.FindVariable(partialVariable)] 1288 #else: 1289 if True: 1290 values = list(frame.GetVariables(True, True, False, True)) 1291 values.reverse() # To get shadowed vars numbered backwards. 1292 1293 variables = [] 1294 for val in values: 1295 val.SetPreferSyntheticValue(False) 1296 if not val.IsValid(): 1297 continue 1298 self.currentContextValue = val 1299 name = val.GetName() 1300 if name is None: 1301 # This can happen for unnamed function parameters with 1302 # default values: void foo(int = 0) 1303 continue 1304 value = self.fromNativeFrameValue(val) 1305 variables.append(value) 1306 1307 self.handleLocals(variables) 1308 self.handleWatches(args) 1309 1310 self.put('],partial="%d"' % isPartial) 1311 self.reportResult(self.output, args) 1312 1313 1314 def fetchRegisters(self, args=None): 1315 if not self.process: 1316 self.reportResult('process="none",registers=[]', args) 1317 return 1318 1319 frame = self.currentFrame() 1320 if not frame or not frame.IsValid(): 1321 self.reportResult('frame="none",registers=[]', args) 1322 return 1323 1324 result = 'registers=[' 1325 for group in frame.GetRegisters(): 1326 for reg in group: 1327 data = reg.GetData() 1328 if data.GetByteOrder() == lldb.eByteOrderLittle: 1329 value = ''.join(["%02x" % x for x in reversed(data.uint8s)]) 1330 else: 1331 value = ''.join(["%02x" % x for x in data.uint8s]) 1332 result += '{name="%s"' % reg.GetName() 1333 result += ',value="0x%s"' % value 1334 result += ',size="%s"' % reg.GetByteSize() 1335 result += ',type="%s"},' % reg.GetType() 1336 result += ']' 1337 self.reportResult(result, args) 1338 1339 1340 def setRegister(self, args): 1341 name = args["name"] 1342 value = args["value"] 1343 result = lldb.SBCommandReturnObject() 1344 interp = self.debugger.GetCommandInterpreter() 1345 interp.HandleCommand("register write %s %s" % (name, value), result) 1346 success = result.Succeeded() 1347 if success: 1348 self.reportResult('output="%s"' % toCString(result.GetOutput()), args) 1349 return 1350 # Try again with register write xmm0 "{0x00 ... 0x02}" syntax: 1351 vec = ' '.join(["0x" + value[i:i + 2] for i in range(2, len(value), 2)]) 1352 success = interp.HandleCommand('register write %s "{%s}"' % (name, vec), result) 1353 if success: 1354 self.reportResult('output="%s"' % toCString(result.GetOutput()), args) 1355 else: 1356 self.reportResult('error="%s"' % toCString(result.GetError()), args) 1357 1358 def report(self, stuff): 1359 with self.outputLock: 1360 sys.stdout.write("@\n" + stuff + "@\n") 1361 sys.stdout.flush() 1362 1363 def reportState(self, state): 1364 self.report('state="%s"' % state) 1365 1366 def interruptInferior(self, args): 1367 if self.process is None: 1368 self.reportResult('status="No process to interrupt",success="0"', args) 1369 else: 1370 self.isInterrupting_ = True 1371 error = self.process.Stop() 1372 self.reportResult(self.describeError(error), args) 1373 1374 def detachInferior(self, args): 1375 if self.process is None: 1376 self.reportResult('status="No process to detach from."', args) 1377 else: 1378 error = self.process.Detach() 1379 self.reportResult(self.describeError(error), args) 1380 1381 def continueInferior(self, args): 1382 if self.process is None: 1383 self.reportResult('status="No process to continue."', args) 1384 else: 1385 # Can fail when attaching to GDBserver. 1386 error = self.process.Continue() 1387 self.reportResult(self.describeError(error), args) 1388 1389 def quitDebugger(self, args): 1390 self.reportState("inferiorshutdownrequested") 1391 self.process.Kill() 1392 self.reportResult('', args) 1393 1394 def handleBreakpointEvent(self, event): 1395 eventType = lldb.SBBreakpoint.GetBreakpointEventTypeFromEvent(event) 1396 # handle only the resolved locations for now.. 1397 if eventType & lldb.eBreakpointEventTypeLocationsResolved: 1398 bp = lldb.SBBreakpoint.GetBreakpointFromEvent(event) 1399 if bp is not None: 1400 self.reportBreakpointUpdate(bp) 1401 1402 def handleEvent(self, event): 1403 if lldb.SBBreakpoint.EventIsBreakpointEvent(event): 1404 self.handleBreakpointEvent(event) 1405 return 1406 if not lldb.SBProcess.EventIsProcessEvent(event): 1407 self.warn("UNEXPECTED event (%s)" % event.GetType()) 1408 return 1409 1410 out = lldb.SBStream() 1411 event.GetDescription(out) 1412 #DumperBase.warn("EVENT: %s" % event) 1413 eventType = event.GetType() 1414 msg = lldb.SBEvent.GetCStringFromEvent(event) 1415 flavor = event.GetDataFlavor() 1416 state = lldb.SBProcess.GetStateFromEvent(event) 1417 bp = lldb.SBBreakpoint.GetBreakpointFromEvent(event) 1418 skipEventReporting = eventType in ( 1419 lldb.SBProcess.eBroadcastBitSTDOUT, lldb.SBProcess.eBroadcastBitSTDERR) 1420 self.report('event={type="%s",data="%s",msg="%s",flavor="%s",state="%s",bp="%s"}' 1421 % (eventType, toCString(out.GetData()), 1422 toCString(msg), flavor, self.stateName(state), bp)) 1423 1424 if state == lldb.eStateExited: 1425 self.eventState = state 1426 if not self.isShuttingDown_: 1427 self.reportState("inferiorexited") 1428 self.report('exited={status="%d",desc="%s"}' 1429 % (self.process.GetExitStatus(), 1430 toCString(self.process.GetExitDescription()))) 1431 elif state != self.eventState and not skipEventReporting: 1432 self.eventState = state 1433 if state == lldb.eStateStopped: 1434 stoppedThread = self.firstStoppedThread() 1435 if stoppedThread: 1436 #self.report("STOPPED THREAD: %s" % stoppedThread) 1437 frame = stoppedThread.GetFrameAtIndex(0) 1438 #self.report("FRAME: %s" % frame) 1439 function = frame.GetFunction() 1440 functionName = function.GetName() 1441 if functionName == "::qt_qmlDebugConnectorOpen()": 1442 self.report("RESOLVER HIT") 1443 for resolver in self.interpreterBreakpointResolvers: 1444 resolver() 1445 self.report("AUTO-CONTINUE AFTER RESOLVING") 1446 self.reportState("inferiorstopok") 1447 self.process.Continue() 1448 return 1449 if functionName == "::qt_qmlDebugMessageAvailable()": 1450 self.report("ASYNC MESSAGE FROM SERVICE") 1451 res = self.handleInterpreterMessage() 1452 if not res: 1453 self.report("EVENT NEEDS NO STOP") 1454 self.reportState("stopped") 1455 self.process.Continue() 1456 return 1457 if self.isInterrupting_: 1458 self.isInterrupting_ = False 1459 self.reportState("inferiorstopok") 1460 else: 1461 self.reportState("stopped") 1462 else: 1463 self.reportState(self.stateName(state)) 1464 1465 if eventType == lldb.SBProcess.eBroadcastBitStateChanged: # 1 1466 state = self.process.GetState() 1467 if state == lldb.eStateStopped: 1468 stoppedThread = self.firstStoppedThread() 1469 if stoppedThread: 1470 self.process.SetSelectedThread(stoppedThread) 1471 elif eventType == lldb.SBProcess.eBroadcastBitInterrupt: # 2 1472 pass 1473 elif eventType == lldb.SBProcess.eBroadcastBitSTDOUT: 1474 self.handleInferiorOutput(self.process.GetSTDOUT, "stdout") 1475 elif eventType == lldb.SBProcess.eBroadcastBitSTDERR: 1476 self.handleInferiorOutput(self.process.GetSTDERR, "stderr") 1477 elif eventType == lldb.SBProcess.eBroadcastBitProfileData: 1478 pass 1479 1480 def handleInferiorOutput(self, proc, channel): 1481 while True: 1482 msg = proc(1024) 1483 if msg == None or len(msg) == 0: 1484 break 1485 self.report('output={channel="%s",data="%s"}' % (channel, self.hexencode(msg))) 1486 1487 def describeBreakpoint(self, bp): 1488 isWatch = isinstance(bp, lldb.SBWatchpoint) 1489 if isWatch: 1490 result = 'lldbid="%s"' % (qqWatchpointOffset + bp.GetID()) 1491 else: 1492 result = 'lldbid="%s"' % bp.GetID() 1493 result += ',valid="%d"' % (1 if bp.IsValid() else 0) 1494 result += ',hitcount="%d"' % bp.GetHitCount() 1495 if bp.IsValid(): 1496 if isinstance(bp, lldb.SBBreakpoint): 1497 result += ',threadid="%d"' % bp.GetThreadID() 1498 result += ',oneshot="%d"' % (1 if bp.IsOneShot() else 0) 1499 cond = bp.GetCondition() 1500 result += ',condition="%s"' % self.hexencode("" if cond is None else cond) 1501 result += ',enabled="%d"' % (1 if bp.IsEnabled() else 0) 1502 result += ',valid="%d"' % (1 if bp.IsValid() else 0) 1503 result += ',ignorecount="%d"' % bp.GetIgnoreCount() 1504 if bp.IsValid() and isinstance(bp, lldb.SBBreakpoint): 1505 result += ',locations=[' 1506 lineEntry = None 1507 for i in range(bp.GetNumLocations()): 1508 loc = bp.GetLocationAtIndex(i) 1509 addr = loc.GetAddress() 1510 lineEntry = addr.GetLineEntry() 1511 result += '{locid="%d"' % loc.GetID() 1512 result += ',function="%s"' % addr.GetFunction().GetName() 1513 result += ',enabled="%d"' % (1 if loc.IsEnabled() else 0) 1514 result += ',resolved="%d"' % (1 if loc.IsResolved() else 0) 1515 result += ',valid="%d"' % (1 if loc.IsValid() else 0) 1516 result += ',ignorecount="%d"' % loc.GetIgnoreCount() 1517 result += ',file="%s"' % toCString(lineEntry.GetFileSpec()) 1518 result += ',line="%d"' % lineEntry.GetLine() 1519 result += ',addr="%s"},' % addr.GetFileAddress() 1520 result += ']' 1521 if lineEntry is not None: 1522 result += ',file="%s"' % toCString(lineEntry.GetFileSpec()) 1523 result += ',line="%d"' % lineEntry.GetLine() 1524 return result 1525 1526 def createBreakpointAtMain(self): 1527 return self.target.BreakpointCreateByName( 1528 'main', self.target.GetExecutable().GetFilename()) 1529 1530 def insertBreakpoint(self, args): 1531 bpType = args['type'] 1532 if bpType == BreakpointType.BreakpointByFileAndLine: 1533 fileName = args['file'] 1534 if fileName.endswith('.js') or fileName.endswith('.qml'): 1535 self.insertInterpreterBreakpoint(args) 1536 return 1537 1538 extra = '' 1539 more = True 1540 if bpType == BreakpointType.BreakpointByFileAndLine: 1541 bp = self.target.BreakpointCreateByLocation( 1542 str(args['file']), int(args['line'])) 1543 elif bpType == BreakpointType.BreakpointByFunction: 1544 bp = self.target.BreakpointCreateByName(args['function']) 1545 elif bpType == BreakpointType.BreakpointByAddress: 1546 bp = self.target.BreakpointCreateByAddress(args['address']) 1547 elif bpType == BreakpointType.BreakpointAtMain: 1548 bp = self.createBreakpointAtMain() 1549 elif bpType == BreakpointType.BreakpointAtThrow: 1550 bp = self.target.BreakpointCreateForException( 1551 lldb.eLanguageTypeC_plus_plus, False, True) 1552 elif bpType == BreakpointType.BreakpointAtCatch: 1553 bp = self.target.BreakpointCreateForException( 1554 lldb.eLanguageTypeC_plus_plus, True, False) 1555 elif bpType == BreakpointType.WatchpointAtAddress: 1556 error = lldb.SBError() 1557 # This might yield bp.IsValid() == False and 1558 # error.desc == 'process is not alive'. 1559 bp = self.target.WatchAddress(args['address'], 4, False, True, error) 1560 extra = self.describeError(error) 1561 elif bpType == BreakpointType.WatchpointAtExpression: 1562 # FIXME: Top level-only for now. 1563 try: 1564 frame = self.currentFrame() 1565 value = frame.FindVariable(args['expression']) 1566 error = lldb.SBError() 1567 bp = self.target.WatchAddress(value.GetLoadAddress(), 1568 value.GetByteSize(), False, True, error) 1569 except: 1570 bp = self.target.BreakpointCreateByName(None) 1571 else: 1572 # This leaves the unhandled breakpoint in a (harmless) 1573 # 'pending' state. 1574 bp = self.target.BreakpointCreateByName(None) 1575 more = False 1576 1577 if more and bp.IsValid(): 1578 bp.SetIgnoreCount(int(args['ignorecount'])) 1579 bp.SetCondition(self.hexdecode(args['condition'])) 1580 bp.SetEnabled(bool(args['enabled'])) 1581 bp.SetScriptCallbackBody('\n'.join([ 1582 'def foo(frame = frame, bp_loc = bp_loc, dict = internal_dict):', 1583 ' ' + self.hexdecode(args['command']).replace('\n', '\n '), 1584 'from cStringIO import StringIO', 1585 'origout = sys.stdout', 1586 'sys.stdout = StringIO()', 1587 'result = foo()', 1588 'd = lldb.theDumper', 1589 'output = d.hexencode(sys.stdout.getvalue())', 1590 'sys.stdout = origout', 1591 'd.report("output={channel=\"stderr\",data=\" + output + \"}")', 1592 'sys.stdout.flush()', 1593 'if result is False:', 1594 ' d.reportState("continueafternextstop")', 1595 'return True' 1596 ])) 1597 if isinstance(bp, lldb.SBBreakpoint): 1598 bp.SetOneShot(bool(args['oneshot'])) 1599 self.reportResult(self.describeBreakpoint(bp) + extra, args) 1600 1601 def changeBreakpoint(self, args): 1602 lldbId = int(args['lldbid']) 1603 if lldbId > qqWatchpointOffset: 1604 bp = self.target.FindWatchpointByID(lldbId) 1605 else: 1606 bp = self.target.FindBreakpointByID(lldbId) 1607 if bp.IsValid(): 1608 bp.SetIgnoreCount(int(args['ignorecount'])) 1609 bp.SetCondition(self.hexdecode(args['condition'])) 1610 bp.SetEnabled(bool(args['enabled'])) 1611 if isinstance(bp, lldb.SBBreakpoint): 1612 bp.SetOneShot(bool(args['oneshot'])) 1613 self.reportResult(self.describeBreakpoint(bp), args) 1614 1615 def enableSubbreakpoint(self, args): 1616 lldbId = int(args['lldbid']) 1617 locId = int(args['locid']) 1618 bp = self.target.FindBreakpointByID(lldbId) 1619 res = False 1620 enabled = False 1621 if bp.IsValid(): 1622 loc = bp.FindLocationByID(locId) 1623 if loc.IsValid(): 1624 loc.SetEnabled(bool(args['enabled'])) 1625 enabled = loc.IsEnabled() 1626 res = True 1627 self.reportResult('success="%d",enabled="%d",locid="%d"' 1628 % (int(res), int(enabled), locId), args) 1629 1630 def removeBreakpoint(self, args): 1631 lldbId = int(args['lldbid']) 1632 if lldbId > qqWatchpointOffset: 1633 res = self.target.DeleteWatchpoint(lldbId - qqWatchpointOffset) 1634 res = self.target.BreakpointDelete(lldbId) 1635 self.reportResult('success="%d"' % int(res), args) 1636 1637 def fetchModules(self, args): 1638 result = 'modules=[' 1639 for i in range(self.target.GetNumModules()): 1640 module = self.target.GetModuleAtIndex(i) 1641 result += '{file="%s"' % toCString(module.file.fullpath) 1642 result += ',name="%s"' % toCString(module.file.basename) 1643 result += ',addrsize="%d"' % module.addr_size 1644 result += ',triple="%s"' % module.triple 1645 #result += ',sections={' 1646 #for section in module.sections: 1647 # result += '[name="%s"' % section.name 1648 # result += ',addr="%s"' % section.addr 1649 # result += ',size="%d"],' % section.size 1650 #result += '}' 1651 result += '},' 1652 result += ']' 1653 self.reportResult(result, args) 1654 1655 def fetchSymbols(self, args): 1656 moduleName = args['module'] 1657 #file = lldb.SBFileSpec(moduleName) 1658 #module = self.target.FindModule(file) 1659 for i in range(self.target.GetNumModules()): 1660 module = self.target.GetModuleAtIndex(i) 1661 if module.file.fullpath == moduleName: 1662 break 1663 result = 'symbols={valid="%s"' % module.IsValid() 1664 result += ',sections="%s"' % module.GetNumSections() 1665 result += ',symbols=[' 1666 for symbol in module.symbols: 1667 startAddress = symbol.GetStartAddress().GetLoadAddress(self.target) 1668 endAddress = symbol.GetEndAddress().GetLoadAddress(self.target) 1669 result += '{type="%s"' % symbol.GetType() 1670 result += ',name="%s"' % symbol.GetName() 1671 result += ',address="0x%x"' % startAddress 1672 result += ',demangled="%s"' % symbol.GetMangledName() 1673 result += ',size="%d"' % (endAddress - startAddress) 1674 result += '},' 1675 result += ']}' 1676 self.reportResult(result, args) 1677 1678 def executeNext(self, args): 1679 self.currentThread().StepOver() 1680 self.reportResult('', args) 1681 1682 def executeNextI(self, args): 1683 self.currentThread().StepInstruction(True) 1684 self.reportResult('', args) 1685 1686 def executeStep(self, args): 1687 self.currentThread().StepInto() 1688 self.reportResult('', args) 1689 1690 def shutdownInferior(self, args): 1691 self.isShuttingDown_ = True 1692 if self.process is not None: 1693 state = self.process.GetState() 1694 if state == lldb.eStateStopped: 1695 self.process.Kill() 1696 self.reportState('inferiorshutdownfinished') 1697 self.reportResult('', args) 1698 1699 def quit(self, args): 1700 self.reportState('engineshutdownfinished') 1701 self.process.Kill() 1702 self.reportResult('', args) 1703 1704 def executeStepI(self, args): 1705 self.currentThread().StepInstruction(False) 1706 self.reportResult('', args) 1707 1708 def executeStepOut(self, args={}): 1709 self.currentThread().StepOut() 1710 self.reportResult('', args) 1711 1712 def executeRunToLocation(self, args): 1713 self.reportToken(args) 1714 addr = args.get('address', 0) 1715 if addr: 1716 # Does not seem to hit anything on Linux: 1717 # self.currentThread().RunToAddress(addr) 1718 bp = self.target.BreakpointCreateByAddress(addr) 1719 if bp.GetNumLocations() == 0: 1720 self.target.BreakpointDelete(bp.GetID()) 1721 self.reportResult(self.describeStatus('No target location found.') 1722 + self.describeLocation(frame), args) 1723 return 1724 bp.SetOneShot(True) 1725 self.reportResult('', args) 1726 self.process.Continue() 1727 else: 1728 frame = self.currentFrame() 1729 file = args['file'] 1730 line = int(args['line']) 1731 error = self.currentThread().StepOverUntil(frame, lldb.SBFileSpec(file), line) 1732 self.reportResult(self.describeError(error), args) 1733 self.reportState('running') 1734 self.reportState('stopped') 1735 1736 def executeJumpToLocation(self, args): 1737 self.reportToken(args) 1738 frame = self.currentFrame() 1739 if not frame: 1740 self.reportResult(self.describeStatus('No frame available.'), args) 1741 return 1742 addr = args.get('address', 0) 1743 if addr: 1744 bp = self.target.BreakpointCreateByAddress(addr) 1745 else: 1746 bp = self.target.BreakpointCreateByLocation( 1747 str(args['file']), int(args['line'])) 1748 if bp.GetNumLocations() == 0: 1749 self.target.BreakpointDelete(bp.GetID()) 1750 status = 'No target location found.' 1751 else: 1752 loc = bp.GetLocationAtIndex(0) 1753 self.target.BreakpointDelete(bp.GetID()) 1754 res = frame.SetPC(loc.GetLoadAddress()) 1755 status = 'Jumped.' if res else 'Cannot jump.' 1756 self.report(self.describeLocation(frame)) 1757 self.reportResult(self.describeStatus(status), args) 1758 1759 def breakList(self): 1760 result = lldb.SBCommandReturnObject() 1761 self.debugger.GetCommandInterpreter().HandleCommand('break list', result) 1762 self.report('success="%d",output="%s",error="%s"' 1763 % (result.Succeeded(), toCString(result.GetOutput()), 1764 toCString(result.GetError()))) 1765 1766 def activateFrame(self, args): 1767 self.reportToken(args) 1768 frame = max(0, int(args['index'])) # Can be -1 in all-asm stacks 1769 self.currentThread().SetSelectedFrame(frame) 1770 self.reportResult('', args) 1771 1772 def selectThread(self, args): 1773 self.reportToken(args) 1774 self.process.SetSelectedThreadByID(int(args['id'])) 1775 self.reportResult('', args) 1776 1777 def fetchFullBacktrace(self, _=None): 1778 command = 'thread backtrace all' 1779 result = lldb.SBCommandReturnObject() 1780 self.debugger.GetCommandInterpreter().HandleCommand(command, result) 1781 self.reportResult(self.hexencode(result.GetOutput()), {}) 1782 1783 def executeDebuggerCommand(self, args): 1784 self.reportToken(args) 1785 result = lldb.SBCommandReturnObject() 1786 command = args['command'] 1787 self.debugger.GetCommandInterpreter().HandleCommand(command, result) 1788 success = result.Succeeded() 1789 output = toCString(result.GetOutput()) 1790 error = toCString(str(result.GetError())) 1791 self.report('success="%d",output="%s",error="%s"' % (success, output, error)) 1792 1793 def executeRoundtrip(self, args): 1794 self.reportResult('', args) 1795 1796 def fetchDisassembler(self, args): 1797 functionName = args.get('function', '') 1798 flavor = args.get('flavor', '') 1799 function = None 1800 if len(functionName): 1801 functions = self.target.FindFunctions(functionName).functions 1802 if len(functions): 1803 function = functions[0] 1804 if function: 1805 base = function.GetStartAddress().GetLoadAddress(self.target) 1806 instructions = function.GetInstructions(self.target) 1807 else: 1808 base = args.get('address', 0) 1809 if int(base) == 0xffffffffffffffff: 1810 self.warn('INVALID DISASSEMBLER BASE') 1811 return 1812 addr = lldb.SBAddress(base, self.target) 1813 instructions = self.target.ReadInstructions(addr, 100) 1814 1815 currentFile = None 1816 currentLine = None 1817 hunks = dict() 1818 sources = dict() 1819 result = 'lines=[' 1820 for insn in instructions: 1821 comment = insn.GetComment(self.target) 1822 addr = insn.GetAddress() 1823 loadAddr = addr.GetLoadAddress(self.target) 1824 lineEntry = addr.GetLineEntry() 1825 if lineEntry: 1826 lineNumber = lineEntry.GetLine() 1827 fileName = str(lineEntry.GetFileSpec()) 1828 if lineNumber != currentLine or fileName != currentFile: 1829 currentLine = lineNumber 1830 currentFile = fileName 1831 key = '%s:%s' % (fileName, lineNumber) 1832 hunk = hunks.get(key, 0) + 1 1833 hunks[key] = hunk 1834 source = sources.get(fileName, None) 1835 if source is None: 1836 try: 1837 with open(fileName, 'r') as f: 1838 source = f.read().splitlines() 1839 sources[fileName] = source 1840 except IOError as error: 1841 # With lldb-3.8 files like /data/dev/creator-3.6/tests/ 1842 # auto/debugger/qt_tst_dumpers_StdVector_bfNWZa/main.cpp 1843 # with non-existent directories appear. 1844 self.warn('FILE: %s ERROR: %s' % (fileName, error)) 1845 source = '' 1846 result += '{line="%d"' % lineNumber 1847 result += ',file="%s"' % toCString(fileName) 1848 if 0 < lineNumber and lineNumber <= len(source): 1849 result += ',hexdata="%s"' % self.hexencode(source[lineNumber - 1]) 1850 result += ',hunk="%s"}' % hunk 1851 result += '{address="%s"' % loadAddr 1852 result += ',data="%s %s"' % (insn.GetMnemonic(self.target), 1853 insn.GetOperands(self.target)) 1854 result += ',function="%s"' % functionName 1855 rawData = insn.GetData(self.target).uint8s 1856 result += ',rawdata="%s"' % ' '.join(["%02x" % x for x in rawData]) 1857 if comment: 1858 result += ',comment="%s"' % self.hexencode(comment) 1859 result += ',offset="%s"}' % (loadAddr - base) 1860 self.reportResult(result + ']', args) 1861 1862 def fetchMemory(self, args): 1863 address = args['address'] 1864 length = args['length'] 1865 error = lldb.SBError() 1866 contents = self.process.ReadMemory(address, length, error) 1867 result = 'address="%s",' % address 1868 result += self.describeError(error) 1869 result += ',contents="%s"' % self.hexencode(contents) 1870 self.reportResult(result, args) 1871 1872 def findValueByExpression(self, exp): 1873 # FIXME: Top level-only for now. 1874 frame = self.currentFrame() 1875 value = frame.FindVariable(exp) 1876 return value 1877 1878 def setValue(self, address, typename, value): 1879 sbtype = self.lookupNativeType(typename) 1880 error = lldb.SBError() 1881 sbaddr = lldb.SBAddress(address, self.target) 1882 sbvalue = self.target.CreateValueFromAddress('x', sbaddr, sbtype) 1883 sbvalue.SetValueFromCString(str(value), error) 1884 1885 def setValues(self, address, typename, values): 1886 sbtype = self.lookupNativeType(typename) 1887 sizeof = sbtype.GetByteSize() 1888 error = lldb.SBError() 1889 for i in range(len(values)): 1890 sbaddr = lldb.SBAddress(address + i * sizeof, self.target) 1891 sbvalue = self.target.CreateValueFromAddress('x', sbaddr, sbtype) 1892 sbvalue.SetValueFromCString(str(values[i]), error) 1893 1894 def assignValue(self, args): 1895 self.reportToken(args) 1896 error = lldb.SBError() 1897 expr = self.hexdecode(args['expr']) 1898 value = self.hexdecode(args['value']) 1899 simpleType = int(args['simpleType']) 1900 lhs = self.findValueByExpression(expr) 1901 typeName = lhs.GetType().GetName() 1902 typeName = typeName.replace('::', '__') 1903 pos = typeName.find('<') 1904 if pos != -1: 1905 typeName = typeName[0:pos] 1906 if typeName in self.qqEditable and not simpleType: 1907 expr = self.parseAndEvaluate(expr) 1908 self.qqEditable[typeName](self, expr, value) 1909 else: 1910 self.parseAndEvaluate(expr + '=' + value) 1911 self.reportResult(self.describeError(error), args) 1912 1913 def watchPoint(self, args): 1914 self.reportToken(args) 1915 ns = self.qtNamespace() 1916 lenns = len(ns) 1917 funcs = self.target.FindGlobalFunctions('.*QApplication::widgetAt', 2, 1) 1918 func = funcs[1] 1919 addr = func.GetFunction().GetStartAddress().GetLoadAddress(self.target) 1920 expr = '((void*(*)(int,int))0x%x)' % addr 1921 #expr = '%sQApplication::widgetAt(%s,%s)' % (ns, args['x'], args['y']) 1922 res = self.parseAndEvaluate(expr) 1923 p = 0 if res is None else res.pointer() 1924 n = ns + 'QWidget' 1925 self.reportResult('selected="0x%x",expr="(%s*)0x%x"' % (p, n, p), args) 1926 1927 def createResolvePendingBreakpointsHookBreakpoint(self, args): 1928 bp = self.target.BreakpointCreateByName('qt_qmlDebugConnectorOpen') 1929 bp.SetOneShot(True) 1930 self.interpreterBreakpointResolvers.append( 1931 lambda: self.resolvePendingInterpreterBreakpoint(args)) 1932 1933 1934# Used in dumper auto test. 1935class Tester(Dumper): 1936 def __init__(self, binary, args): 1937 Dumper.__init__(self) 1938 lldb.theDumper = self 1939 self.loadDumpers({'token': 1}) 1940 error = lldb.SBError() 1941 self.target = self.debugger.CreateTarget(binary, None, None, True, error) 1942 1943 if error.GetType(): 1944 self.warn('ERROR: %s' % error) 1945 return 1946 1947 s = threading.Thread(target=self.testLoop, args=(args,)) 1948 s.start() 1949 s.join(30) 1950 1951 def testLoop(self, args): 1952 # Disable intermediate reporting. 1953 savedReport = self.report 1954 self.report = lambda stuff: 0 1955 1956 error = lldb.SBError() 1957 launchInfo = lldb.SBLaunchInfo([]) 1958 launchInfo.SetWorkingDirectory(os.getcwd()) 1959 environmentList = [key + '=' + value for key, value in os.environ.items()] 1960 launchInfo.SetEnvironmentEntries(environmentList, False) 1961 1962 self.process = self.target.Launch(launchInfo, error) 1963 if error.GetType(): 1964 self.warn('ERROR: %s' % error) 1965 1966 event = lldb.SBEvent() 1967 listener = self.debugger.GetListener() 1968 while True: 1969 state = self.process.GetState() 1970 if listener.WaitForEvent(100, event): 1971 #DumperBase.warn('EVENT: %s' % event) 1972 state = lldb.SBProcess.GetStateFromEvent(event) 1973 if state == lldb.eStateExited: # 10 1974 break 1975 if state == lldb.eStateStopped: # 5 1976 stoppedThread = None 1977 for i in range(0, self.process.GetNumThreads()): 1978 thread = self.process.GetThreadAtIndex(i) 1979 reason = thread.GetStopReason() 1980 #DumperBase.warn('THREAD: %s REASON: %s' % (thread, reason)) 1981 if (reason == lldb.eStopReasonBreakpoint or 1982 reason == lldb.eStopReasonException or 1983 reason == lldb.eStopReasonSignal): 1984 stoppedThread = thread 1985 1986 if stoppedThread: 1987 # This seems highly fragile and depending on the 'No-ops' in the 1988 # event handling above. 1989 frame = stoppedThread.GetFrameAtIndex(0) 1990 line = frame.line_entry.line 1991 if line != 0: 1992 self.report = savedReport 1993 self.process.SetSelectedThread(stoppedThread) 1994 self.fakeAddress_ = frame.GetPC() 1995 self.fakeLAddress_ = frame.GetPCAddress() 1996 self.fetchVariables(args) 1997 #self.describeLocation(frame) 1998 self.report('@NS@%s@' % self.qtNamespace()) 1999 #self.report('ENV=%s' % os.environ.items()) 2000 #self.report('DUMPER=%s' % self.qqDumpers) 2001 break 2002 2003 else: 2004 self.warn('TIMEOUT') 2005 self.warn('Cannot determined stopped thread') 2006 2007 lldb.SBDebugger.Destroy(self.debugger) 2008 2009# ------------------------------ For use in LLDB ------------------------------ 2010 2011 2012from pprint import pprint 2013 2014__module__ = sys.modules[__name__] 2015DEBUG = False if not hasattr(__module__, 'DEBUG') else DEBUG 2016 2017 2018class LogMixin(): 2019 @staticmethod 2020 def log(message='', log_caller=False, frame=1, args=''): 2021 if not DEBUG: 2022 return 2023 if log_caller: 2024 message = ": " + message if len(message) else '' 2025 # FIXME: Compute based on first frame not in this class? 2026 frame = sys._getframe(frame) 2027 fn = frame.f_code.co_name 2028 localz = frame.f_locals 2029 instance = str(localz["self"]) + "." if 'self' in localz else '' 2030 message = "%s%s(%s)%s" % (instance, fn, args, message) 2031 print(message) 2032 2033 @staticmethod 2034 def log_fn(arg_str=''): 2035 LogMixin.log(log_caller=True, frame=2, args=arg_str) 2036 2037 2038class DummyDebugger(object): 2039 def __getattr__(self, attr): 2040 raise AttributeError("Debugger should not be needed to create summaries") 2041 2042 2043class SummaryDumper(Dumper, LogMixin): 2044 _instance = None 2045 _lock = threading.RLock() 2046 _type_caches = {} 2047 2048 @staticmethod 2049 def initialize(): 2050 SummaryDumper._instance = SummaryDumper() 2051 return SummaryDumper._instance 2052 2053 @staticmethod 2054 @contextmanager 2055 def shared(valobj): 2056 SummaryDumper._lock.acquire() 2057 dumper = SummaryDumper._instance 2058 dumper.target = valobj.target 2059 dumper.process = valobj.process 2060 debugger_id = dumper.target.debugger.GetID() 2061 dumper.typeCache = SummaryDumper._type_caches.get(debugger_id, {}) 2062 yield dumper 2063 SummaryDumper._type_caches[debugger_id] = dumper.typeCache 2064 SummaryDumper._lock.release() 2065 2066 @staticmethod 2067 def warn(message): 2068 print("Qt summary warning: %s" % message) 2069 2070 @staticmethod 2071 def showException(message, exType, exValue, exTraceback): 2072 # FIXME: Store for later and report back in summary 2073 SummaryDumper.log("Exception during dumping: %s" % exValue) 2074 2075 def __init__(self): 2076 DumperBase.warn = staticmethod(SummaryDumper.warn) 2077 DumperBase.showException = staticmethod(SummaryDumper.showException) 2078 2079 Dumper.__init__(self, DummyDebugger()) 2080 2081 self.setVariableFetchingOptions({ 2082 'fancy': True, 2083 'qobjectnames': True, 2084 'passexceptions': True 2085 }) 2086 2087 self.dumpermodules = ['qttypes'] 2088 self.loadDumpers({}) 2089 self.output = '' 2090 2091 def report(self, stuff): 2092 return # Don't mess up lldb output 2093 2094 def dump_summary(self, valobj, expanded=False): 2095 try: 2096 from pygdbmi import gdbmiparser 2097 except ImportError: 2098 print("Qt summary provider requires the pygdbmi module, " 2099 "please install using 'sudo /usr/bin/easy_install pygdbmi', " 2100 "and then restart Xcode.") 2101 lldb.debugger.HandleCommand('type category delete Qt') 2102 return None 2103 2104 value = self.fromNativeValue(valobj) 2105 2106 # Expand variable if we need synthetic children 2107 oldExpanded = self.expandedINames 2108 self.expandedINames = [value.name] if expanded else [] 2109 2110 savedOutput = self.output 2111 self.output = '' 2112 with TopLevelItem(self, value.name): 2113 self.putItem(value) 2114 2115 # FIXME: Hook into putField, etc to build up object instead of parsing MI 2116 response = gdbmiparser.parse_response("^ok,summary=%s" % self.output) 2117 2118 self.output = savedOutput 2119 self.expandedINames = oldExpanded 2120 2121 summary = response["payload"]["summary"] 2122 2123 #print value, " --> ", 2124 #pprint(summary) 2125 2126 return summary 2127 2128 2129class SummaryProvider(LogMixin): 2130 2131 DEFAULT_SUMMARY = '' 2132 VOID_PTR_TYPE = None 2133 2134 @staticmethod 2135 def provide_summary(valobj, internal_dict, options=None): 2136 if __name__ not in internal_dict: 2137 # When disabling the import of the Qt summary providers, the 2138 # summary functions are still registered with LLDB, and we will 2139 # get callbacks to provide summaries, but at this point the child 2140 # providers are not active, so instead of providing half-baked and 2141 # confusing summaries we opt to unload all the summaries. 2142 SummaryDumper.log("Module '%s' was unloaded, removing Qt category" % __name__) 2143 lldb.debugger.HandleCommand('type category delete Qt') 2144 return SummaryProvider.DEFAULT_SUMMARY 2145 2146 # FIXME: It would be nice to cache the providers, so that if a 2147 # synthetic child provider has already been created for a valobj, 2148 # we can re-use that when providing summary for the synthetic child 2149 # parent, but we lack a consistent cache key for that to work. 2150 2151 provider = SummaryProvider(valobj) 2152 provider.update() 2153 2154 return provider.get_summary(options) 2155 2156 def __init__(self, valobj, expand=False): 2157 # Prevent recursive evaluation during logging, etc 2158 valobj.SetPreferSyntheticValue(False) 2159 2160 self.log_fn(valobj.path) 2161 2162 self.valobj = valobj 2163 self.expand = expand 2164 2165 if not SummaryProvider.VOID_PTR_TYPE: 2166 with SummaryDumper.shared(self.valobj) as dumper: 2167 SummaryProvider.VOID_PTR_TYPE = dumper.lookupNativeType('void*') 2168 2169 def __repr__(self): 2170 return "%s(%s)" % (self.__class__.__name__, repr(self.key())) 2171 2172 def key(self): 2173 if not hasattr(self, 'valobj'): 2174 return None 2175 return self.valobj.path 2176 2177 def update(self): 2178 self.log_fn() 2179 with SummaryDumper.shared(self.valobj) as dumper: 2180 self.summary = dumper.dump_summary(self.valobj, self.expand) 2181 2182 def get_summary(self, options): 2183 self.log_fn() 2184 2185 summary = self.summary 2186 if not summary: 2187 return '<error: could not get summary from Qt provider>' 2188 2189 encoding = summary.get("valueencoded") 2190 summaryValue = summary["value"] 2191 2192 # FIXME: Share between Creator and LLDB in the python code 2193 2194 if encoding: 2195 special_encodings = { 2196 "empty": "<empty>", 2197 "minimumitemcount": "<at least %s items>" % summaryValue, 2198 "undefined": "<undefined>", 2199 "null": "<null>", 2200 "itemcount": "<%s items>" % summaryValue, 2201 "notaccessible": "<not accessible>", 2202 "optimizedout": "<optimized out>", 2203 "nullreference": "<null reference>", 2204 "emptystructure": "<empty structure>", 2205 "uninitialized": "<uninitialized>", 2206 "invalid": "<invalid>", 2207 "notcallable": "<not callable>", 2208 "outofscope": "<out of scope>" 2209 } 2210 if encoding in special_encodings: 2211 return special_encodings[encoding] 2212 2213 text_encodings = [ 2214 'latin1', 2215 # 'local8bit', 2216 'utf8', 2217 'utf16', 2218 # 'ucs4' 2219 ] 2220 2221 if encoding in text_encodings: 2222 try: 2223 binaryvalue = summaryValue.decode('hex') 2224 # LLDB expects UTF-8 2225 return "\"%s\"" % (binaryvalue.decode(encoding).encode('utf8')) 2226 except: 2227 return "<failed to decode '%s' as '%s'>" % (summaryValue, encoding) 2228 2229 # FIXME: Support these 2230 other_encodings = [ 2231 'int', 2232 'uint', 2233 'float', 2234 'juliandate', 2235 'juliandateandmillisecondssincemidnight', 2236 'millisecondssincemidnight', 2237 'ipv6addressandhexscopeid', 2238 'datetimeinternal'] 2239 2240 summaryValue += " <encoding='%s'>" % encoding 2241 2242 if self.valobj.value: 2243 # If we've resolved a pointer that matches what LLDB natively chose, 2244 # then use that instead of printing the values twice. FIXME, ideally 2245 # we'd have the same pointer format as LLDB uses natively. 2246 if re.sub('^0x0*', '', self.valobj.value) == re.sub('^0x0*', '', summaryValue): 2247 return SummaryProvider.DEFAULT_SUMMARY 2248 2249 return summaryValue.strip() 2250 2251 2252class SyntheticChildrenProvider(SummaryProvider): 2253 def __init__(self, valobj, dict): 2254 SummaryProvider.__init__(self, valobj, expand=True) 2255 self.summary = None 2256 self.synthetic_children = [] 2257 2258 def num_native_children(self): 2259 return self.valobj.GetNumChildren() 2260 2261 def num_children(self): 2262 self.log("native: %d synthetic: %d" % 2263 (self.num_native_children(), len(self.synthetic_children)), True) 2264 return self._num_children() 2265 2266 def _num_children(self): 2267 return self.num_native_children() + len(self.synthetic_children) 2268 2269 def has_children(self): 2270 return self._num_children() > 0 2271 2272 def get_child_index(self, name): 2273 # FIXME: Do we ever need this to return something? 2274 self.log_fn(name) 2275 return None 2276 2277 def get_child_at_index(self, index): 2278 self.log_fn(index) 2279 2280 if index < 0 or index > self._num_children(): 2281 return None 2282 if not self.valobj.IsValid() or not self.summary: 2283 return None 2284 2285 if index < self.num_native_children(): 2286 # Built-in children 2287 value = self.valobj.GetChildAtIndex(index) 2288 else: 2289 # Synthetic children 2290 index -= self.num_native_children() 2291 child = self.synthetic_children[index] 2292 name = child.get('name', "[%s]" % index) 2293 value = self.create_value(child, name) 2294 2295 return value 2296 2297 def create_value(self, child, name=''): 2298 child_type = child.get('type', self.summary.get('childtype')) 2299 2300 value = None 2301 if child_type: 2302 if 'address' in child: 2303 value_type = None 2304 with SummaryDumper.shared(self.valobj) as dumper: 2305 value_type = dumper.lookupNativeType(child_type) 2306 if not value_type or not value_type.IsValid(): 2307 return None 2308 address = int(child['address'], 16) 2309 2310 # Create as void* so that the value is fully initialized before 2311 # we trigger our own summary/child providers recursively. 2312 value = self.valobj.synthetic_child_from_address( 2313 name, address, SummaryProvider.VOID_PTR_TYPE).Cast(value_type) 2314 else: 2315 self.log("Don't know how to create value for child %s" % child) 2316 # FIXME: Figure out if we ever will hit this case, and deal with it 2317 #value = self.valobj.synthetic_child_from_expression(name, 2318 # "(%s)(%s)" % (child_type, child['value'])) 2319 else: 2320 # FIXME: Find a good way to deal with synthetic values 2321 self.log("Don't know how to create value for child %s" % child) 2322 2323 # FIXME: Handle value type or value errors consistently 2324 return value 2325 2326 def update(self): 2327 SummaryProvider.update(self) 2328 2329 self.synthetic_children = [] 2330 if 'children' not in self.summary: 2331 return 2332 2333 dereference_child = None 2334 for child in self.summary['children']: 2335 if not child or not isinstance(child, dict): 2336 continue 2337 2338 # Skip base classes, they are built-in children 2339 # FIXME: Is there a better check than 'iname'? 2340 if 'iname' in child: 2341 continue 2342 2343 name = child.get('name') 2344 if name: 2345 if name == '*': 2346 # No use for this unless the built in children failed to resolve 2347 dereference_child = child 2348 continue 2349 2350 if name.startswith('['): 2351 # Skip pure synthetic children until we can deal with them 2352 continue 2353 2354 if name.startswith('#'): 2355 # Skip anonymous unions, lookupNativeType doesn't handle them (yet), 2356 # so it triggers the slow lookup path, and the union is provided as 2357 # a native child anyways. 2358 continue 2359 2360 # Skip native children 2361 if self.valobj.GetChildMemberWithName(name): 2362 continue 2363 2364 self.synthetic_children.append(child) 2365 2366 # Xcode will sometimes fail to show the children of pointers in 2367 # the debugger UI, even if dereferencing the pointer works fine. 2368 # We fall back to the special child reported by the Qt dumper. 2369 if not self.valobj.GetNumChildren() and dereference_child: 2370 self.valobj = self.create_value(dereference_child) 2371 self.update() 2372 2373 2374def __lldb_init_module(debugger, internal_dict): 2375 # Module is being imported in an LLDB session 2376 dumper = SummaryDumper.initialize() 2377 2378 type_category = 'Qt' 2379 2380 # Concrete types 2381 summary_function = "%s.%s.%s" % (__name__, 'SummaryProvider', 'provide_summary') 2382 types = map(lambda x: x.replace('__', '::'), dumper.qqDumpers) 2383 debugger.HandleCommand("type summary add -F %s -w %s %s" 2384 % (summary_function, type_category, ' '.join(types))) 2385 2386 regex_types = list(map(lambda x: "'" + x + "'", dumper.qqDumpersEx.keys())) 2387 if regex_types: 2388 debugger.HandleCommand("type summary add -x -F %s -w %s %s" 2389 % (summary_function, type_category, ' '.join(regex_types))) 2390 2391 # Global catch-all for Qt classes 2392 debugger.HandleCommand("type summary add -x '^Q.*$' -F %s -w %s" 2393 % (summary_function, type_category)) 2394 2395 # Named summary ('frame variable foo --summary Qt') 2396 debugger.HandleCommand("type summary add --name Qt -F %s -w %s" 2397 % (summary_function, type_category)) 2398 2399 # Synthetic children 2400 debugger.HandleCommand("type synthetic add -x '^Q.*$' -l %s -w %s" 2401 % ("lldbbridge.SyntheticChildrenProvider", type_category)) 2402 2403 debugger.HandleCommand('type category enable %s' % type_category) 2404 2405 if not __name__ == 'qt': 2406 # Make available under global 'qt' name for consistency 2407 internal_dict['qt'] = internal_dict[__name__] 2408 2409 2410if __name__ == "lldbbridge": 2411 try: 2412 theDumper = Dumper() 2413 except Exception as error: 2414 print('@\nstate="enginesetupfailed",error="{}"@\n'.format(error)) 2415