lldbbridge.py 68.9 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
        self.reportToken(args)
637
        error = lldb.SBError()
638
639

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

hjk's avatar
hjk committed
650
        self.ignoreStops = 0
651
652
653
654
655
656
657
658
659
        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
660

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

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

671

672
673
674
675
        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)
676

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

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

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

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

694
695
696
        if self.attachPid_ > 0:
            attachInfo = lldb.SBAttachInfo(self.attachPid_)
            self.process = self.target.Attach(attachInfo, error)
697
            if not error.Success():
698
                self.reportState("inferiorrunfailed")
Fawzi Mohamed's avatar
Fawzi Mohamed committed
699
700
                return
            self.report('pid="%s"' % self.process.GetProcessID())
701
702
703
704
            # 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
705
        elif self.startMode_ == AttachToRemoteServer or self.startMode_ == AttachToRemoteProcess:
Fawzi Mohamed's avatar
Fawzi Mohamed committed
706
            self.process = self.target.ConnectRemote(
707
708
                self.debugger.GetListener(),
                self.remoteChannel_, None, error)
709
            if not error.Success():
710
711
                self.reportError(error)
                self.reportState("enginerunfailed")
712
                return
713
714
715
716
            # 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")
717
718
719
720
721
        elif self.startMode_ == AttachCore:
            coreFile = args.get('coreFile', '');
            self.process = self.target.LoadCore(coreFile)
            self.reportState("enginerunokandinferiorunrunnable")
            #self.reportContinuation(args)
722
        else:
723
            launchInfo = lldb.SBLaunchInfo(self.processArgs_)
724
            launchInfo.SetWorkingDirectory(os.getcwd())
725
726
            environmentList = [key + "=" + value for key,value in os.environ.items()]
            launchInfo.SetEnvironmentEntries(environmentList, False)
727
728
            if self.breakOnMain_:
                self.createBreakpointAtMain()
729
            self.process = self.target.Launch(launchInfo, error)
730
            if not error.Success():
731
                self.reportError(error)
732
                self.reportState("enginerunfailed")
Fawzi Mohamed's avatar
Fawzi Mohamed committed
733
734
                return
            self.report('pid="%s"' % self.process.GetProcessID())
735
            self.reportState("enginerunandinferiorrunok")
736

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

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

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

    def currentThread(self):
760
        return None if self.process is None else self.process.GetSelectedThread()
761
762

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

766
    def reportLocation(self, frame):
767
768
769
770
771
        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))
772

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

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

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

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

835
836
        self.reportLocation(thread.GetFrameAtIndex(0)) # FIXME

837
        isNativeMixed = int(args.get('nativeMixed', 0))
838

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

850
            lineEntry = frame.GetLineEntry()
851
852
853
854
855
856
857
858
859
860
            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

861
            if isNativeMixed:
862
                if self.isReportableQmlFrame(functionName):
863
864
865
866
867
868
869
870
871
                    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'
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889

                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
890
891
892
893
        result += ']'
        result += ',hasmore="%d"' % isLimited
        result += ',limit="%d"' % limit
        result += '}'
894
        self.report(result)
895
896
        self.reportContinuation(args)

897
898
899
900
901
902
    def reportToken(self, args):
        if "token" in args:
            # Unusual syntax intended, to support the double-click in left
            # logview pane feature.
            self.report('token(\"%s\")' % args["token"])

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

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

915
916
917
918
919
920
921
922
923
924
    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))

925
926
927
928
929
930
931
    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)

932
933
    def findSymbol(self, symbolName):
        return self.target.FindFirstGlobalVariable(symbolName)
hjk's avatar
hjk committed
934

935
    def stripNamespaceFromType(self, typeName):
936
        #type = self.stripClassTag(typeName)
937
        type = typeName
938
939
940
        ns = self.qtNamespace()
        if len(ns) > 0 and type.startswith(ns):
            type = type[len(ns):]
941
942
943
944
945
946
        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
947
948
949
950
        if type.startswith("const "):
            type = type[6:]
        if type.startswith("volatile "):
            type = type[9:]
951
952
953
        return type

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

hjk's avatar
hjk committed
960
    def putAddress(self, addr):
961
962
963
964
        #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
965

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

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

hjk's avatar
hjk committed
978
        if tryDynamic:
979
            self.putAddress(value.GetLoadAddress())
hjk's avatar
hjk committed
980

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