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