lldbbridge.py 70.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
129
130
131
    item = value.GetChildMemberWithName(index)
    if item.IsValid():
        return item
    raise RuntimeError("SBValue.__getitem__: No such member '%s'" % index)
132

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

140
lldb.SBValue.__add__ = impl_SBValue__add__
141
lldb.SBValue.__sub__ = impl_SBValue__sub__
142
lldb.SBValue.__le__ = impl_SBValue__le__
143

144
145
lldb.SBValue.__getitem__ = impl_SBValue__getitem__
lldb.SBValue.__int__ = impl_SBValue__int__
146
lldb.SBValue.__float__ = impl_SBValue__float__
147
148
lldb.SBValue.__long__ = lambda self: long(self.GetValue(), 0)

149
lldb.SBValue.code = lambda self: self.GetTypeClass()
150
lldb.SBValue.cast = lambda self, typeObj: self.Cast(typeObj)
151
lldb.SBValue.dereference = impl_SBValue__deref
152
lldb.SBValue.address = property(lambda self: self.GetLoadAddress())
153
154

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


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

hjk's avatar
hjk committed
165
166
167
lldb.SBType.__orig__str__ = lldb.SBType.__str__
lldb.SBType.__str__ = lldb.SBType.GetName

168
class Dumper(DumperBase):
169
    def __init__(self):
170
171
        DumperBase.__init__(self)

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

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

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

        self.currentIName = None
211
212
        self.currentValue = ReportItem()
        self.currentType = ReportItem()
213
214
215
216
        self.currentNumChild = None
        self.currentMaxNumChild = None
        self.currentPrintsAddress = None
        self.currentChildType = None
217
        self.currentChildNumChild = -1
218
        self.currentWatchers = {}
219

hjk's avatar
hjk committed
220
        self.executable_ = None
221
222
223
224
        self.startMode_ = None
        self.processArgs_ = None
        self.attachPid_ = None

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

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

239
240
241
242
    def enterSubItem(self, item):
        if isinstance(item.name, lldb.SBValue):
            # Avoid $$__synth__ suffix on Mac.
            value = item.name
hjk's avatar
hjk committed
243
244
            if self.isGoodLldb:
                value.SetPreferSyntheticValue(False)
245
246
247
248
            item.name = value.GetName()
            if item.name is None:
                self.anonNumber += 1
                item.name = "#%d" % self.anonNumber
249
250
        if not item.iname:
            item.iname = "%s.%s" % (self.currentIName, item.name)
251
252
253
254
255
256
257
258
259
260
        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
261
262
        self.currentValue = ReportItem()
        self.currentType = ReportItem()
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)
269
            self.putSpecialValue(SpecialNotAccessibleValue)
270
        try:
hjk's avatar
hjk committed
271
272
273
274
            if self.currentType.value:
                typeName = self.currentType.value
                if len(typeName) > 0 and typeName != self.currentChildType:
                    self.put('type="%s",' % typeName) # str(type.unqualified()) ?
275
            if  self.currentValue.value is None:
276
277
                self.put('value="",encoding="%d",numchild="0",'
                        % SpecialNotAccessibleValue)
278
            else:
279
280
281
282
283
                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)
284
285
286
287
288
289
290
291
        except:
            pass
        self.put('},')
        self.currentIName = item.savedIName
        self.currentValue = item.savedValue
        self.currentType = item.savedType
        return True

hjk's avatar
hjk committed
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
329
330
331
    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

332
333
334
335
    def isSimpleType(self, typeobj):
        typeClass = typeobj.GetTypeClass()
        return typeClass == lldb.eTypeClassBuiltin

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

340
341
342
    def simpleValue(self, value):
        return str(value.value)

343
344
345
346
347
348
349
350
351
    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()

352
353
354
355
356
    def enumExpression(self, enumType, enumValue):
        ns = self.qtNamespace()
        return ns + "Qt::" + enumType + "(" \
            + ns + "Qt::" + enumType + "::" + enumValue + ")"

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

hjk's avatar
hjk committed
368
369
370
371
    def isBadPointer(self, value):
        target = value.dereference()
        return target.GetError().Fail()

372
373
374
375
376
    def makeValue(self, type, *args):
        thread = self.currentThread()
        frame = thread.GetFrameAtIndex(0)
        inner = ','.join(args)
        value = frame.EvaluateExpression(type + '{' + inner + '}')
377
378
379
        #self.warn("  TYPE: %s" % value.type)
        #self.warn("  ADDR: 0x%x" % value.address)
        #self.warn("  VALUE: %s" % value)
380
381
        return value

382
383
384
385
386
    def parseAndEvaluate(self, expr):
        thread = self.currentThread()
        frame = thread.GetFrameAtIndex(0)
        return frame.EvaluateExpression(expr)

387
388
389
390
391
392
393
394
    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):
395
        result = typeobj.GetDirectBaseClassAtIndex(index).GetType()
396
        return result if result.IsValid() else None
397

398
    def templateArgument(self, typeobj, index):
399
        type = typeobj.GetTemplateArgumentType(index)
hjk's avatar
hjk committed
400
        if type.IsValid():
401
402
403
404
405
            return type
        inner = self.extractTemplateArgument(typeobj.GetName(), index)
        return self.lookupType(inner)

    def numericTemplateArgument(self, typeobj, index):
406
        # There seems no API to extract the numeric value.
407
        inner = self.extractTemplateArgument(typeobj.GetName(), index)
408
409
410
411
412
413
414
415
        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
416

hjk's avatar
hjk committed
417
418
419
420
421
422
    def isReferenceType(self, typeobj):
        return typeobj.IsReferenceType()

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

423
424
425
426
427
428
429
430
431
    def isWindowsTarget(self):
        return False

    def isQnxTarget(self):
        return False

    def isArmArchitecture(self):
        return False

432
    def qtVersionAndNamespace(self):
433
434
        for func in self.target.FindFunctions('qVersion'):
            name = func.GetSymbol().GetName()
435
436
            if name.endswith('()'):
                name = name[:-2]
437
438
439
            if name.count(':') > 2:
                continue

440
441
442
            qtNamespace = name[:name.find('qVersion')]
            self.qtNamespace = lambda: qtNamespace

443
444
445
446
447
448
449
450
451
452
            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)
453

454
455
456
457
            if not res.IsValid() or not res.GetType().IsPointerType():
                continue

            version = str(res)
458
459
460
            if version.count('.') != 2:
                continue

461
462
            version.replace("'", '"') # Both seem possible
            version = version[version.find('"')+1:version.rfind('"')]
463
464
465
466
467
468
469
470

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

            return (qtNamespace, qtVersion)

        return ('', 0x50200)
471
472

    def qtNamespace(self):
473
        return self.qtVersionAndNamespace()[0]
474
475

    def qtVersion(self):
476
        self.qtVersionAndNamespace()
477
        return self.qtVersionAndNamespace()[1]
478

hjk's avatar
hjk committed
479
480
481
    def intSize(self):
        return 4

482
483
484
    def ptrSize(self):
        return self.target.GetAddressByteSize()

485
    def intType(self):
486
        return self.target.GetBasicType(lldb.eBasicTypeInt)
487

488
    def int64Type(self):
489
        return self.target.GetBasicType(lldb.eBasicTypeLongLong)
490

491
    def charType(self):
492
        return self.target.GetBasicType(lldb.eBasicTypeChar)
493
494

    def charPtrType(self):
495
        return self.target.GetBasicType(lldb.eBasicTypeChar).GetPointerType()
496
497

    def voidPtrType(self):
498
        return self.target.GetBasicType(lldb.eBasicVoid).GetPointerType()
499
500
501
502
503
504

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

505
506
507
    def addressOf(self, value):
        return int(value.GetLoadAddress())

508
509
510
511
512
513
514
515
516
517
    def extractUShort(self, address):
        error = lldb.SBError()
        return int(self.process.ReadUnsignedFromMemory(address, 2, error))

    def extractShort(self, address):
        i = self.extractUInt(address)
        if i >= 0x8000:
            i -= 0x10000
        return i

518
    def extractUInt(self, address):
519
        error = lldb.SBError()
520
        return int(self.process.ReadUnsignedFromMemory(address, 4, error))
hjk's avatar
hjk committed
521

522
523
524
525
526
527
528
    def extractInt(self, address):
        i = self.extractUInt(address)
        if i >= 0x80000000:
            i -= 0x100000000
        return i

    def extractUInt64(self, address):
529
        error = lldb.SBError()
530
        return int(self.process.ReadUnsignedFromMemory(address, 8, error))
531

532
533
534
535
536
537
    def extractInt64(self, address):
        i = self.extractUInt64(address)
        if i >= 0x8000000000000000:
            i -= 0x10000000000000000
        return i

538
    def extractByte(self, address):
539
        error = lldb.SBError()
540
        return int(self.process.ReadUnsignedFromMemory(address, 1, error) & 0xFF)
541

542
543
544
545
546
547
    def handleCommand(self, command):
        result = lldb.SBCommandReturnObject()
        self.debugger.GetCommandInterpreter().HandleCommand(command, result)
        success = result.Succeeded()
        if success:
            self.report('output="%s"' % result.GetOutput())
548
        else:
549
550
551
552
553
554
            self.report('error="%s"' % result.GetError())
        self.reportData()

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

555
    def isMovableType(self, type):
556
        if type.GetTypeClass() in (lldb.eTypeClassBuiltin, lldb.eTypeClassPointer):
557
            return True
558
        return self.isKnownMovableType(self.stripNamespaceFromType(type.GetName()))
559

560
561
562
563
564
565
566
    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
567
568
569
    def putSimpleValue(self, value, encoding = None, priority = 0):
        self.putValue(value.GetValue(), encoding, priority)

570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
    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
598

599
600
    def createPointerValue(self, address, pointeeType):
        addr = int(address) & 0xFFFFFFFFFFFFFFFF
601
602
603
604
605
606
        sbaddr = lldb.SBAddress(addr, self.target)
        # Any type.
        # FIXME: This can be replaced with self.target.CreateValueFromExpression
        # as soon as we drop support for lldb builds not having that (~Xcode 6.1)
        dummy = self.target.CreateValueFromAddress('@', sbaddr, self.target.FindFirstType('char'))
        return dummy.CreateValueFromExpression('', '(%s*)%s' % (pointeeType, addr))
607
608
609

    def createValue(self, address, referencedType):
        addr = int(address) & 0xFFFFFFFFFFFFFFFF
610
        sbaddr = lldb.SBAddress(addr, self.target)
611
        return self.target.CreateValueFromAddress('@', sbaddr, referencedType)
612

613
614
615
616
617
    def childRange(self):
        if self.currentMaxNumChild is None:
            return xrange(0, self.currentNumChild)
        return xrange(min(self.currentMaxNumChild, self.currentNumChild))

618
619
620
    def canonicalTypeName(self, name):
        return re.sub('\\bconst\\b', '', name).replace(' ', '')

621
    def lookupType(self, name):
622
        #self.warn("LOOKUP TYPE NAME: %s" % name)
623
624
625
        typeobj = self.target.FindFirstType(name)
        if typeobj.IsValid():
            return typeobj
hjk's avatar
hjk committed
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
        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)
656
        return None
657

658
    def setupInferior(self, args):
659
        self.reportToken(args)
660
        error = lldb.SBError()
661
662

        self.executable_ = args['executable']
663
        self.startMode_ = args.get('startMode', 1)
664
        self.breakOnMain_ = args.get('breakOnMain', 0)
hjk's avatar
hjk committed
665
        self.useTerminal_ = args.get('useTerminal', 0)
666
667
        self.processArgs_ = args.get('processArgs', [])
        self.processArgs_ = map(lambda x: self.hexdecode(x), self.processArgs_)
668
        self.attachPid_ = args.get('attachPid', 0)
Fawzi Mohamed's avatar
Fawzi Mohamed committed
669
        self.sysRoot_ = args.get('sysRoot', '')
Fawzi Mohamed's avatar
Fawzi Mohamed committed
670
        self.remoteChannel_ = args.get('remoteChannel', '')
671
        self.platform_ = args.get('platform', '')
672

hjk's avatar
hjk committed
673
        self.ignoreStops = 0
674
675
676
677
678
679
680
681
682
        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
683

684
685
686
687
        else:
            if self.useTerminal_:
                self.ignoreStops = 1

688
689
        if self.platform_:
            self.debugger.SetCurrentPlatform(self.platform_)
Fawzi Mohamed's avatar
Fawzi Mohamed committed
690
691
692
        # sysroot has to be set *after* the platform
        if self.sysRoot_:
            self.debugger.SetCurrentPlatformSDKRoot(self.sysRoot_)
693

694

695
696
697
698
        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)
699

700
        if self.target.IsValid():
701
702
            for bp in args['bkpts']:
                self.insertBreakpoint(bp)
703

704
705
        state = "inferiorsetupok" if self.target.IsValid() else "inferiorsetupfailed"
        self.report('state="%s",msg="%s",exe="%s"' % (state, error, self.executable_))
706

707
708
    def runEngine(self, args):
        self.prepare(args)
hjk's avatar
hjk committed
709
710
711
        s = threading.Thread(target=self.loop, args=[])
        s.start()

712
    def prepare(self, args):
713
        self.reportToken(args)
714
        error = lldb.SBError()
hjk's avatar
hjk committed
715
716
        listener = self.debugger.GetListener()

717
718
719
        if self.attachPid_ > 0:
            attachInfo = lldb.SBAttachInfo(self.attachPid_)
            self.process = self.target.Attach(attachInfo, error)
720
            if not error.Success():
721
                self.reportState("inferiorrunfailed")
Fawzi Mohamed's avatar
Fawzi Mohamed committed
722
723
                return
            self.report('pid="%s"' % self.process.GetProcessID())
724
725
726
727
            # 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
728
        elif self.startMode_ == AttachToRemoteServer or self.startMode_ == AttachToRemoteProcess:
Fawzi Mohamed's avatar
Fawzi Mohamed committed
729
            self.process = self.target.ConnectRemote(
730
731
                self.debugger.GetListener(),
                self.remoteChannel_, None, error)
732
            if not error.Success():
733
734
                self.reportError(error)
                self.reportState("enginerunfailed")
735
                return
736
737
738
739
            # 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")
740
741
742
743
744
        elif self.startMode_ == AttachCore:
            coreFile = args.get('coreFile', '');
            self.process = self.target.LoadCore(coreFile)
            self.reportState("enginerunokandinferiorunrunnable")
            #self.reportContinuation(args)
745
        else:
746
            launchInfo = lldb.SBLaunchInfo(self.processArgs_)
747
            launchInfo.SetWorkingDirectory(os.getcwd())
748
749
            environmentList = [key + "=" + value for key,value in os.environ.items()]
            launchInfo.SetEnvironmentEntries(environmentList, False)
750
751
            if self.breakOnMain_:
                self.createBreakpointAtMain()
752
            self.process = self.target.Launch(launchInfo, error)
753
            if not error.Success():
754
                self.reportError(error)
755
                self.reportState("enginerunfailed")
Fawzi Mohamed's avatar
Fawzi Mohamed committed
756
757
                return
            self.report('pid="%s"' % self.process.GetProcessID())
758
            self.reportState("enginerunandinferiorrunok")
759

hjk's avatar
hjk committed
760
    def loop(self):
hjk's avatar
hjk committed
761
        event = lldb.SBEvent()
hjk's avatar
hjk committed
762
        listener = self.debugger.GetListener()
hjk's avatar
hjk committed
763
764
765
766
767
        while True:
            if listener.WaitForEvent(10000000, event):
                self.handleEvent(event)
            else:
                warn('TIMEOUT')
768

769
    def describeError(self, error):
770
771
772
773
774
        desc = lldb.SBStream()
        error.GetDescription(desc)
        result = 'error={type="%s"' % error.GetType()
        result += ',code="%s"' % error.GetError()
        result += ',desc="%s"}' % desc.GetData()
775
776
777
778
        return result

    def reportError(self, error):
        self.report(self.describeError(error))
hjk's avatar
hjk committed
779
780
        if error.GetType():
            self.reportStatus(error.GetCString())
781
782

    def currentThread(self):
783
        return None if self.process is None else self.process.GetSelectedThread()
784
785

    def currentFrame(self):
786
787
        thread = self.currentThread()
        return None if thread is None else thread.GetSelectedFrame()
788

789
    def reportLocation(self, frame):
790
791
792
793
794
        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))
795

796
797
798
    def firstStoppedThread(self):
        for i in xrange(0, self.process.GetNumThreads()):
            thread = self.process.GetThreadAtIndex(i)
799
800
801
802
803
804
            reason = thread.GetStopReason()
            if (reason == lldb.eStopReasonBreakpoint or
                    reason == lldb.eStopReasonException or
                    reason == lldb.eStopReasonPlanComplete or
                    reason == lldb.eStopReasonSignal or
                    reason == lldb.eStopReasonWatchpoint):
805
806
807
                return thread
        return None

808
809
    def reportThreads(self, args):
        self.reportToken(args)
810
        result = 'threads={threads=['
811
        for i in xrange(0, self.process.GetNumThreads()):
812
            thread = self.process.GetThreadAtIndex(i)
hjk's avatar
hjk committed
813
814
815
816
817
818
819
            if thread.is_stopped:
                state = "stopped"
            elif thread.is_suspended:
                state = "suspended"
            else:
                state = "unknown"
            reason = thread.GetStopReason()
820
821
            result += '{id="%d"' % thread.GetThreadID()
            result += ',index="%s"' % i
822
            result += ',details="%s"' % thread.GetQueueName()
hjk's avatar
hjk committed
823
824
            result += ',stop-reason="%s"' % self.stopReason(thread.GetStopReason())
            result += ',state="%s"' % state
825
            result += ',name="%s"' % thread.GetName()
826
827
828
829
830
            result += ',frame={'
            frame = thread.GetFrameAtIndex(0)
            result += 'pc="0x%x"' % frame.pc
            result += ',addr="0x%x"' % frame.pc
            result += ',fp="0x%x"' % frame.fp
831
            result += ',func="%s"' % frame.GetFunctionName()
832
833
834
835
836
            result += ',line="%s"' % frame.line_entry.line
            result += ',fullname="%s"' % fileName(frame.line_entry.file)
            result += ',file="%s"' % fileName(frame.line_entry.file)
            result += '}},'

837
        result += ']},'
838
839
        self.report(result)

840
841
842
843
    def reportCurrentThread(self, args):
        self.reportToken(args)
        self.report('current-thread={id="%s"}' % self.currentThread().id)

844
    def firstUsableFrame(self, thread):
hjk's avatar
hjk committed
845
        for i in xrange(10):
hjk's avatar
hjk committed
846
847
848
849
850
851
852
            frame = thread.GetFrameAtIndex(i)
            lineEntry = frame.GetLineEntry()
            line = lineEntry.GetLine()
            if line != 0:
                return i
        return None

853
    def reportStack(self, args):
854
        self.reportToken(args)
855
        if not self.process:
856
            self.report('msg="No process"')
857
858
859
860
861
            return
        thread = self.currentThread()
        if not thread:
            self.report('msg="No thread"')
            return
862

863
864
        self.reportLocation(thread.GetFrameAtIndex(0)) # FIXME

865
        isNativeMixed = int(args.get('nativeMixed', 0))
866

867
868
        limit = args.get('stacklimit', -1)
        (n, isLimited) = (limit, True) if limit > 0 else (thread.GetNumFrames(), False)
869
        self.currentCallContext = None
870
        result = 'stack={current-thread="%s"' % thread.GetThreadID()
871
872
873
        result += ',frames=['
        for i in xrange(n):
            frame = thread.GetFrameAtIndex(i)
874
875
876
            if not frame.IsValid():
                isLimited = False
                break
877

878
            lineEntry = frame.GetLineEntry()
879
880
881
882
883
884
885
886
887
888
            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

889
            if isNativeMixed:
890
                if self.isReportableQmlFrame(functionName):
891
892
893
894
895
896
897
898
899
                    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'
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917

                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
918
919
920
921
        result += ']'
        result += ',hasmore="%d"' % isLimited
        result += ',limit="%d"' % limit
        result += '}'
922
        self.report(result)
923
924
        self.reportContinuation(args)

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

931
    def reportContinuation(self, args):
932
        if not self.isShuttingDown_ and "continuation" in args:
933
            self.report('continuation=\"%s\"' % args["continuation"])
934

hjk's avatar
hjk committed
935
    def extractBlob(self, base, size):
hjk's avatar
hjk committed
936
        if size == 0:
hjk's avatar
hjk committed
937
            return Blob("")
938
939
        base = int(base) & 0xFFFFFFFFFFFFFFFF
        size = int(size) & 0xFFFFFFFF
hjk's avatar
hjk committed
940
        error = lldb.SBError()
hjk's avatar
hjk committed
941
        return Blob(self.process.ReadMemory(base, size, error))
hjk's avatar
hjk committed
942

943
944
945
946
947
948
949
950
951
952
    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))

953
954
955
956
957
958
959
    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)

960
961
    def findSymbol(self, symbolName):
        return self.target.FindFirstGlobalVariable(symbolName)
hjk's avatar
hjk committed
962

963
    def stripNamespaceFromType(self, typeName):
964
        #type = self.stripClassTag(typeName)
965
        type = typeName
966
967
968
        ns = self.qtNamespace()
        if len(ns) > 0 and type.startswith(ns):
            type = type[len(ns):]
969
970
971
972
973
974
        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
975
976
977
978
        if type.startswith("const "):
            type = type[6:]
        if type.startswith("volatile "):
            type = type[9:]
979
980
981
        return type

    def putSubItem(self, component, value, tryDynamic=True):
982
        if not value.IsValid():
983
            self.warn("INVALID SUBITEM: %s" % value.GetName())
984
            return
985
986
987
        with SubItem(self, component):
            self.putItem(value, tryDynamic)

hjk's avatar
hjk committed
988
    def putAddress(self, addr):
989
990
991
992
        #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
993

hjk's avatar
hjk committed
994
995
996
997
998
    def isFunctionType(self, typeobj):
        if self.isGoodLldb:
            return typeobj.IsFunctionType()
        #warn("TYPE: %s" % typeobj)
        return False
hjk's avatar
hjk committed
999

1000
    def putItem(self, value, tryDynamic=True):
1001
        typeName = value.GetType().GetUnqualifiedType().GetName()
hjk's avatar
hjk committed
1002
1003
        if self.isGoodLldb:
            value.SetPreferDynamicValue(tryDynamic)
hjk's avatar
hjk committed
1004
        typeClass = value.GetType().GetTypeClass()
1005

hjk's avatar
hjk committed
1006
        if tryDynamic:
1007
            self.putAddress(value.GetLoadAddress())
hjk's avatar
hjk committed
1008

1009
        # Handle build-in LLDB visualizers if wanted.
1010
        if False and self.useLldbDumpers and value.GetTypeSynthetic().IsValid():
1011
1012
1013
1014
            # FIXME: print "official" summary?
            summary = value.GetTypeSummary()
            if summary.IsValid():
                warn("DATA: %s" % summary.GetData())
hjk's avatar
hjk committed
1015
1016
            if self.isGoodLldb:
                value.SetPreferSyntheticValue(False)
1017
1018
1019
1020
1021
            provider = value.GetTypeSynthetic()
            data = provider.GetData()
            formatter = eval(data)(value, {})
            formatter.update()
            numchild = formatter.num_children()
hjk's avatar
hjk committed
1022
            self.put('iname="%s",' % self.currentIName)
hjk's avatar
hjk committed
1023
            self.putType(typeName)
hjk's avatar
hjk committed
1024
1025
            self.put('numchild="%s",' % numchild)
            self.put('addr="0x%x",' % value.GetLoadAddress())
1026
            self.putItemCount(numchild)
hjk's avatar
hjk committed
1027
1028
            if self.currentIName in self.expandedINames:
                with Children(self):
1029