lldbbridge.py 68.3 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
650
651
        self.ignoreStops = 0
        if self.useTerminal_ and platform.system() == "Linux":
            self.ignoreStops = 2
hjk's avatar
hjk committed
652

653
654
        if self.platform_:
            self.debugger.SetCurrentPlatform(self.platform_)
Fawzi Mohamed's avatar
Fawzi Mohamed committed
655
656
657
        # sysroot has to be set *after* the platform
        if self.sysRoot_:
            self.debugger.SetCurrentPlatformSDKRoot(self.sysRoot_)
658
659
660
661
662

        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)
663

664
        if self.target.IsValid():
665
666
            for bp in args['bkpts']:
                self.insertBreakpoint(bp)
667

668
669
        state = "inferiorsetupok" if self.target.IsValid() else "inferiorsetupfailed"
        self.report('state="%s",msg="%s",exe="%s"' % (state, error, self.executable_))
670

671
    def runEngine(self, _):
hjk's avatar
hjk committed
672
        self.prepare()
hjk's avatar
hjk committed
673
674
675
        s = threading.Thread(target=self.loop, args=[])
        s.start()

hjk's avatar
hjk committed
676
    def prepare(self):
677
        error = lldb.SBError()
hjk's avatar
hjk committed
678
679
        listener = self.debugger.GetListener()

680
681
682
        if self.attachPid_ > 0:
            attachInfo = lldb.SBAttachInfo(self.attachPid_)
            self.process = self.target.Attach(attachInfo, error)
683
            if not error.Success():
684
                self.reportState("inferiorrunfailed")
Fawzi Mohamed's avatar
Fawzi Mohamed committed
685
686
                return
            self.report('pid="%s"' % self.process.GetProcessID())
687
688
689
690
            # 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
691
        elif self.startMode_ == AttachToRemoteServer or self.startMode_ == AttachToRemoteProcess:
Fawzi Mohamed's avatar
Fawzi Mohamed committed
692
            self.process = self.target.ConnectRemote(
693
694
                self.debugger.GetListener(),
                self.remoteChannel_, None, error)
695
            if not error.Success():
696
697
                self.reportError(error)
                self.reportState("enginerunfailed")
698
                return
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")
703
        else:
704
            launchInfo = lldb.SBLaunchInfo(self.processArgs_)
705
            launchInfo.SetWorkingDirectory(os.getcwd())
706
707
            environmentList = [key + "=" + value for key,value in os.environ.items()]
            launchInfo.SetEnvironmentEntries(environmentList, False)
708
709
            if self.breakOnMain_:
                self.createBreakpointAtMain()
710
            self.process = self.target.Launch(launchInfo, error)
711
            if not error.Success():
712
                self.reportError(error)
713
                self.reportState("enginerunfailed")
Fawzi Mohamed's avatar
Fawzi Mohamed committed
714
715
                return
            self.report('pid="%s"' % self.process.GetProcessID())
716
            self.reportState("enginerunandinferiorrunok")
717

hjk's avatar
hjk committed
718
    def loop(self):
hjk's avatar
hjk committed
719
        event = lldb.SBEvent()
hjk's avatar
hjk committed
720
        listener = self.debugger.GetListener()
hjk's avatar
hjk committed
721
722
723
724
725
        while True:
            if listener.WaitForEvent(10000000, event):
                self.handleEvent(event)
            else:
                warn('TIMEOUT')
726

727
    def describeError(self, error):
728
729
730
731
732
        desc = lldb.SBStream()
        error.GetDescription(desc)
        result = 'error={type="%s"' % error.GetType()
        result += ',code="%s"' % error.GetError()
        result += ',desc="%s"}' % desc.GetData()
733
734
735
736
        return result

    def reportError(self, error):
        self.report(self.describeError(error))
hjk's avatar
hjk committed
737
738
        if error.GetType():
            self.reportStatus(error.GetCString())
739
740

    def currentThread(self):
741
        return None if self.process is None else self.process.GetSelectedThread()
742
743

    def currentFrame(self):
744
745
        thread = self.currentThread()
        return None if thread is None else thread.GetSelectedFrame()
746
747
748

    def reportLocation(self):
        thread = self.currentThread()
749
        frame = thread.GetSelectedFrame()
750
751
        file = fileName(frame.line_entry.file)
        line = frame.line_entry.line
752
753
        self.report('location={file="%s",line="%s",addr="%s"}'
            % (file, line, frame.pc))
754

755
756
757
    def firstStoppedThread(self):
        for i in xrange(0, self.process.GetNumThreads()):
            thread = self.process.GetThreadAtIndex(i)
758
759
760
761
762
763
            reason = thread.GetStopReason()
            if (reason == lldb.eStopReasonBreakpoint or
                    reason == lldb.eStopReasonException or
                    reason == lldb.eStopReasonPlanComplete or
                    reason == lldb.eStopReasonSignal or
                    reason == lldb.eStopReasonWatchpoint):
764
765
766
                return thread
        return None

767
768
    def reportThreads(self):
        result = 'threads={threads=['
769
        for i in xrange(0, self.process.GetNumThreads()):
770
            thread = self.process.GetThreadAtIndex(i)
hjk's avatar
hjk committed
771
772
773
774
775
776
777
            if thread.is_stopped:
                state = "stopped"
            elif thread.is_suspended:
                state = "suspended"
            else:
                state = "unknown"
            reason = thread.GetStopReason()
778
779
            result += '{id="%d"' % thread.GetThreadID()
            result += ',index="%s"' % i
780
            result += ',details="%s"' % thread.GetQueueName()
hjk's avatar
hjk committed
781
782
            result += ',stop-reason="%s"' % self.stopReason(thread.GetStopReason())
            result += ',state="%s"' % state
783
            result += ',name="%s"' % thread.GetName()
784
785
786
787
788
            result += ',frame={'
            frame = thread.GetFrameAtIndex(0)
            result += 'pc="0x%x"' % frame.pc
            result += ',addr="0x%x"' % frame.pc
            result += ',fp="0x%x"' % frame.fp
789
            result += ',func="%s"' % frame.GetFunctionName()
790
791
792
793
794
795
796
797
            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)

798
    def firstUsableFrame(self, thread):
hjk's avatar
hjk committed
799
        for i in xrange(10):
hjk's avatar
hjk committed
800
801
802
803
804
805
806
            frame = thread.GetFrameAtIndex(i)
            lineEntry = frame.GetLineEntry()
            line = lineEntry.GetLine()
            if line != 0:
                return i
        return None

807
    def reportStack(self, args):
808
        if not self.process:
809
            self.report('msg="No process"')
810
811
812
813
814
            return
        thread = self.currentThread()
        if not thread:
            self.report('msg="No thread"')
            return
815

816
        isNativeMixed = int(args.get('nativeMixed', 0))
817

818
819
        limit = args.get('stacklimit', -1)
        (n, isLimited) = (limit, True) if limit > 0 else (thread.GetNumFrames(), False)
820
        self.currentCallContext = None
821
        result = 'stack={current-thread="%s"' % thread.GetThreadID()
822
823
824
        result += ',frames=['
        for i in xrange(n):
            frame = thread.GetFrameAtIndex(i)
825
826
827
            if not frame.IsValid():
                isLimited = False
                break
828

829
            lineEntry = frame.GetLineEntry()
830
831
832
833
834
835
836
837
838
839
            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

840
            if isNativeMixed:
841
                if self.isReportableQmlFrame(functionName):
842
843
844
845
846
847
848
849
850
                    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'
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868

                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
869
870
871
872
        result += ']'
        result += ',hasmore="%d"' % isLimited
        result += ',limit="%d"' % limit
        result += '}'
873
        self.report(result)
874
875
876
877
878
        self.reportContinuation(args)

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

880
881
882
883
884
885
886
887
888
889
890
891
892
893
    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
894
    def extractBlob(self, base, size):
hjk's avatar
hjk committed
895
        if size == 0:
hjk's avatar
hjk committed
896
            return Blob("")
897
898
        base = int(base) & 0xFFFFFFFFFFFFFFFF
        size = int(size) & 0xFFFFFFFF
hjk's avatar
hjk committed
899
        error = lldb.SBError()
hjk's avatar
hjk committed
900
        return Blob(self.process.ReadMemory(base, size, error))
hjk's avatar
hjk committed
901

902
903
904
905
906
907
908
909
910
911
    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))

912
913
914
915
916
917
918
    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)

919
920
    def findSymbol(self, symbolName):
        return self.target.FindFirstGlobalVariable(symbolName)
hjk's avatar
hjk committed
921

922
    def stripNamespaceFromType(self, typeName):
923
        #type = self.stripClassTag(typeName)
924
        type = typeName
925
926
927
        ns = self.qtNamespace()
        if len(ns) > 0 and type.startswith(ns):
            type = type[len(ns):]
928
929
930
931
932
933
        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
934
935
936
937
        if type.startswith("const "):
            type = type[6:]
        if type.startswith("volatile "):
            type = type[9:]
938
939
940
        return type

    def putSubItem(self, component, value, tryDynamic=True):
941
        if not value.IsValid():
942
            self.warn("INVALID SUBITEM: %s" % value.GetName())
943
            return
944
945
946
        with SubItem(self, component):
            self.putItem(value, tryDynamic)

hjk's avatar
hjk committed
947
    def putAddress(self, addr):
948
949
950
951
        #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
952

hjk's avatar
hjk committed
953
954
955
956
957
    def isFunctionType(self, typeobj):
        if self.isGoodLldb:
            return typeobj.IsFunctionType()
        #warn("TYPE: %s" % typeobj)
        return False
hjk's avatar
hjk committed
958

959
    def putItem(self, value, tryDynamic=True):
960
        typeName = value.GetType().GetUnqualifiedType().GetName()
hjk's avatar
hjk committed
961
962
        if self.isGoodLldb:
            value.SetPreferDynamicValue(tryDynamic)
hjk's avatar
hjk committed
963
        typeClass = value.GetType().GetTypeClass()
964

hjk's avatar
hjk committed
965
        if tryDynamic:
966
            self.putAddress(value.GetLoadAddress())
hjk's avatar
hjk committed
967

968
        # Handle build-in LLDB visualizers if wanted.
969
        if False and self.useLldbDumpers and value.GetTypeSynthetic().IsValid():
970
971
972
973
            # FIXME: print "official" summary?
            summary = value.GetTypeSummary()
            if summary.IsValid():
                warn("DATA: %s" % summary.GetData())
hjk's avatar
hjk committed
974
975
            if self.isGoodLldb:
                value.SetPreferSyntheticValue(False)
976
977
978
979
980
            provider = value.GetTypeSynthetic()
            data = provider.GetData()
            formatter = eval(data)(value, {})
            formatter.update()
            numchild = formatter.num_children()
hjk's avatar
hjk committed
981
            self.put('iname="%s",' % self.currentIName)
hjk's avatar
hjk committed
982
            self.putType(typeName)
hjk's avatar
hjk committed
983
984
            self.put('numchild="%s",' % numchild)
            self.put('addr="0x%x",' % value.GetLoadAddress())
985
            self.putItemCount(numchild)
hjk's avatar
hjk committed
986
987
            if self.currentIName in self.expandedINames:
                with Children(self):
988
989
990
991
992
993
                    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
994
995
        # Typedefs
        if typeClass == lldb.eTypeClassTypedef:
996
            if typeName in self.qqDumpers:
hjk's avatar
hjk committed
997
998
                self.putType(typeName)
                self.context = value
999
                self.qqDumpers[typeName](self, value)
hjk's avatar
hjk committed
1000
                return
hjk's avatar
hjk committed
1001
1002
            realType = value.GetType()
            if hasattr(realType, 'GetCanonicalType'):
1003
                baseType = realType.GetCanonicalType()
1004
1005
1006
1007
1008
                if baseType != realType:
                    baseValue = value.Cast(baseType.unqualified())
                    self.putItem(baseValue)
                    self.putBetterType(realType)
                    return
hjk's avatar
hjk committed
1009

1010
        # Our turf now.
hjk's avatar
hjk committed
1011
1012
        if self.isGoodLldb:
            value.SetPreferSyntheticValue(False)
1013

1014
        # Arrays
hjk's avatar
hjk committed
1015
        if typeClass == lldb.eTypeClassArray:
1016
            self.putCStyleArray(value)
1017
1018
            return

1019
1020
        # Vectors like char __attribute__ ((vector_size (8)))
        if typeClass == lldb.eTypeClassVector:
1021
            self.putCStyleArray(value)