lldbbridge.py 59.7 KB
Newer Older
1
2
############################################################################
#
3
# Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Contact: http://www.qt-project.org/legal
#
# 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
# a written agreement between you and Digia.  For licensing terms and
# conditions see http://qt.digia.com/licensing.  For further information
# use the contact form at http://qt.digia.com/contact-us.
#
# GNU Lesser General Public License Usage
# Alternatively, this file may be used under the terms of the GNU Lesser
# General Public License version 2.1 as published by the Free Software
# Foundation and appearing in the file LICENSE.LGPL included in the
# packaging of this file.  Please review the following information to
# ensure the GNU Lesser General Public License version 2.1 requirements
# will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
#
# In addition, as a special exception, Digia gives you certain additional
# rights.  These rights are described in the Digia Qt LGPL Exception
# version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
#
#############################################################################
29

30
import atexit
31
import inspect
32
import json
33
import os
34
import re
35
36
import select
import sys
37
import subprocess
38
import threading
39

40
41
42
43
44
currentDir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
sys.path.insert(1, currentDir)

from dumper import *
from qttypes import *
hjk's avatar
hjk committed
45
46
47
from stdtypes import *
from misctypes import *
from boosttypes import *
48
from creatortypes import *
49

50
51
52
lldbCmd = 'lldb'
if len(sys.argv) > 1:
    lldbCmd = sys.argv[1]
53

54
proc = subprocess.Popen(args=[lldbCmd, '-P'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
55
(path, error) = proc.communicate()
56

57
if error.startswith('lldb: invalid option -- P'):
58
    sys.stdout.write('msg=\'Could not run "%s -P". Trying to find lldb.so from Xcode.\'@\n' % lldbCmd)
59
60
61
62
63
    proc = subprocess.Popen(args=['xcode-select', '--print-path'],
        stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (path, error) = proc.communicate()
    if len(error):
        path = '/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/Resources/Python/'
64
65
        sys.stdout.write('msg=\'Could not run "xcode-select --print-path"@\n')
        sys.stdout.write('msg=\'Using hardcoded fallback at %s\'@\n' % path)
66
67
    else:
        path = path.strip() + '/../SharedFrameworks/LLDB.framework/Versions/A/Resources/Python/'
68
        sys.stdout.write('msg=\'Using fallback at %s\'@\n' % path)
69

70
sys.path.insert(1, path.strip())
71
72

import lldb
73
74
75
76
77
78
79

#######################################################################
#
# Helpers
#
#######################################################################

80
qqWatchpointOffset = 10000
81

82
83

def warn(message):
84
    print('\n\nWARNING="%s",\n' % message.encode("latin1").replace('"', "'"))
85
86
87

def showException(msg, exType, exValue, exTraceback):
    warn("**** CAUGHT EXCEPTION: %s ****" % msg)
88
89
90
    import traceback
    lines = [line for line in traceback.format_exception(exType, exValue, exTraceback)]
    warn('\n'.join(lines))
91
92
93
94

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

95

96
97
98
99
100
101
102
103
104
105
# Breakpoints. Keep synchronized with BreakpointType in breakpoint.h
UnknownType = 0
BreakpointByFileAndLine = 1
BreakpointByFunction = 2
BreakpointByAddress = 3
BreakpointAtThrow = 4
BreakpointAtCatch = 5
BreakpointAtMain = 6
BreakpointAtFork = 7
BreakpointAtExec = 8
106
107
108
109
110
BreakpointAtSysCall = 9
WatchpointAtAddress = 10
WatchpointAtExpression = 11
BreakpointOnQmlSignalEmit = 12
BreakpointAtJavaScriptThrow = 13
111

112
113
114
# See db.StateType
stateNames = ["invalid", "unloaded", "connected", "attaching", "launching", "stopped",
    "running", "stepping", "crashed", "detached", "exited", "suspended" ]
115

116
117
118
def loggingCallback(args):
    s = args.strip()
    s = s.replace('"', "'")
119
    sys.stdout.write('log="%s"@\n' % s)
120

hjk's avatar
hjk committed
121
122
123
124
def check(exp):
    if not exp:
        raise RuntimeError("Check failed")

125
126
Value = lldb.SBValue

127
128
def impl_SBValue__add__(self, offset):
    if self.GetType().IsPointerType():
129
130
131
132
        if isinstance(offset, int) or isinstance(offset, long):
            pass
        else:
            offset = offset.GetValueAsSigned()
133
        itemsize = self.GetType().GetPointeeType().GetByteSize()
134
        address = self.GetValueAsUnsigned() + offset * itemsize
135
        address = address & 0xFFFFFFFFFFFFFFFF  # Force unsigned
136
137
        return self.CreateValueFromAddress(None, address,
                self.GetType().GetPointeeType()).AddressOf()
hjk's avatar
hjk committed
138

139
    raise RuntimeError("SBValue.__add__ not implemented: %s" % self.GetType())
140
141
    return NotImplemented

142
def impl_SBValue__sub__(self, other):
143
    if self.GetType().IsPointerType():
144
145
146
147
        if isinstance(other, int) or isinstance(other, long):
            address = self.GetValueAsUnsigned() - offset.GetValueAsSigned()
            address = address & 0xFFFFFFFFFFFFFFFF  # Force unsigned
            return self.CreateValueFromAddress(None, address, self.GetType())
148
        if other.GetType().IsPointerType():
149
150
            itemsize = self.GetType().GetPointeeType().GetByteSize()
            return (self.GetValueAsUnsigned() - other.GetValueAsUnsigned()) / itemsize
151
    raise RuntimeError("SBValue.__sub__ not implemented: %s" % self.GetType())
152
153
    return NotImplemented

154
155
156
157
158
159
160
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):
161
    return self.GetValueAsSigned()
162
163
164
165
166
167
168
169
170
171

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
172

173
174
175
def impl_SBValue__long__(self):
    return int(self.GetValue(), 0)

176
177
178
179
180
181
182
183
184
def impl_SBValue__getitem__(value, index):
    if isinstance(index, int):
        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)
185
186
187
188
189
190
191
192
193
194
    result = value.GetChildMemberWithName(index)
    if int(result.GetLoadAddress()) == 0xffffffffffffffff:
        options = lldb.SBExpressionOptions()
        typeClass = child.GetType().GetTypeClass()
        if typeClass != lldb.eTypeClassBuiltin:
            i = value.GetIndexOfChildWithName(index)
            field = value.GetType().GetFieldAtIndex(i)
            addr = value.GetLoadAddress() + field.GetOffsetInBytes()
            child = value.CreateValueFromAddress(child.GetName(), addr, child.GetType())
    return result
195

196
197
198
199
def impl_SBValue__deref(value):
    result = value.Dereference()
    if result.IsValid():
        return result
200
201
202
    #warn("RESULT.LOADADDRESS A: 0x%x" % result.GetLoadAddress())
    result = value.CreateValueFromAddress(None, value.GetValueAsUnsigned(), value.GetType().GetPointerType())
    #warn("RESULT.LOADADDRESS B: 0x%x" % result.GetLoadAddress())
203
204
    return result

205
lldb.SBValue.__add__ = impl_SBValue__add__
206
lldb.SBValue.__sub__ = impl_SBValue__sub__
207
lldb.SBValue.__le__ = impl_SBValue__le__
208

209
210
lldb.SBValue.__getitem__ = impl_SBValue__getitem__
lldb.SBValue.__int__ = impl_SBValue__int__
211
lldb.SBValue.__float__ = impl_SBValue__float__
212
213
lldb.SBValue.__long__ = lambda self: long(self.GetValue(), 0)

214
lldb.SBValue.code = lambda self: self.GetTypeClass()
215
lldb.SBValue.cast = lambda self, typeObj: self.Cast(typeObj)
216
lldb.SBValue.dereference = impl_SBValue__deref
217
lldb.SBValue.address = property(lambda self: self.GetLoadAddress())
218
219

lldb.SBType.pointer = lambda self: self.GetPointerType()
hjk's avatar
hjk committed
220
lldb.SBType.target = lambda self: self.GetPointeeType()
221
lldb.SBType.code = lambda self: self.GetTypeClass()
222
lldb.SBType.sizeof = property(lambda self: self.GetByteSize())
223
224


hjk's avatar
hjk committed
225
226
lldb.SBType.unqualified = \
    lambda self: self.GetUnqualifiedType() if hasattr(self, 'GetUnqualifiedType') else self
227
228
lldb.SBType.strip_typedefs = \
    lambda self: self.GetCanonicalType() if hasattr(self, 'GetCanonicalType') else self
229

hjk's avatar
hjk committed
230
231
232
lldb.SBType.__orig__str__ = lldb.SBType.__str__
lldb.SBType.__str__ = lldb.SBType.GetName

233
234
235
236
def simpleEncoding(typeobj):
    code = typeobj.GetTypeClass()
    size = typeobj.sizeof
    if code == lldb.eTypeClassBuiltin:
hjk's avatar
hjk committed
237
238
239
240
241
242
        name = str(typeobj)
        if name == "float":
            return Hex2EncodedFloat4
        if name == "double":
            return Hex2EncodedFloat8
        if name.find("unsigned") >= 0:
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
            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
hjk's avatar
hjk committed
261

262
class Dumper(DumperBase):
263
    def __init__(self):
264
265
        DumperBase.__init__(self)

266
        self.debugger = lldb.SBDebugger.Create()
267
        #self.debugger.SetLoggingCallback(loggingCallback)
268
269
270
271
272
273
        #Same as: self.debugger.HandleCommand("log enable lldb dyld step")
        #self.debugger.EnableLog("lldb", ["dyld", "step", "process", "state", "thread", "events",
        #    "communication", "unwind", "commands"])
        #self.debugger.EnableLog("lldb", ["all"])
        self.debugger.Initialize()
        self.debugger.HandleCommand("settings set auto-confirm on")
274
275
276
277
278
279
280
281
282
283

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

284
        self.isLldb = True
285
286
287
288
        self.process = None
        self.target = None
        self.eventState = lldb.eStateInvalid
        self.expandedINames = {}
289
        self.passExceptions = False
290
        self.useLldbDumpers = False
hjk's avatar
hjk committed
291
        self.autoDerefPointers = True
292
        self.useDynamicType = True
hjk's avatar
hjk committed
293
        self.useFancy = True
hjk's avatar
hjk committed
294
295
        self.formats = {}
        self.typeformats = {}
296
297
298
299
300
301

        self.currentIName = None
        self.currentValuePriority = -100
        self.currentValueEncoding = None
        self.currentType = ""
        self.currentTypePriority = -100
302
        self.currentValue = None
303
304
305
306
307
        self.currentNumChild = None
        self.currentMaxNumChild = None
        self.currentPrintsAddress = None
        self.currentChildType = None
        self.currentChildNumChild = None
308
        self.currentWatchers = {}
309

hjk's avatar
hjk committed
310
        self.executable_ = None
311
312
313
314
        self.startMode_ = None
        self.processArgs_ = None
        self.attachPid_ = None

315
316
        self.charType_ = None
        self.intType_ = None
317
        self.int64Type_ = None
318
319
        self.sizetType_ = None
        self.charPtrType_ = None
hjk's avatar
hjk committed
320
        self.voidPtrType_ = None
321
        self.isShuttingDown_ = False
322
        self.isInterrupting_ = False
323
        self.dummyValue = None
324
        self.types_ = {}
325

326
327
328
329
330
331
332
333
334
    def enterSubItem(self, item):
        if isinstance(item.name, lldb.SBValue):
            # Avoid $$__synth__ suffix on Mac.
            value = item.name
            value.SetPreferSyntheticValue(False)
            item.name = value.GetName()
            if item.name is None:
                self.anonNumber += 1
                item.name = "#%d" % self.anonNumber
335
336
        if not item.iname:
            item.iname = "%s.%s" % (self.currentIName, item.name)
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
        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.savedValuePriority = self.currentValuePriority
        item.savedValueEncoding = self.currentValueEncoding
        item.savedType = self.currentType
        item.savedTypePriority = self.currentTypePriority
        self.currentIName = item.iname
        self.currentValuePriority = -100
        self.currentValueEncoding = None
        self.currentType = ""
        self.currentTypePriority = -100

    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:
            typeName = self.currentType
            if len(typeName) > 0 and typeName != self.currentChildType:
                self.put('type="%s",' % typeName) # str(type.unqualified()) ?
            if  self.currentValue is None:
                self.put('value="<not accessible>",numchild="0",')
            else:
                if not self.currentValueEncoding is None:
369
                    self.put('valueencoded="%s",' % self.currentValueEncoding)
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
                self.put('value="%s",' % self.currentValue)
        except:
            pass
        self.put('},')
        self.currentIName = item.savedIName
        self.currentValue = item.savedValue
        self.currentValuePriority = item.savedValuePriority
        self.currentValueEncoding = item.savedValueEncoding
        self.currentType = item.savedType
        self.currentTypePriority = item.savedTypePriority
        return True

    def isSimpleType(self, typeobj):
        typeClass = typeobj.GetTypeClass()
        return typeClass == lldb.eTypeClassBuiltin

hjk's avatar
hjk committed
386
387
388
    def childWithName(self, value, name):
        child = value.GetChildMemberWithName(name)
        return child if child.IsValid() else None
389

390
391
392
393
394
395
396
397
398
    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()

399
400
401
402
403
    def enumExpression(self, enumType, enumValue):
        ns = self.qtNamespace()
        return ns + "Qt::" + enumType + "(" \
            + ns + "Qt::" + enumType + "::" + enumValue + ")"

404
405
406
407
408
409
410
411
412
413
414
    def call2(self, value, func, args):
        # args is a tuple.
        arg = ','.join(args)
        #warn("CALL: %s -> %s(%s)" % (value, func, arg))
        type = value.type.name
        exp = "((%s*)%s)->%s(%s)" % (type, value.address, func, arg)
        #warn("CALL: %s" % exp)
        result = value.CreateValueFromExpression('$tmp', exp)
        #warn("  -> %s" % result)
        return result

415
416
417
418
419
420
421
422
423
424
    def makeValue(self, type, *args):
        thread = self.currentThread()
        frame = thread.GetFrameAtIndex(0)
        inner = ','.join(args)
        value = frame.EvaluateExpression(type + '{' + inner + '}')
        #warn("  TYPE: %s" % value.type)
        #warn("  ADDR: 0x%x" % value.address)
        #warn("  VALUE: %s" % value)
        return value

425
426
427
428
429
    def parseAndEvaluate(self, expr):
        thread = self.currentThread()
        frame = thread.GetFrameAtIndex(0)
        return frame.EvaluateExpression(expr)

430
431
432
433
434
435
436
437
438
439
440
441
442
    def call(self, value, func, *args):
        return self.call2(value, func, args)

    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):
        return typeobj.GetDirectBaseClassAtIndex(index)

443
    def templateArgument(self, typeobj, index):
444
        type = typeobj.GetTemplateArgumentType(index)
hjk's avatar
hjk committed
445
        if type.IsValid():
446
447
448
449
450
451
452
            return type
        inner = self.extractTemplateArgument(typeobj.GetName(), index)
        return self.lookupType(inner)

    def numericTemplateArgument(self, typeobj, index):
        inner = self.extractTemplateArgument(typeobj.GetName(), index)
        return int(inner)
453

hjk's avatar
hjk committed
454
455
456
457
458
459
    def isReferenceType(self, typeobj):
        return typeobj.IsReferenceType()

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

460
461
    def qtVersionAndNamespace(self):
        self.cachedQtNamespace = ""
462
        self.cachedQtVersion = 0x0
463

464
465
466
        coreExpression = re.compile(r"(lib)?Qt5?Core")
        for n in range(0, self.target.GetNumModules()):
            module = self.target.GetModuleAtIndex(n)
467
468
            fileName = module.GetFileSpec().GetFilename()
            if coreExpression.match(fileName):
469
                # Extract version.
470
                reverseVersion = module.GetVersion()
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
                if len(reverseVersion):
                    # Mac, Clang?
                    reverseVersion.reverse()
                    shift = 0
                    for v in reverseVersion:
                        self.cachedQtVersion += v << shift
                        shift += 8
                else:
                    # Linux, gcc?
                    if fileName.endswith(".5"):
                        self.cachedQtVersion = 0x50000
                    elif fileName.endswith(".4"):
                        self.cachedQtVersion = 0x40800
                    else:
                        warn("CANNOT GUESS QT VERSION")

487
488
489
490
491
492
493
494
495
496

                # Look for some Qt symbol to extract namespace.
                for symbol in module.symbols:
                    name = symbol.GetName()
                    pos = name.find("QString")
                    if pos >= 0:
                        name = name[:pos]
                        if name.endswith("::"):
                            self.cachedQtNamespace = re.sub('^.*[^\w]([\w]+)::$', '\\1', name) + '::'
                        break
497
                break
498
499

        # Memoize good results.
500
        self.qtNamespace = lambda: self.cachedQtNamespace
501
        self.qtVersion = lambda: self.cachedQtVersion
502
503
504
505
506
507

    def qtNamespace(self):
        self.qtVersionAndNamespace()
        return self.cachedQtNamespace

    def qtVersion(self):
508
        self.qtVersionAndNamespace()
509
        return self.cachedQtVersion
510

hjk's avatar
hjk committed
511
512
513
    def intSize(self):
        return 4

514
515
    def intType(self):
        if self.intType_ is None:
hjk's avatar
hjk committed
516
             self.intType_ = self.target.FindFirstType('int')
517
518
        return self.intType_

519
520
521
522
523
    def int64Type(self):
        if self.int64Type_ is None:
             self.int64Type_ = self.target.FindFirstType('long long int')
        return self.int64Type_

524
525
    def charType(self):
        if self.charType_ is None:
hjk's avatar
hjk committed
526
             self.charType_ = self.target.FindFirstType('char')
527
528
529
530
531
532
533
534
        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
535
536
537
        if self.voidPtrType_ is None:
             self.voidPtrType_ = self.target.FindFirstType('void').GetPointerType()
        return self.voidPtrType_
538

hjk's avatar
hjk committed
539
    def ptrSize(self):
540
541
542
543
544
545
546
        return self.charPtrType().GetByteSize()

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

547
548
549
    def addressOf(self, value):
        return int(value.GetLoadAddress())

hjk's avatar
hjk committed
550
551
552
553
554
555
556
557
558
    def dereferenceValue(self, value):
        return long(value.Cast(self.voidPtrType()))

    def dereference(self, address):
        return long(self.createValue(address, self.voidPtrType()))

    def extractInt(self, address):
        return int(self.createValue(address, self.intType()))

559
560
561
    def extractInt64(self, address):
        return int(self.createValue(address, self.int64Type()))

562
563
564
    def extractByte(self, address):
        return int(self.createValue(address, self.charType())) & 0xFF

565
566
567
568
569
570
    def handleCommand(self, command):
        result = lldb.SBCommandReturnObject()
        self.debugger.GetCommandInterpreter().HandleCommand(command, result)
        success = result.Succeeded()
        if success:
            self.report('output="%s"' % result.GetOutput())
571
        else:
572
573
574
575
576
577
            self.report('error="%s"' % result.GetError())
        self.reportData()

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

578
    def isMovableType(self, type):
579
        if type.GetTypeClass() in (lldb.eTypeClassBuiltin, lldb.eTypeClassPointer):
580
            return True
581
        return self.isKnownMovableType(self.stripNamespaceFromType(type.GetName()))
582

583
584
    def putNumChild(self, numchild):
        #warn("NUM CHILD: '%s' '%s'" % (numchild, self.currentChildNumChild))
hjk's avatar
hjk committed
585
586
        #if numchild != self.currentChildNumChild:
        self.put('numchild="%s",' % numchild)
587

588
589
590
591
592
593
594
    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
595
596
597
    def putSimpleValue(self, value, encoding = None, priority = 0):
        self.putValue(value.GetValue(), encoding, priority)

598
    def tryPutArrayContents(self, typeobj, base, n):
599
        if not self.isSimpleType(typeobj):
600
601
602
            return False
        size = n * typeobj.sizeof
        self.put('childtype="%s",' % typeobj)
603
604
        self.put('addrbase="0x%x",' % int(base))
        self.put('addrstep="%d",' % typeobj.sizeof)
605
606
        self.put('arrayencoding="%s",' % simpleEncoding(typeobj))
        self.put('arraydata="')
607
        self.put(self.readMemory(base, size))
608
609
610
611
612
613
        self.put('",')
        return True

    def putArrayData(self, type, base, n,
            childNumChild = None, maxNumChild = 10000):
        if not self.tryPutArrayContents(type, base, n):
614
            base = self.createPointerValue(base, type)
615
616
617
618
619
            with Children(self, n, type, childNumChild, maxNumChild,
                    base, type.GetByteSize()):
                for i in self.childRange():
                    self.putSubItem(i, (base + i).dereference())

620
621
622
623
624
625
626
627
    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)

628
    def putCallItem(self, name, value, func, *args):
629
        result = self.call2(value, func, args)
630
631
632
        with SubItem(self, name):
            self.putItem(result)

633
634
635
636
637
    def childRange(self):
        if self.currentMaxNumChild is None:
            return xrange(0, self.currentNumChild)
        return xrange(min(self.currentMaxNumChild, self.currentNumChild))

638
639
640
    def canonicalTypeName(self, name):
        return re.sub('\\bconst\\b', '', name).replace(' ', '')

641
    def lookupType(self, name):
hjk's avatar
hjk committed
642
        #warn("LOOKUP TYPE NAME: %s" % name)
hjk's avatar
hjk committed
643
        if name.endswith('*'):
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
            typeobj = self.lookupType(name[:-1].strip())
            return typeobj.GetPointerType() if type.IsValid() else None
        typeobj = self.target.FindFirstType(name)
        #warn("LOOKUP RESULT: %s" % typeobj.name)
        #warn("LOOKUP VALID: %s" % typeobj.IsValid())
        if typeobj.IsValid():
            return typeobj
        try:
            if len(self.types_) == 0:
                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())
                        self.types_[n] = t
            return self.types_.get(self.canonicalTypeName(name))
        except:
            pass
        return None
664

665
    def setupInferior(self, args):
666
        error = lldb.SBError()
667
668

        self.executable_ = args['executable']
669
670
671
        self.startMode_ = args.get('startMode', 1)
        self.processArgs_ = args.get('processArgs', '')
        self.attachPid_ = args.get('attachPid', 0)
Fawzi Mohamed's avatar
Fawzi Mohamed committed
672
        self.sysRoot_ = args.get('sysRoot', '')
Fawzi Mohamed's avatar
Fawzi Mohamed committed
673
        self.remoteChannel_ = args.get('remoteChannel', '')
674
        self.platform_ = args.get('platform', '')
675

676
677
        if self.platform_:
            self.debugger.SetCurrentPlatform(self.platform_)
Fawzi Mohamed's avatar
Fawzi Mohamed committed
678
679
680
        # sysroot has to be set *after* the platform
        if self.sysRoot_:
            self.debugger.SetCurrentPlatformSDKRoot(self.sysRoot_)
681
        self.target = self.debugger.CreateTarget(self.executable_, None, None, True, error)
682
683
        self.importDumpers()

684
685
        state = "inferiorsetupok" if self.target.IsValid() else "inferiorsetupfailed"
        self.report('state="%s",msg="%s",exe="%s"' % (state, error, self.executable_))
686

687
    def runEngine(self, _):
hjk's avatar
hjk committed
688
689
690
691
        s = threading.Thread(target=self.loop, args=[])
        s.start()

    def loop(self):
692
        error = lldb.SBError()
hjk's avatar
hjk committed
693
694
        listener = self.debugger.GetListener()

695
696
697
        if self.attachPid_ > 0:
            attachInfo = lldb.SBAttachInfo(self.attachPid_)
            self.process = self.target.Attach(attachInfo, error)
698
            if not error.Success():
Fawzi Mohamed's avatar
Fawzi Mohamed committed
699
700
701
                self.report('state="inferiorrunfailed"')
                return
            self.report('pid="%s"' % self.process.GetProcessID())
702
703
704
705
            # 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.report('state="enginerunandinferiorrunok"')
Fawzi Mohamed's avatar
Fawzi Mohamed committed
706
707
708
709
        elif len(self.remoteChannel_) > 0:
            self.process = self.target.ConnectRemote(
            self.debugger.GetListener(),
            self.remoteChannel_, None, error)
710
711
712
            if not error.Success():
                self.report('state="inferiorrunfailed"')
                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.report('state="enginerunandinferiorrunok"')
717
        else:
718
            launchInfo = lldb.SBLaunchInfo(self.processArgs_.split())
719
            launchInfo.SetWorkingDirectory(os.getcwd())
720
721
            environmentList = [key + "=" + value for key,value in os.environ.items()]
            launchInfo.SetEnvironmentEntries(environmentList, False)
722
            self.process = self.target.Launch(launchInfo, error)
723
            if not error.Success():
724
725
                self.reportError(error)
                self.report('state="enginerunfailed"')
Fawzi Mohamed's avatar
Fawzi Mohamed committed
726
727
728
                return
            self.report('pid="%s"' % self.process.GetProcessID())
            self.report('state="enginerunandinferiorrunok"')
729

hjk's avatar
hjk committed
730
731
732
733
734
735
        event = lldb.SBEvent()
        while True:
            if listener.WaitForEvent(10000000, event):
                self.handleEvent(event)
            else:
                warn('TIMEOUT')
736

737
    def describeError(self, error):
738
739
740
741
742
743
        desc = lldb.SBStream()
        error.GetDescription(desc)
        result = 'error={type="%s"' % error.GetType()
        result += ',code="%s"' % error.GetError()
        result += ',msg="%s"' % error.GetCString()
        result += ',desc="%s"}' % desc.GetData()
744
745
746
747
        return result

    def reportError(self, error):
        self.report(self.describeError(error))
748
749

    def currentThread(self):
750
        return self.process.GetSelectedThread()
751
752
753
754
755
756

    def currentFrame(self):
        return self.currentThread().GetSelectedFrame()

    def reportLocation(self):
        thread = self.currentThread()
757
        frame = thread.GetSelectedFrame()
758
759
760
761
        file = fileName(frame.line_entry.file)
        line = frame.line_entry.line
        self.report('location={file="%s",line="%s",addr="%s"}' % (file, line, frame.pc))

762
763
764
    def firstStoppedThread(self):
        for i in xrange(0, self.process.GetNumThreads()):
            thread = self.process.GetThreadAtIndex(i)
765
766
767
768
769
770
            reason = thread.GetStopReason()
            if (reason == lldb.eStopReasonBreakpoint or
                    reason == lldb.eStopReasonException or
                    reason == lldb.eStopReasonPlanComplete or
                    reason == lldb.eStopReasonSignal or
                    reason == lldb.eStopReasonWatchpoint):
771
772
773
                return thread
        return None

774
    def reportThreads(self):
775
776
        reasons = ['None', 'Trace', 'Breakpoint', 'Watchpoint', 'Signal', 'Exception',
            'Exec', 'PlanComplete']
777
        result = 'threads={threads=['
778
        for i in xrange(0, self.process.GetNumThreads()):
779
            thread = self.process.GetThreadAtIndex(i)
780
            stopReason = thread.GetStopReason()
781
782
            result += '{id="%d"' % thread.GetThreadID()
            result += ',index="%s"' % i
783
            result += ',details="%s"' % thread.GetQueueName()
784
785
786
            result += ',stop-reason="%s"' % stopReason
            if stopReason >= 0 and stopReason < len(reasons):
                result += ',state="%s"' % reasons[stopReason]
787
            result += ',name="%s"' % thread.GetName()
788
789
790
791
792
            result += ',frame={'
            frame = thread.GetFrameAtIndex(0)
            result += 'pc="0x%x"' % frame.pc
            result += ',addr="0x%x"' % frame.pc
            result += ',fp="0x%x"' % frame.fp
793
            result += ',func="%s"' % frame.GetFunctionName()
794
795
796
797
798
799
800
801
            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)

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

hjk's avatar
hjk committed
811
    def reportStack(self, _ = None):
812
        if not self.process:
813
            self.report('msg="No process"')
814
815
816
817
818
819
820
821
            return
        thread = self.currentThread()
        if not thread:
            self.report('msg="No thread"')
            return
        frame = thread.GetSelectedFrame()
        if frame:
            frameId = frame.GetFrameID()
822
        else:
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
            frameId = 0;
        result = 'stack={current-frame="%s"' % frameId
        result += ',current-thread="%s"' % thread.GetThreadID()
        result += ',frames=['
        n = thread.GetNumFrames()
        for i in xrange(n):
            frame = thread.GetFrameAtIndex(i)
            lineEntry = frame.GetLineEntry()
            line = lineEntry.GetLine()
            usable = line != 0
            result += '{pc="0x%x"' % frame.GetPC()
            result += ',level="%d"' % frame.idx
            result += ',addr="0x%x"' % frame.GetPCAddress().GetLoadAddress(self.target)
            result += ',func="%s"' % frame.GetFunctionName()
            result += ',line="%d"' % line
            result += ',fullname="%s"' % fileName(lineEntry.file)
            result += ',usable="%d"' % usable
            result += ',file="%s"},' % fileName(lineEntry.file)
        result += '],hasmore="0"},'
        self.report(result)
843

844
845
846
847
848
    def putBetterType(self, type):
        try:
            self.currentType = type.GetName()
        except:
            self.currentType = str(type)
849
        self.currentTypePriority = self.currentTypePriority + 1
hjk's avatar
hjk committed
850
        #warn("BETTER TYPE: %s PRIORITY: %s" % (type, self.currentTypePriority))
hjk's avatar
hjk committed
851

hjk's avatar
hjk committed
852
    def extractBlob(self, base, size):
hjk's avatar
hjk committed
853
        if size == 0:
hjk's avatar
hjk committed
854
            return Blob("")
855
856
        base = int(base) & 0xFFFFFFFFFFFFFFFF
        size = int(size) & 0xFFFFFFFF
hjk's avatar
hjk committed
857
        error = lldb.SBError()
hjk's avatar
hjk committed
858
        return Blob(self.process.ReadMemory(base, size, error))
hjk's avatar
hjk committed
859

hjk's avatar
hjk committed
860
861
862
863
864
865
866
867
868
869
870
    def isQObject(self, value):
        try:
            vtable = value.Cast(self.voidPtrType().GetPointerType())
            metaObjectEntry = vtable.Dereference()
            addr = lldb.SBAddress(long(metaObjectEntry), self.target)
            symbol = addr.GetSymbol()
            name = symbol.GetMangledName()
            return name.find("10metaObjectEv") > 0
        except:
            return False

871
872
873
    def stripNamespaceFromType(self, typeName):
        #type = stripClassTag(typeName)
        type = typeName
874
875
876
        ns = self.qtNamespace()
        if len(ns) > 0 and type.startswith(ns):
            type = type[len(ns):]
877
878
879
880
881
882
        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
883
884
885
886
        if type.startswith("const "):
            type = type[6:]
        if type.startswith("volatile "):
            type = type[9:]
887
888
889
        return type

    def putSubItem(self, component, value, tryDynamic=True):
890
        if not value.IsValid():
hjk's avatar
hjk committed
891
            warn("INVALID SUBITEM")
892
            return
893
894
895
        with SubItem(self, component):
            self.putItem(value, tryDynamic)

hjk's avatar
hjk committed
896
    def putAddress(self, addr):
897
898
899
900
        #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
901

hjk's avatar
hjk committed
902
903
904
    def isFunctionType(self, type):
        return type.IsFunctionType()

905
    def putItem(self, value, tryDynamic=True):
hjk's avatar
hjk committed
906
        #value = value.GetDynamicValue(lldb.eDynamicCanRunTarget)
907
        typeName = value.GetType().GetUnqualifiedType().GetName()
908
        value.SetPreferDynamicValue(tryDynamic)
hjk's avatar
hjk committed
909
        typeClass = value.GetType().GetTypeClass()
910

hjk's avatar
hjk committed
911
        if tryDynamic:
912
            self.putAddress(value.GetLoadAddress())
hjk's avatar
hjk committed
913

914
        # Handle build-in LLDB visualizers if wanted.
915
        if False and self.useLldbDumpers and value.GetTypeSynthetic().IsValid():
916
917
918
919
920
921
922
923
924
925
            # FIXME: print "official" summary?
            summary = value.GetTypeSummary()
            if summary.IsValid():
                warn("DATA: %s" % summary.GetData())
            value.SetPreferSyntheticValue(False)
            provider = value.GetTypeSynthetic()
            data = provider.GetData()
            formatter = eval(data)(value, {})
            formatter.update()
            numchild = formatter.num_children()
hjk's avatar
hjk committed
926
            self.put('iname="%s",' % self.currentIName)
hjk's avatar
hjk committed
927
            self.putType(typeName)
hjk's avatar
hjk committed
928
929
            self.put('numchild="%s",' % numchild)
            self.put('addr="0x%x",' % value.GetLoadAddress())
930
            self.putItemCount(numchild)
hjk's avatar
hjk committed
931
932
            if self.currentIName in self.expandedINames:
                with Children(self):
933
934
935
936
937
938
                    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
939
940
        # Typedefs
        if typeClass == lldb.eTypeClassTypedef:
941
            if typeName in self.qqDumpers:
hjk's avatar
hjk committed
942
943
                self.putType(typeName)
                self.context = value
944
                self.qqDumpers[typeName](self, value)
hjk's avatar
hjk committed
945
                return
hjk's avatar
hjk committed
946
947
            realType = value.GetType()
            if hasattr(realType, 'GetCanonicalType'):
948
949
950
951
                baseType = realType.GetCanonicalType()
                baseValue = value.Cast(baseType.unqualified())
                self.putItem(baseValue)
                self.putBetterType(realType)
hjk's avatar
hjk committed
952
                return
hjk's avatar
hjk committed
953

954
        # Our turf now.
955
        value.SetPreferSyntheticValue(False)
956

957
        # Arrays
hjk's avatar
hjk committed
958
        if typeClass == lldb.eTypeClassArray:
959
            self.putCStyleArray(value)
960
961
            return

962
963
        # Vectors like char __attribute__ ((vector_size (8)))
        if typeClass == lldb.eTypeClassVector:
964
            self.putCStyleArray(value)
965
966
            return

967
968
        # References
        if value.GetType().IsReferenceType():
hjk's avatar
hjk committed
969
            origType = value.GetTypeName();
hjk's avatar
hjk committed
970
            type = value.GetType().GetDereferencedType().unqualified()
hjk's avatar
hjk committed
971
            addr = int(value) & 0xFFFFFFFFFFFFFFFF
hjk's avatar
hjk committed
972
            self.putItem(value.CreateValueFromAddress(None, addr, type))
hjk's avatar
hjk committed
973
            self.putBetterType(origType)
974
975
            return

hjk's avatar
hjk committed
976
        # Pointers
hjk's avatar
hjk committed
977
        if value.GetType().IsPointerType():
hjk's avatar
hjk committed
978
979
            self.putFormattedPointer(value)
            return
hjk's avatar
hjk committed
980

981
        #warn("VALUE: %s" % value)
hjk's avatar
hjk committed
982
983
984
985
        #warn("FANCY: %s" % self.useFancy)
        if self.useFancy:
            stripped = self.stripNamespaceFromType(typeName).replace("::", "__")
            #warn("STRIPPED: %s" % stripped)
986
987
            #warn("DUMPABLE: %s" % (stripped in self.qqDumpers))
            if stripped in self.qqDumpers:
hjk's avatar
hjk committed
988
                self.putType(typeName)
hjk's avatar
hjk committed
989
                self.context = value
990
                self.qqDumpers[stripped](self, value)
hjk's avatar
hjk committed
991
                return
992
993
994
995

        # Normal value
        #numchild = 1 if value.MightHaveChildren() else 0
        numchild = value.GetNumChildren()
hjk's avatar
hjk committed
996
        self.putType(typeName)
hjk's avatar
hjk committed
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
        if typeClass == lldb.eTypeClassStruct or typeClass == lldb.eTypeClassClass:
            if self.isQObject(value):
                self.context = value
                if not self.putQObjectNameValue(value):  # Is this too expensive?
                    self.putEmptyValue()
            else:
                self.putEmptyValue()
        else:
            v = value.GetValue()
            if v:
                self.putValue(v)
            else:
                self.putEmptyValue()

1011
        self.put('numchild="%s",' % numchild)
1012

1013
1014
1015
        if self.currentIName in self.expandedINames:
            with Children(self):
                self.putFields(value)
1016

1017
1018
1019
    def warn(self, msg):
        self.put('{name="%s",value="",type=""},' % msg)

1020
    def putFields(self, value):
1021
1022
1023
1024
        # Suppress printing of 'name' field for arrays.
        if value.GetType().GetTypeClass() == lldb.eTypeClassArray:
            for i in xrange(value.GetNumChildren()):
                child = value.GetChildAtIndex(i)
1025
                with UnnamedSubItem(self, str(i)):
1026
1027
1028
                    self.putItem(child)
            return

1029
        n = value.GetNumChildren()
1030
        m = value.GetType().GetNumberOfDirectBaseClasses()
1031
1032
        if n > 10000:
            n = 10000
1033
1034
1035
        # seems to happen in the 'inheritance' autotest
        if m > n:
            m = n
1036
1037
1038
        for i in xrange(m):
            child = value.GetChildAtIndex(i)
            with UnnamedSubItem(self, "@%d" % (i + 1)):
1039
                self.put('iname="%s",' % self.currentIName)
1040
1041
1042
                self.put('name="[%s]",' % child.name)
                self.putItem(child)
        for i in xrange(m, n):
1043
        #for i in range(n):
hjk's avatar
hjk committed
1044
            child = value.GetChildAtIndex(i)
1045
1046
1047
1048
1049
            if int(child.GetLoadAddress()) == 0xffffffffffffffff:
                typeClass = child.GetType().GetTypeClass()
                if typeClass != lldb.eTypeClassBuiltin:
                    field = value.GetType().GetFieldAtIndex(i)
                    addr = value.GetLoadAddress() + field.GetOffsetInBytes()
1050
                    child = value.CreateValueFromAddress(child.GetName(), addr, child.GetType())
hjk's avatar
hjk committed
1051
1052
1053
            if child.IsValid():  # FIXME: Anon members?
                with SubItem(self, child):
                    self.putItem(child)
1054

hjk's avatar
hjk committed
1055
    def reportVariables(self, _ = None):
1056
        frame = self.currentThread().GetSelectedFrame()
1057
        self.currentIName = 'local'
1058
        self.put('data=[')
1059
        self.anonNumber = 0
1060
        shadowed = {}