lldbbridge.py 68.4 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
        self.currentNumChild = None
        self.currentMaxNumChild = None
        self.currentPrintsAddress = None
        self.currentChildType = None
214
        self.currentChildNumChild = -1
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
    def extractInt(self, address):
512
        error = lldb.SBError()
513
        return int(self.process.ReadUnsignedFromMemory(address, 4, error))
hjk's avatar
hjk committed
514

515
    def extractInt64(self, address):
516
        error = lldb.SBError()
517
        return int(self.process.ReadUnsignedFromMemory(address, 8, error))
518

519
    def extractByte(self, address):
520
        error = lldb.SBError()
521
        return int(self.process.ReadUnsignedFromMemory(address, 1, error) & 0xFF)
522

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

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

536
    def isMovableType(self, type):
537
        if type.GetTypeClass() in (lldb.eTypeClassBuiltin, lldb.eTypeClassPointer):
538
            return True
539
        return self.isKnownMovableType(self.stripNamespaceFromType(type.GetName()))
540

541
542
543
544
545
546
547
    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
548
549
550
    def putSimpleValue(self, value, encoding = None, priority = 0):
        self.putValue(value.GetValue(), encoding, priority)

551
552
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
    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
579

580
581
582
583
584
585
586
587
    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)

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

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

596
    def lookupType(self, name):
597
        #self.warn("LOOKUP TYPE NAME: %s" % name)
598
599
600
        typeobj = self.target.FindFirstType(name)
        if typeobj.IsValid():
            return typeobj
hjk's avatar
hjk committed
601
602
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
        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)
631
        return None
632

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

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

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

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

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

669

670
671
672
673
        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)
674

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

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

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

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

812
        result += ']},'
813
814
        self.report(result)

815
816
817
818
    def reportCurrentThread(self, args):
        self.reportToken(args)
        self.report('current-thread={id="%s"}' % self.currentThread().id)

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

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

838
839
        self.reportLocation(thread.GetFrameAtIndex(0)) # FIXME

840
        isNativeMixed = int(args.get('nativeMixed', 0))
841

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

853
            lineEntry = frame.GetLineEntry()
854
855
856
857
858
859
860
861
862
863
            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

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

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

900
901
902
903
904
905
    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"])

906
    def reportContinuation(self, args):
907
        if not self.isShuttingDown_ and "continuation" in args:
908
            self.report('continuation=\"%s\"' % args["continuation"])
909

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