lldbbridge.py 69 KB
Newer Older
1
2
############################################################################
#
Eike Ziller's avatar
Eike Ziller committed
3
4
# Copyright (C) 2015 The Qt Company Ltd.
# Contact: http://www.qt.io/licensing
5
6
7
8
9
10
11
#
# This file is part of Qt Creator.
#
# Commercial License Usage
# Licensees holding valid commercial Qt licenses may use this file in
# accordance with the commercial license agreement provided with the
# Software or, alternatively, in accordance with the terms contained in
Eike Ziller's avatar
Eike Ziller committed
12
13
# a written agreement between you and The Qt Company.  For licensing terms and
# conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
# use the contact form at http://www.qt.io/contact-us.
15
16
17
#
# GNU Lesser General Public License Usage
# Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18
19
20
21
22
23
# General Public License version 2.1 or version 3 as published by the Free
# Software Foundation and appearing in the file LICENSE.LGPLv21 and
# LICENSE.LGPLv3 included in the packaging of this file.  Please review the
# following information to ensure the GNU Lesser General Public License
# requirements will be met: https://www.gnu.org/licenses/lgpl.html and
# http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24
#
Eike Ziller's avatar
Eike Ziller committed
25
26
# In addition, as a special exception, The Qt Company gives you certain additional
# rights.  These rights are described in The Qt Company LGPL Exception
27
28
29
# version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
#
#############################################################################
30
31
32

import inspect
import os
33
import platform
34
import re
35
import sys
36
import threading
37
import lldb
38

hjk's avatar
hjk committed
39
sys.path.insert(1, os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))))
40
41
42

from dumper import *

43
44
45
46
47
48
#######################################################################
#
# Helpers
#
#######################################################################

49
qqWatchpointOffset = 10000
50

51
def warn(message):
52
    print('\n\nWARNING="%s",\n' % message.encode("latin1").replace('"', "'"))
53
54
55

def showException(msg, exType, exValue, exTraceback):
    warn("**** CAUGHT EXCEPTION: %s ****" % msg)
56
57
58
    import traceback
    lines = [line for line in traceback.format_exception(exType, exValue, exTraceback)]
    warn('\n'.join(lines))
59
60
61
62

def fileName(file):
    return str(file) if file.IsValid() else ''

63

hjk's avatar
hjk committed
64
65
66
67
def check(exp):
    if not exp:
        raise RuntimeError("Check failed")

68
69
Value = lldb.SBValue

70
71
def impl_SBValue__add__(self, offset):
    if self.GetType().IsPointerType():
72
        if isinstance(offset, int) or isinstance(offset, long):
73
74
75
            pass
        else:
            offset = offset.GetValueAsSigned()
76
        itemsize = self.GetType().GetPointeeType().GetByteSize()
77
        address = self.GetValueAsUnsigned() + offset * itemsize
78
        address = address & 0xFFFFFFFFFFFFFFFF  # Force unsigned
79
80
        return self.CreateValueFromAddress(None, address,
                self.GetType().GetPointeeType()).AddressOf()
hjk's avatar
hjk committed
81

82
    raise RuntimeError("SBValue.__add__ not implemented: %s" % self.GetType())
83
84
    return NotImplemented

85
def impl_SBValue__sub__(self, other):
86
    if self.GetType().IsPointerType():
87
        if isinstance(other, int) or isinstance(other, long):
88
            address = self.GetValueAsUnsigned() - other
89
90
            address = address & 0xFFFFFFFFFFFFFFFF  # Force unsigned
            return self.CreateValueFromAddress(None, address, self.GetType())
91
        if other.GetType().IsPointerType():
92
93
            itemsize = self.GetType().GetPointeeType().GetByteSize()
            return (self.GetValueAsUnsigned() - other.GetValueAsUnsigned()) / itemsize
94
    raise RuntimeError("SBValue.__sub__ not implemented: %s" % self.GetType())
95
96
    return NotImplemented

97
98
99
100
101
102
103
def impl_SBValue__le__(self, other):
    if self.GetType().IsPointerType() and other.GetType().IsPointerType():
        return int(self) <= int(other)
    raise RuntimeError("SBValue.__le__ not implemented")
    return NotImplemented

def impl_SBValue__int__(self):
104
    return self.GetValueAsSigned()
105
106
107
108
109
110
111
112
113
114

def impl_SBValue__float__(self):
    error = lldb.SBError()
    if self.GetType().GetByteSize() == 4:
        result = self.GetData().GetFloat(error, 0)
    else:
        result = self.GetData().GetDouble(error, 0)
    if error.Success():
        return result
    return NotImplemented
115

116
117
118
def impl_SBValue__long__(self):
    return int(self.GetValue(), 0)

119
def impl_SBValue__getitem__(value, index):
120
    if isinstance(index, int) or isinstance(index, long):
121
122
123
124
125
126
127
        type = value.GetType()
        if type.IsPointerType():
            innertype = value.Dereference().GetType()
            address = value.GetValueAsUnsigned() + index * innertype.GetByteSize()
            address = address & 0xFFFFFFFFFFFFFFFF  # Force unsigned
            return value.CreateValueFromAddress(None, address, innertype)
        return value.GetChildAtIndex(index)
128
    return value.GetChildMemberWithName(index)
129

130
131
132
133
def impl_SBValue__deref(value):
    result = value.Dereference()
    if result.IsValid():
        return result
134
135
    exp = "*(class %s*)0x%x" % (value.GetType().GetPointeeType(), value.GetValueAsUnsigned())
    return value.CreateValueFromExpression(None, exp)
136

137
lldb.SBValue.__add__ = impl_SBValue__add__
138
lldb.SBValue.__sub__ = impl_SBValue__sub__
139
lldb.SBValue.__le__ = impl_SBValue__le__
140

141
142
lldb.SBValue.__getitem__ = impl_SBValue__getitem__
lldb.SBValue.__int__ = impl_SBValue__int__
143
lldb.SBValue.__float__ = impl_SBValue__float__
144
145
lldb.SBValue.__long__ = lambda self: long(self.GetValue(), 0)

146
lldb.SBValue.code = lambda self: self.GetTypeClass()
147
lldb.SBValue.cast = lambda self, typeObj: self.Cast(typeObj)
148
lldb.SBValue.dereference = impl_SBValue__deref
149
lldb.SBValue.address = property(lambda self: self.GetLoadAddress())
150
151

lldb.SBType.pointer = lambda self: self.GetPointerType()
hjk's avatar
hjk committed
152
lldb.SBType.target = lambda self: self.GetPointeeType()
153
lldb.SBType.code = lambda self: self.GetTypeClass()
154
lldb.SBType.sizeof = property(lambda self: self.GetByteSize())
155
156


hjk's avatar
hjk committed
157
158
lldb.SBType.unqualified = \
    lambda self: self.GetUnqualifiedType() if hasattr(self, 'GetUnqualifiedType') else self
159
160
lldb.SBType.strip_typedefs = \
    lambda self: self.GetCanonicalType() if hasattr(self, 'GetCanonicalType') else self
161

hjk's avatar
hjk committed
162
163
164
lldb.SBType.__orig__str__ = lldb.SBType.__str__
lldb.SBType.__str__ = lldb.SBType.GetName

165
class Dumper(DumperBase):
166
    def __init__(self):
167
168
        DumperBase.__init__(self)

hjk's avatar
hjk committed
169
        self.outputLock = threading.Lock()
170
        self.debugger = lldb.SBDebugger.Create()
171
        #self.debugger.SetLoggingCallback(loggingCallback)
hjk's avatar
hjk committed
172
173
174
175
        #def loggingCallback(args):
        #    s = args.strip()
        #    s = s.replace('"', "'")
        #    sys.stdout.write('log="%s"@\n' % s)
176
        #Same as: self.debugger.HandleCommand("log enable lldb dyld step")
hjk's avatar
hjk committed
177
178
        #self.debugger.EnableLog("lldb", ["dyld", "step", "process", "state",
        #    "thread", "events",
179
180
181
182
        #    "communication", "unwind", "commands"])
        #self.debugger.EnableLog("lldb", ["all"])
        self.debugger.Initialize()
        self.debugger.HandleCommand("settings set auto-confirm on")
183
184
185
186
187
188
189
190
191
192

        # FIXME: warn("DISABLING DEFAULT FORMATTERS")
        # It doesn't work at all with 179.5 and we have some bad
        # interactonn in 3000
        # if not hasattr(lldb.SBType, 'GetCanonicalType'): # "Test" for 179.5
        self.debugger.HandleCommand('type category delete gnu-libstdc++')
        self.debugger.HandleCommand('type category delete libcxx')
        #for i in range(self.debugger.GetNumCategories()):
        #    self.debugger.GetCategoryAtIndex(i).SetEnabled(False)

193
        self.isLldb = True
hjk's avatar
hjk committed
194
        self.isGoodLldb = hasattr(lldb.SBValue, "SetPreferDynamicValue")
195
196
197
198
        self.process = None
        self.target = None
        self.eventState = lldb.eStateInvalid
        self.expandedINames = {}
199
        self.passExceptions = False
200
        self.useLldbDumpers = False
hjk's avatar
hjk committed
201
        self.autoDerefPointers = True
202
        self.useDynamicType = True
hjk's avatar
hjk committed
203
        self.useFancy = True
hjk's avatar
hjk committed
204
205
        self.formats = {}
        self.typeformats = {}
206
207

        self.currentIName = None
208
209
        self.currentValue = ReportItem()
        self.currentType = ReportItem()
210
211
212
213
214
        self.currentNumChild = None
        self.currentMaxNumChild = None
        self.currentPrintsAddress = None
        self.currentChildType = None
        self.currentChildNumChild = None
215
        self.currentWatchers = {}
216

hjk's avatar
hjk committed
217
        self.executable_ = None
218
219
220
221
        self.startMode_ = None
        self.processArgs_ = None
        self.attachPid_ = None

222
223
        self.charType_ = None
        self.intType_ = None
224
        self.int64Type_ = None
225
226
        self.sizetType_ = None
        self.charPtrType_ = None
hjk's avatar
hjk committed
227
        self.voidPtrType_ = None
228
        self.isShuttingDown_ = False
229
        self.isInterrupting_ = False
230
        self.dummyValue = None
231
232
        self.qmlBreakpointResolvers = {}
        self.qmlTriggeredBreakpoint = None
233

hjk's avatar
hjk committed
234
235
236
        self.report('lldbversion=\"%s\"' % lldb.SBDebugger.GetVersionString())
        self.reportState("enginesetupok")

237
238
239
240
    def enterSubItem(self, item):
        if isinstance(item.name, lldb.SBValue):
            # Avoid $$__synth__ suffix on Mac.
            value = item.name
hjk's avatar
hjk committed
241
242
            if self.isGoodLldb:
                value.SetPreferSyntheticValue(False)
243
244
245
246
            item.name = value.GetName()
            if item.name is None:
                self.anonNumber += 1
                item.name = "#%d" % self.anonNumber
247
248
        if not item.iname:
            item.iname = "%s.%s" % (self.currentIName, item.name)
249
250
251
252
253
254
255
256
257
258
        self.put('{')
        #if not item.name is None:
        if isinstance(item.name, str):
            if item.name == '**&':
                item.name = '*'
            self.put('name="%s",' % item.name)
        item.savedIName = self.currentIName
        item.savedValue = self.currentValue
        item.savedType = self.currentType
        self.currentIName = item.iname
259
260
        self.currentValue = ReportItem()
        self.currentType = ReportItem()
261
262
263
264
265
266
267
268

    def exitSubItem(self, item, exType, exValue, exTraceBack):
        if not exType is None:
            if self.passExceptions:
                showException("SUBITEM", exType, exValue, exTraceBack)
            self.putNumChild(0)
            self.putValue("<not accessible>")
        try:
hjk's avatar
hjk committed
269
270
271
272
            if self.currentType.value:
                typeName = self.currentType.value
                if len(typeName) > 0 and typeName != self.currentChildType:
                    self.put('type="%s",' % typeName) # str(type.unqualified()) ?
273
            if  self.currentValue.value is None:
274
275
                self.put('value="<not accessible>",numchild="0",')
            else:
276
277
278
279
280
                if not self.currentValue.encoding is None:
                    self.put('valueencoded="%s",' % self.currentValue.encoding)
                if self.currentValue.elided:
                    self.put('valueelided="%s",' % self.currentValue.elided)
                self.put('value="%s",' % self.currentValue.value)
281
282
283
284
285
286
287
288
        except:
            pass
        self.put('},')
        self.currentIName = item.savedIName
        self.currentValue = item.savedValue
        self.currentType = item.savedType
        return True

hjk's avatar
hjk committed
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
    def stateName(self, s):
        try:
            # See db.StateType
            return (
                'invalid',
                'unloaded',  # Process is object is valid, but not currently loaded
                'connected', # Process is connected to remote debug services,
                             #  but not launched or attached to anything yet
                'attaching', # Process is currently trying to attach
                'launching', # Process is in the process of launching
                'stopped',   # Process or thread is stopped and can be examined.
                'running',   # Process or thread is running and can't be examined.
                'stepping',  # Process or thread is in the process of stepping
                             #  and can not be examined.
                'crashed',   # Process or thread has crashed and can be examined.
                'detached',  # Process has been detached and can't be examined.
                'exited',    # Process has exited and can't be examined.
                'suspended'  # Process or thread is in a suspended state as far
                )[s]
        except:
            return 'unknown(%s)' % s

    def stopReason(self, s):
        try:
            return (
                'invalid',
                'none',
                'trace',
                'breakpoint',
                'watchpoint',
                'signal',
                'exception',
                'exec',
                'plancomplete',
                'threadexiting',
                'instrumentation',
                )[s]
        except:
            return 'unknown(%s)' % s

329
330
331
332
    def isSimpleType(self, typeobj):
        typeClass = typeobj.GetTypeClass()
        return typeClass == lldb.eTypeClassBuiltin

hjk's avatar
hjk committed
333
334
335
    def childWithName(self, value, name):
        child = value.GetChildMemberWithName(name)
        return child if child.IsValid() else None
336

337
338
339
    def simpleValue(self, value):
        return str(value.value)

340
341
342
343
344
345
346
347
348
    def childAt(self, value, index):
        return value.GetChildAtIndex(index)

    def fieldAt(self, type, index):
        return type.GetFieldAtIndex(index)

    def pointerValue(self, value):
        return value.GetValueAsUnsigned()

349
350
351
352
353
    def enumExpression(self, enumType, enumValue):
        ns = self.qtNamespace()
        return ns + "Qt::" + enumType + "(" \
            + ns + "Qt::" + enumType + "::" + enumValue + ")"

354
    def callHelper(self, value, func, args):
355
356
        # args is a tuple.
        arg = ','.join(args)
357
        #self.warn("CALL: %s -> %s(%s)" % (value, func, arg))
358
359
        type = value.type.name
        exp = "((%s*)%s)->%s(%s)" % (type, value.address, func, arg)
360
        #self.warn("CALL: %s" % exp)
361
        result = value.CreateValueFromExpression('', exp)
362
        #self.warn("  -> %s" % result)
363
364
        return result

365
366
367
368
369
    def makeValue(self, type, *args):
        thread = self.currentThread()
        frame = thread.GetFrameAtIndex(0)
        inner = ','.join(args)
        value = frame.EvaluateExpression(type + '{' + inner + '}')
370
371
372
        #self.warn("  TYPE: %s" % value.type)
        #self.warn("  ADDR: 0x%x" % value.address)
        #self.warn("  VALUE: %s" % value)
373
374
        return value

375
376
377
378
379
    def parseAndEvaluate(self, expr):
        thread = self.currentThread()
        frame = thread.GetFrameAtIndex(0)
        return frame.EvaluateExpression(expr)

380
381
382
383
384
385
386
387
    def checkPointer(self, p, align = 1):
        if not self.isNull(p):
            p.Dereference()

    def isNull(self, p):
        return p.GetValueAsUnsigned() == 0

    def directBaseClass(self, typeobj, index = 0):
388
        result = typeobj.GetDirectBaseClassAtIndex(index).GetType()
389
        return result if result.IsValid() else None
390

391
    def templateArgument(self, typeobj, index):
392
        type = typeobj.GetTemplateArgumentType(index)
hjk's avatar
hjk committed
393
        if type.IsValid():
394
395
396
397
398
            return type
        inner = self.extractTemplateArgument(typeobj.GetName(), index)
        return self.lookupType(inner)

    def numericTemplateArgument(self, typeobj, index):
399
        # There seems no API to extract the numeric value.
400
        inner = self.extractTemplateArgument(typeobj.GetName(), index)
401
402
403
404
405
406
407
408
        innerType = typeobj.GetTemplateArgumentType(index)
        basicType = innerType.GetBasicType()
        value = toInteger(inner)
        # Clang writes 'int' and '0xfffffff' into the debug info
        # LLDB manages to read a value of 0xfffffff...
        if basicType == lldb.eBasicTypeInt and value >= 0x8000000:
            value -= 0x100000000
        return value
409

hjk's avatar
hjk committed
410
411
412
413
414
415
    def isReferenceType(self, typeobj):
        return typeobj.IsReferenceType()

    def isStructType(self, typeobj):
        return typeobj.GetTypeClass() in (lldb.eTypeClassStruct, lldb.eTypeClassClass)

416
417
418
419
420
421
422
423
424
    def isWindowsTarget(self):
        return False

    def isQnxTarget(self):
        return False

    def isArmArchitecture(self):
        return False

425
    def qtVersionAndNamespace(self):
426
427
        for func in self.target.FindFunctions('qVersion'):
            name = func.GetSymbol().GetName()
428
429
            if name.endswith('()'):
                name = name[:-2]
430
431
432
            if name.count(':') > 2:
                continue

433
434
435
            qtNamespace = name[:name.find('qVersion')]
            self.qtNamespace = lambda: qtNamespace

436
437
438
439
440
441
442
443
444
445
            options = lldb.SBExpressionOptions()
            res = self.target.EvaluateExpression(name + '()', options)

            if not res.IsValid() or not res.GetType().IsPointerType():
                exp = '((const char*())%s)()' % name
                res = self.target.EvaluateExpression(exp, options)

            if not res.IsValid() or not res.GetType().IsPointerType():
                exp = '((const char*())_Z8qVersionv)()'
                res = self.target.EvaluateExpression(exp, options)
446

447
448
449
450
            if not res.IsValid() or not res.GetType().IsPointerType():
                continue

            version = str(res)
451
452
453
            if version.count('.') != 2:
                continue

454
455
            version.replace("'", '"') # Both seem possible
            version = version[version.find('"')+1:version.rfind('"')]
456
457
458
459
460
461
462
463

            (major, minor, patch) = version.split('.')
            qtVersion = 0x10000 * int(major) + 0x100 * int(minor) + int(patch)
            self.qtVersion = lambda: qtVersion

            return (qtNamespace, qtVersion)

        return ('', 0x50200)
464
465

    def qtNamespace(self):
466
        return self.qtVersionAndNamespace()[0]
467
468

    def qtVersion(self):
469
        self.qtVersionAndNamespace()
470
        return self.qtVersionAndNamespace()[1]
471

hjk's avatar
hjk committed
472
473
474
    def intSize(self):
        return 4

475
476
    def intType(self):
        if self.intType_ is None:
hjk's avatar
hjk committed
477
             self.intType_ = self.target.FindFirstType('int')
478
479
        return self.intType_

480
481
482
483
484
    def int64Type(self):
        if self.int64Type_ is None:
             self.int64Type_ = self.target.FindFirstType('long long int')
        return self.int64Type_

485
486
    def charType(self):
        if self.charType_ is None:
hjk's avatar
hjk committed
487
             self.charType_ = self.target.FindFirstType('char')
488
489
490
491
492
493
494
495
        return self.charType_

    def charPtrType(self):
        if self.charPtrType_ is None:
             self.charPtrType_ = self.charType().GetPointerType()
        return self.charPtrType_

    def voidPtrType(self):
hjk's avatar
hjk committed
496
497
498
        if self.voidPtrType_ is None:
             self.voidPtrType_ = self.target.FindFirstType('void').GetPointerType()
        return self.voidPtrType_
499

hjk's avatar
hjk committed
500
    def ptrSize(self):
501
502
503
504
505
506
507
        return self.charPtrType().GetByteSize()

    def sizetType(self):
        if self.sizetType_ is None:
             self.sizetType_ = self.lookupType('size_t')
        return self.sizetType_

508
509
510
    def addressOf(self, value):
        return int(value.GetLoadAddress())

hjk's avatar
hjk committed
511
512
513
    def extractInt(self, address):
        return int(self.createValue(address, self.intType()))

514
515
516
    def extractInt64(self, address):
        return int(self.createValue(address, self.int64Type()))

517
518
519
    def extractByte(self, address):
        return int(self.createValue(address, self.charType())) & 0xFF

520
521
522
523
524
525
    def handleCommand(self, command):
        result = lldb.SBCommandReturnObject()
        self.debugger.GetCommandInterpreter().HandleCommand(command, result)
        success = result.Succeeded()
        if success:
            self.report('output="%s"' % result.GetOutput())
526
        else:
527
528
529
530
531
532
            self.report('error="%s"' % result.GetError())
        self.reportData()

    def put(self, stuff):
        sys.stdout.write(stuff)

533
    def isMovableType(self, type):
534
        if type.GetTypeClass() in (lldb.eTypeClassBuiltin, lldb.eTypeClassPointer):
535
            return True
536
        return self.isKnownMovableType(self.stripNamespaceFromType(type.GetName()))
537

538
    def putNumChild(self, numchild):
539
        #self.warn("NUM CHILD: '%s' '%s'" % (numchild, self.currentChildNumChild))
hjk's avatar
hjk committed
540
541
        #if numchild != self.currentChildNumChild:
        self.put('numchild="%s",' % numchild)
542

543
544
545
546
547
548
549
    def putPointerValue(self, value):
        # Use a lower priority
        if value is None:
            self.putEmptyValue(-1)
        else:
            self.putValue("0x%x" % value.Dereference())

hjk's avatar
hjk committed
550
551
552
    def putSimpleValue(self, value, encoding = None, priority = 0):
        self.putValue(value.GetValue(), encoding, priority)

553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
    def simpleEncoding(self, typeobj):
        code = typeobj.GetTypeClass()
        size = typeobj.sizeof
        if code == lldb.eTypeClassBuiltin:
            name = str(typeobj)
            if name == "float":
                return Hex2EncodedFloat4
            if name == "double":
                return Hex2EncodedFloat8
            if name.find("unsigned") >= 0:
                if size == 1:
                    return Hex2EncodedUInt1
                if size == 2:
                    return Hex2EncodedUInt2
                if size == 4:
                    return Hex2EncodedUInt4
                if size == 8:
                    return Hex2EncodedUInt8
            else:
                if size == 1:
                    return Hex2EncodedInt1
                if size == 2:
                    return Hex2EncodedInt2
                if size == 4:
                    return Hex2EncodedInt4
                if size == 8:
                    return Hex2EncodedInt8
        return None
581

582
583
584
585
586
587
588
589
    def createPointerValue(self, address, pointeeType):
        addr = int(address) & 0xFFFFFFFFFFFFFFFF
        return self.context.CreateValueFromAddress(None, addr, pointeeType).AddressOf()

    def createValue(self, address, referencedType):
        addr = int(address) & 0xFFFFFFFFFFFFFFFF
        return self.context.CreateValueFromAddress(None, addr, referencedType)

590
591
592
593
594
    def childRange(self):
        if self.currentMaxNumChild is None:
            return xrange(0, self.currentNumChild)
        return xrange(min(self.currentMaxNumChild, self.currentNumChild))

595
596
597
    def canonicalTypeName(self, name):
        return re.sub('\\bconst\\b', '', name).replace(' ', '')

598
    def lookupType(self, name):
599
        #self.warn("LOOKUP TYPE NAME: %s" % name)
600
601
602
        typeobj = self.target.FindFirstType(name)
        if typeobj.IsValid():
            return typeobj
hjk's avatar
hjk committed
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
        typeobj = self.target.FindFirstType(name + '*')
        if typeobj.IsValid():
            return typeob.GetPointeeType()
        typeobj = self.target.FindFirstType(name + '&')
        if typeobj.IsValid():
            return typeob.GetReferencedType()
        if name.endswith('*'):
            typeobj = self.target.FindFirstType(name[:-1].strip())
            if typeobj.IsValid():
                return typeobj.GetPointerType()
        #self.warn("LOOKUP RESULT: %s" % typeobj.name)
        #self.warn("LOOKUP VALID: %s" % typeobj.IsValid())
        needle = self.canonicalTypeName(name)
        #self.warn("NEEDLE: %s " % needle)
        for i in xrange(self.target.GetNumModules()):
            module = self.target.GetModuleAtIndex(i)
            # SBModule.GetType is new somewhere after early 300.x
            # So this may fail.
            for t in module.GetTypes():
                n = self.canonicalTypeName(t.GetName())
                if n == needle:
                    #self.warn("FOUND TYPE DIRECT 2: %s " % t)
                    return t
                if n == needle + '*':
                    #self.warn("FOUND TYPE BY POINTER 2: %s " % t.GetPointeeType())
                    return t.GetPointeeType()
                if n == needle + '&':
                    #self.warn("FOUND TYPE BY REFERENCE 2: %s " % t)
                    return t.GetDereferencedType()
        #self.warn("NOT FOUND: %s " % needle)
633
        return None
634

635
    def setupInferior(self, args):
636
        error = lldb.SBError()
637
638

        self.executable_ = args['executable']
639
        self.startMode_ = args.get('startMode', 1)
640
        self.breakOnMain_ = args.get('breakOnMain', 0)
hjk's avatar
hjk committed
641
        self.useTerminal_ = args.get('useTerminal', 0)
642
643
        self.processArgs_ = args.get('processArgs', [])
        self.processArgs_ = map(lambda x: self.hexdecode(x), self.processArgs_)
644
        self.attachPid_ = args.get('attachPid', 0)
Fawzi Mohamed's avatar
Fawzi Mohamed committed
645
        self.sysRoot_ = args.get('sysRoot', '')
Fawzi Mohamed's avatar
Fawzi Mohamed committed
646
        self.remoteChannel_ = args.get('remoteChannel', '')
647
        self.platform_ = args.get('platform', '')
648

hjk's avatar
hjk committed
649
        self.ignoreStops = 0
650
651
652
653
654
655
656
657
658
        self.silentStops = 0
        if platform.system() == "Linux":
            if self.startMode_ == AttachCore:
                pass
            else:
                if self.useTerminal_:
                    self.ignoreStops = 2
                else:
                    self.silentStops = 1
hjk's avatar
hjk committed
659

660
661
662
663
        else:
            if self.useTerminal_:
                self.ignoreStops = 1

664
665
        if self.platform_:
            self.debugger.SetCurrentPlatform(self.platform_)
Fawzi Mohamed's avatar
Fawzi Mohamed committed
666
667
668
        # sysroot has to be set *after* the platform
        if self.sysRoot_:
            self.debugger.SetCurrentPlatformSDKRoot(self.sysRoot_)
669

670

671
672
673
674
        if os.path.isfile(self.executable_):
            self.target = self.debugger.CreateTarget(self.executable_, None, None, True, error)
        else:
            self.target = self.debugger.CreateTarget(None, None, None, True, error)
675

676
        if self.target.IsValid():
677
678
            for bp in args['bkpts']:
                self.insertBreakpoint(bp)
679

680
681
        state = "inferiorsetupok" if self.target.IsValid() else "inferiorsetupfailed"
        self.report('state="%s",msg="%s",exe="%s"' % (state, error, self.executable_))
682

683
684
    def runEngine(self, args):
        self.prepare(args)
hjk's avatar
hjk committed
685
686
687
        s = threading.Thread(target=self.loop, args=[])
        s.start()

688
    def prepare(self, args):
689
        error = lldb.SBError()
hjk's avatar
hjk committed
690
691
        listener = self.debugger.GetListener()

692
693
694
        if self.attachPid_ > 0:
            attachInfo = lldb.SBAttachInfo(self.attachPid_)
            self.process = self.target.Attach(attachInfo, error)
695
            if not error.Success():
696
                self.reportState("inferiorrunfailed")
Fawzi Mohamed's avatar
Fawzi Mohamed committed
697
698
                return
            self.report('pid="%s"' % self.process.GetProcessID())
699
700
701
702
            # Even if it stops it seems that LLDB assumes it is running
            # and later detects that it did stop after all, so it is be
            # better to mirror that and wait for the spontaneous stop.
            self.reportState("enginerunandinferiorrunok")
hjk's avatar
hjk committed
703
        elif self.startMode_ == AttachToRemoteServer or self.startMode_ == AttachToRemoteProcess:
Fawzi Mohamed's avatar
Fawzi Mohamed committed
704
            self.process = self.target.ConnectRemote(
705
706
                self.debugger.GetListener(),
                self.remoteChannel_, None, error)
707
            if not error.Success():
708
709
                self.reportError(error)
                self.reportState("enginerunfailed")
710
                return
711
712
713
714
            # Even if it stops it seems that LLDB assumes it is running
            # and later detects that it did stop after all, so it is be
            # better to mirror that and wait for the spontaneous stop.
            self.reportState("enginerunandinferiorrunok")
715
716
717
718
719
        elif self.startMode_ == AttachCore:
            coreFile = args.get('coreFile', '');
            self.process = self.target.LoadCore(coreFile)
            self.reportState("enginerunokandinferiorunrunnable")
            #self.reportContinuation(args)
720
        else:
721
            launchInfo = lldb.SBLaunchInfo(self.processArgs_)
722
            launchInfo.SetWorkingDirectory(os.getcwd())
723
724
            environmentList = [key + "=" + value for key,value in os.environ.items()]
            launchInfo.SetEnvironmentEntries(environmentList, False)
725
726
            if self.breakOnMain_:
                self.createBreakpointAtMain()
727
            self.process = self.target.Launch(launchInfo, error)
728
            if not error.Success():
729
                self.reportError(error)
730
                self.reportState("enginerunfailed")
Fawzi Mohamed's avatar
Fawzi Mohamed committed
731
732
                return
            self.report('pid="%s"' % self.process.GetProcessID())
733
            self.reportState("enginerunandinferiorrunok")
734

hjk's avatar
hjk committed
735
    def loop(self):
hjk's avatar
hjk committed
736
        event = lldb.SBEvent()
hjk's avatar
hjk committed
737
        listener = self.debugger.GetListener()
hjk's avatar
hjk committed
738
739
740
741
742
        while True:
            if listener.WaitForEvent(10000000, event):
                self.handleEvent(event)
            else:
                warn('TIMEOUT')
743

744
    def describeError(self, error):
745
746
747
748
749
        desc = lldb.SBStream()
        error.GetDescription(desc)
        result = 'error={type="%s"' % error.GetType()
        result += ',code="%s"' % error.GetError()
        result += ',desc="%s"}' % desc.GetData()
750
751
752
753
        return result

    def reportError(self, error):
        self.report(self.describeError(error))
hjk's avatar
hjk committed
754
755
        if error.GetType():
            self.reportStatus(error.GetCString())
756
757

    def currentThread(self):
758
        return None if self.process is None else self.process.GetSelectedThread()
759
760

    def currentFrame(self):
761
762
        thread = self.currentThread()
        return None if thread is None else thread.GetSelectedFrame()
763

764
    def reportLocation(self, frame):
765
766
767
768
769
        if int(frame.pc) != 0xffffffffffffffff:
            file = fileName(frame.line_entry.file)
            line = frame.line_entry.line
            self.report('location={file="%s",line="%s",addr="%s"}'
                % (file, line, frame.pc))
770

771
772
773
    def firstStoppedThread(self):
        for i in xrange(0, self.process.GetNumThreads()):
            thread = self.process.GetThreadAtIndex(i)
774
775
776
777
778
779
            reason = thread.GetStopReason()
            if (reason == lldb.eStopReasonBreakpoint or
                    reason == lldb.eStopReasonException or
                    reason == lldb.eStopReasonPlanComplete or
                    reason == lldb.eStopReasonSignal or
                    reason == lldb.eStopReasonWatchpoint):
780
781
782
                return thread
        return None

783
784
    def reportThreads(self):
        result = 'threads={threads=['
785
        for i in xrange(0, self.process.GetNumThreads()):
786
            thread = self.process.GetThreadAtIndex(i)
hjk's avatar
hjk committed
787
788
789
790
791
792
793
            if thread.is_stopped:
                state = "stopped"
            elif thread.is_suspended:
                state = "suspended"
            else:
                state = "unknown"
            reason = thread.GetStopReason()
794
795
            result += '{id="%d"' % thread.GetThreadID()
            result += ',index="%s"' % i
796
            result += ',details="%s"' % thread.GetQueueName()
hjk's avatar
hjk committed
797
798
            result += ',stop-reason="%s"' % self.stopReason(thread.GetStopReason())
            result += ',state="%s"' % state
799
            result += ',name="%s"' % thread.GetName()
800
801
802
803
804
            result += ',frame={'
            frame = thread.GetFrameAtIndex(0)
            result += 'pc="0x%x"' % frame.pc
            result += ',addr="0x%x"' % frame.pc
            result += ',fp="0x%x"' % frame.fp
805
            result += ',func="%s"' % frame.GetFunctionName()
806
807
808
809
810
811
812
813
            result += ',line="%s"' % frame.line_entry.line
            result += ',fullname="%s"' % fileName(frame.line_entry.file)
            result += ',file="%s"' % fileName(frame.line_entry.file)
            result += '}},'

        result += '],current-thread-id="%s"},' % self.currentThread().id
        self.report(result)

814
    def firstUsableFrame(self, thread):
hjk's avatar
hjk committed
815
        for i in xrange(10):
hjk's avatar
hjk committed
816
817
818
819
820
821
822
            frame = thread.GetFrameAtIndex(i)
            lineEntry = frame.GetLineEntry()
            line = lineEntry.GetLine()
            if line != 0:
                return i
        return None

823
    def reportStack(self, args):
824
        if not self.process:
825
            self.report('msg="No process"')
826
827
828
829
830
            return
        thread = self.currentThread()
        if not thread:
            self.report('msg="No thread"')
            return
831

832
        isNativeMixed = int(args.get('nativeMixed', 0))
833

834
835
        limit = args.get('stacklimit', -1)
        (n, isLimited) = (limit, True) if limit > 0 else (thread.GetNumFrames(), False)
836
        self.currentCallContext = None
837
        result = 'stack={current-thread="%s"' % thread.GetThreadID()
838
839
840
        result += ',frames=['
        for i in xrange(n):
            frame = thread.GetFrameAtIndex(i)
841
842
843
            if not frame.IsValid():
                isLimited = False
                break
844

845
            lineEntry = frame.GetLineEntry()
846
847
848
849
850
851
852
853
854
855
            lineNumber = lineEntry.GetLine()

            pc = frame.GetPC()
            level = frame.idx
            addr = frame.GetPCAddress().GetLoadAddress(self.target)
            functionName = frame.GetFunctionName()
            fullname = fileName(lineEntry.file)
            usable = None
            language = None

856
            if isNativeMixed:
857
                if self.isReportableQmlFrame(functionName):
858
859
860
861
862
863
864
865
866
                    engine = frame.FindVariable("engine")
                    self.context = engine
                    h = self.extractQmlLocation(engine)
                    pc = 0
                    functionName = h['functionName']
                    fullname = h['fileName']
                    lineNumber = h['lineNumber']
                    addr = h['context']
                    language = 'js'
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884

                elif not functionName is None:
                    if functionName.startswith("qt_v4"):
                        usable = 0
                    elif functionName.find("QV4::") >= 0:
                        usable = 0

            result += '{pc="0x%x"' % pc
            result += ',level="%d"' % level
            result += ',addr="0x%x"' % addr
            if not usable is None:
                result += ',usable="%s"' % usable
            result += ',func="%s"' % functionName
            result += ',line="%d"' % lineNumber
            if not language is None:
                result += ',language="%s"' % language
            result += ',fullname="%s"' % fullname
            result += ',file="%s"},' % fullname
885
886
887
888
        result += ']'
        result += ',hasmore="%d"' % isLimited
        result += ',limit="%d"' % limit
        result += '}'
889
        self.report(result)
890
891
892
893
894
        self.reportContinuation(args)

    def reportContinuation(self, args):
        if "continuation" in args:
            self.report('continuation=\"%s\"' % args["continuation"])
895

896
897
898
899
900
901
902
903
904
905
906
907
908
909
    def reportStackPosition(self):
        thread = self.currentThread()
        if not thread:
            self.report('msg="No thread"')
            return
        frame = thread.GetSelectedFrame()
        if frame:
            self.report('stack-position={id="%s"}' % frame.GetFrameID())
        else:
            self.report('stack-position={id="-1"}')

    def reportStackTop(self):
        self.report('stack-top={}')

hjk's avatar
hjk committed
910
    def extractBlob(self, base, size):
hjk's avatar
hjk committed
911
        if size == 0:
hjk's avatar
hjk committed
912
            return Blob("")
913
914
        base = int(base) & 0xFFFFFFFFFFFFFFFF
        size = int(size) & 0xFFFFFFFF
hjk's avatar
hjk committed
915
        error = lldb.SBError()
hjk's avatar
hjk committed
916
        return Blob(self.process.ReadMemory(base, size, error))
hjk's avatar
hjk committed
917

918
919
920
921
922
923
924
925
926
927
    def toBlob(self, value):
        data = value.GetData()
        size = int(data.GetByteSize())
        buf = bytearray(struct.pack('x' * size))
        error = lldb.SBError()
        #data.ReadRawData(error, 0, buf)
        for i in range(size):
            buf[i] = data.GetUnsignedInt8(error, i)
        return Blob(bytes(buf))

928
929
930
931
932
933
934
    def mangleName(self, typeName):
        return '_ZN%sE' % ''.join(map(lambda x: "%d%s" % (len(x), x), typeName.split('::')))

    def findStaticMetaObject(self, typeName):
        symbolName = self.mangleName(typeName + '::staticMetaObject')
        return self.target.FindFirstGlobalVariable(symbolName)

935
936
    def findSymbol(self, symbolName):
        return self.target.FindFirstGlobalVariable(symbolName)
hjk's avatar
hjk committed
937

938
    def stripNamespaceFromType(self, typeName):
939
        #type = self.stripClassTag(typeName)
940
        type = typeName
941
942
943
        ns = self.qtNamespace()
        if len(ns) > 0 and type.startswith(ns):
            type = type[len(ns):]
944
945
946
947
948
949
        pos = type.find("<")
        # FIXME: make it recognize  foo<A>::bar<B>::iterator?
        while pos != -1:
            pos1 = type.rfind(">", pos)
            type = type[0:pos] + type[pos1+1:]
            pos = type.find("<")
hjk's avatar
hjk committed
950
951
952
953
        if type.startswith("const "):
            type = type[6:]
        if type.startswith("volatile "):
            type = type[9:]
954
955
956
        return type

    def putSubItem(self, component, value, tryDynamic=True):
957
        if not value.IsValid():
958
            self.warn("INVALID SUBITEM: %s" % value.GetName())
959
            return
960
961
962
        with SubItem(self, component):
            self.putItem(value, tryDynamic)

hjk's avatar
hjk committed
963
    def putAddress(self, addr):
964
965
966
967
        #if int(addr) == 0xffffffffffffffff:
        #    raise RuntimeError("Illegal address")
        if self.currentPrintsAddress and not addr is None:
            self.put('addr="0x%x",' % int(addr))
hjk's avatar
hjk committed
968

hjk's avatar
hjk committed
969
970
971
972
973
    def isFunctionType(self, typeobj):
        if self.isGoodLldb:
            return typeobj.IsFunctionType()
        #warn("TYPE: %s" % typeobj)
        return False
hjk's avatar
hjk committed
974

975
    def putItem(self, value, tryDynamic=True):
976
        typeName = value.GetType().GetUnqualifiedType().GetName()
hjk's avatar
hjk committed
977
978
        if self.isGoodLldb:
            value.SetPreferDynamicValue(tryDynamic)
hjk's avatar
hjk committed
979
        typeClass = value.GetType().GetTypeClass()
980

hjk's avatar
hjk committed
981
        if tryDynamic:
982
            self.putAddress(value.GetLoadAddress())
hjk's avatar
hjk committed
983

984
        # Handle build-in LLDB visualizers if wanted.
985
        if False and self.useLldbDumpers and value.GetTypeSynthetic().IsValid():
986
987
988
989
            # FIXME: print "official" summary?
            summary = value.GetTypeSummary()
            if summary.IsValid():
                warn("DATA: %s" % summary.GetData())
hjk's avatar
hjk committed
990
991
            if self.isGoodLldb:
                value.SetPreferSyntheticValue(False)
992
993
994
995
996
            provider = value.GetTypeSynthetic()
            data = provider.GetData()
            formatter = eval(data)(value, {})
            formatter.update()
            numchild = formatter.num_children()
hjk's avatar
hjk committed
997
            self.put('iname="%s",' % self.currentIName)
hjk's avatar
hjk committed
998
            self.putType(typeName)
hjk's avatar
hjk committed
999
1000
            self.put('numchild="%s",' % numchild)
            self.put('addr="0x%x",' % value.GetLoadAddress())
1001
            self.putItemCount(numchild)
hjk's avatar
hjk committed
1002
1003
            if self.currentIName in self.expandedINames:
                with Children(self):
1004
1005
1006
1007
1008
1009
                    for i in xrange(numchild):
                        child = formatter.get_child_at_index(i)
                        with SubItem(self, i):
                            self.putItem(child)
            return

hjk's avatar
hjk committed
1010
1011
        # Typedefs
        if typeClass == lldb.eTypeClassTypedef:
1012
            if typeName in self.qqDumpers:
hjk's avatar
hjk committed
1013
1014
                self.putType(typeName)
                self.context = value
1015
                self.qqDumpers[typeName](self, value)
hjk's avatar
hjk committed
1016
                return
hjk's avatar
hjk committed
1017
1018
            realType = value.GetType()
            if hasattr(realType, 'GetCanonicalType'):
1019
                baseType = realType.GetCanonicalType()
1020
1021
1022
1023
1024
                if baseType != realType:
                    baseValue = value.Cast(baseType.unqualified())
                    self.putItem(baseValue)
                    self.putBetterType(realType)
                    return
hjk's avatar
hjk committed
1025

1026
        # Our turf now.
hjk's avatar
hjk committed
1027
1028
        if self.isGoodLldb:
            value.SetPreferSyntheticValue(False)
1029

1030
        # Arrays
hjk's avatar