lldbbridge.py 56.4 KB
Newer Older
1
2
3
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
############################################################################
#
# Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
# 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 binascii
32
import inspect
33
import json
34
import os
35
import re
36
37
import select
import sys
38
import subprocess
39
import threading
40

41
42
43
44
45
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
46
47
48
from stdtypes import *
from misctypes import *
from boosttypes import *
49
from creatortypes import *
50

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

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

58
if error.startswith('lldb: invalid option -- P'):
59
    sys.stdout.write('msg=\'Could not run "%s -P". Trying to find lldb.so from Xcode.\'@\n' % lldbCmd)
60
61
62
63
64
    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/'
65
66
        sys.stdout.write('msg=\'Could not run "xcode-select --print-path"@\n')
        sys.stdout.write('msg=\'Using hardcoded fallback at %s\'@\n' % path)
67
68
    else:
        path = path.strip() + '/../SharedFrameworks/LLDB.framework/Versions/A/Resources/Python/'
69
        sys.stdout.write('msg=\'Using fallback at %s\'@\n' % path)
70

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

import lldb
74
75
76
77
78
79
80

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

81
qqWatchpointOffset = 10000
82

83
84

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

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

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

96

97
98
99
100
101
102
103
104
105
106
# 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
107
108
109
110
111
BreakpointAtSysCall = 9
WatchpointAtAddress = 10
WatchpointAtExpression = 11
BreakpointOnQmlSignalEmit = 12
BreakpointAtJavaScriptThrow = 13
112

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

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

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

126
127
Value = lldb.SBValue

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

        # We don't have a dumper object
        #return createPointerValue(self, address, self.GetType().GetPointeeType())
        addr = int(address) & 0xFFFFFFFFFFFFFFFF
        return self.CreateValueFromAddress(None, addr, self.GetType().GetPointeeType()).AddressOf()

143
    raise RuntimeError("SBValue.__add__ not implemented: %s" % self.GetType())
144
145
    return NotImplemented

146
def impl_SBValue__sub__(self, other):
147
    if self.GetType().IsPointerType():
148
149
150
151
        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())
152
        if other.GetType().IsPointerType():
153
154
            itemsize = self.GetType().GetPointeeType().GetByteSize()
            return (self.GetValueAsUnsigned() - other.GetValueAsUnsigned()) / itemsize
155
    raise RuntimeError("SBValue.__sub__ not implemented: %s" % self.GetType())
156
157
    return NotImplemented

158
159
160
161
162
163
164
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):
165
    return self.GetValueAsSigned()
166
167
168
169
170
171
172
173
174
175

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
176

177
178
179
def impl_SBValue__long__(self):
    return int(self.GetValue(), 0)

180
181
182
183
184
185
186
187
188
189
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)
    return value.GetChildMemberWithName(index)
190

191
lldb.SBValue.__add__ = impl_SBValue__add__
192
lldb.SBValue.__sub__ = impl_SBValue__sub__
193
lldb.SBValue.__le__ = impl_SBValue__le__
194

195
196
lldb.SBValue.__getitem__ = impl_SBValue__getitem__
lldb.SBValue.__int__ = impl_SBValue__int__
197
lldb.SBValue.__float__ = impl_SBValue__float__
198
199
lldb.SBValue.__long__ = lambda self: long(self.GetValue(), 0)

200
lldb.SBValue.code = lambda self: self.GetTypeClass()
201
202
lldb.SBValue.cast = lambda self, typeObj: self.Cast(typeObj)
lldb.SBValue.dereference = lambda self: self.Dereference()
203
lldb.SBValue.address = property(lambda self: self.GetAddress())
204
205

lldb.SBType.pointer = lambda self: self.GetPointerType()
hjk's avatar
hjk committed
206
lldb.SBType.target = lambda self: self.GetPointeeType()
207
lldb.SBType.code = lambda self: self.GetTypeClass()
208
lldb.SBType.sizeof = property(lambda self: self.GetByteSize())
209
210


hjk's avatar
hjk committed
211
212
lldb.SBType.unqualified = \
    lambda self: self.GetUnqualifiedType() if hasattr(self, 'GetUnqualifiedType') else self
213
214
lldb.SBType.strip_typedefs = \
    lambda self: self.GetCanonicalType() if hasattr(self, 'GetCanonicalType') else self
215

hjk's avatar
hjk committed
216
217
218
lldb.SBType.__orig__str__ = lldb.SBType.__str__
lldb.SBType.__str__ = lldb.SBType.GetName

219
220
221
222
def simpleEncoding(typeobj):
    code = typeobj.GetTypeClass()
    size = typeobj.sizeof
    if code == lldb.eTypeClassBuiltin:
hjk's avatar
hjk committed
223
224
225
226
227
228
        name = str(typeobj)
        if name == "float":
            return Hex2EncodedFloat4
        if name == "double":
            return Hex2EncodedFloat8
        if name.find("unsigned") >= 0:
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
            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
247

248
class Dumper(DumperBase):
249
    def __init__(self):
250
251
        DumperBase.__init__(self)

252
        self.debugger = lldb.SBDebugger.Create()
253
        #self.debugger.SetLoggingCallback(loggingCallback)
254
255
256
257
258
259
        #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")
260
261
262
263
264
265
266
267
268
269

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

270
        self.isLldb = True
271
272
273
274
        self.process = None
        self.target = None
        self.eventState = lldb.eStateInvalid
        self.expandedINames = {}
275
        self.passExceptions = False
276
        self.useLldbDumpers = False
hjk's avatar
hjk committed
277
        self.autoDerefPointers = True
278
        self.useDynamicType = True
hjk's avatar
hjk committed
279
        self.useFancy = True
hjk's avatar
hjk committed
280
281
282
        self.formats = {}
        self.typeformats = {}
        self.currentAddress = None
283
284
285
286
287
288

        self.currentIName = None
        self.currentValuePriority = -100
        self.currentValueEncoding = None
        self.currentType = ""
        self.currentTypePriority = -100
289
        self.currentValue = None
290
291
292
293
294
        self.currentNumChild = None
        self.currentMaxNumChild = None
        self.currentPrintsAddress = None
        self.currentChildType = None
        self.currentChildNumChild = None
295
        self.currentWatchers = {}
296

hjk's avatar
hjk committed
297
        self.executable_ = None
298
299
300
301
        self.startMode_ = None
        self.processArgs_ = None
        self.attachPid_ = None

302
303
        self.charType_ = None
        self.intType_ = None
304
        self.int64Type_ = None
305
306
        self.sizetType_ = None
        self.charPtrType_ = None
hjk's avatar
hjk committed
307
        self.voidPtrType_ = None
308
        self.isShuttingDown_ = False
309
        self.isInterrupting_ = False
310
        self.dummyValue = None
311

312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
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
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
    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
        item.iname = "%s.%s" % (self.currentIName, item.name)
        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.savedCurrentAddress = self.currentAddress
        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:
                    self.put('valueencoded="%d",' % self.currentValueEncoding)
                self.put('value="%s",' % self.currentValue)
        except:
            pass
        if not self.currentAddress is None:
            self.put(self.currentAddress)
        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
        self.currentAddress = item.savedCurrentAddress
        return True

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

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

    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

395
396
397
398
399
    def parseAndEvaluate(self, expr):
        thread = self.currentThread()
        frame = thread.GetFrameAtIndex(0)
        return frame.EvaluateExpression(expr)

400
401
402
403
404
405
406
407
408
409
410
411
412
    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)

413
    def templateArgument(self, typeobj, index):
414
        type = typeobj.GetTemplateArgumentType(index)
hjk's avatar
hjk committed
415
        if type.IsValid():
416
417
418
419
420
421
422
            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)
423

hjk's avatar
hjk committed
424
425
426
427
428
429
    def isReferenceType(self, typeobj):
        return typeobj.IsReferenceType()

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

430
    def qtVersion(self):
431
        self.cachedQtVersion = 0x0
432
433
434
435
436
437
438
439
        coreExpression = re.compile(r"(lib)?Qt5?Core")
        for n in range(0, self.target.GetNumModules()):
            module = self.target.GetModuleAtIndex(n)
            if coreExpression.match(module.GetFileSpec().GetFilename()):
                reverseVersion = module.GetVersion()
                reverseVersion.reverse()
                shift = 0
                for v in reverseVersion:
440
                    self.cachedQtVersion += v << shift
441
442
                    shift += 8
                break
443
444
445
446

        # Memoize good results.
        self.qtVersion = lambda: self.cachedQtVersion
        return self.cachedQtVersion
447

hjk's avatar
hjk committed
448
449
450
    def intSize(self):
        return 4

451
452
    def intType(self):
        if self.intType_ is None:
hjk's avatar
hjk committed
453
             self.intType_ = self.target.FindFirstType('int')
454
455
        return self.intType_

456
457
458
459
460
    def int64Type(self):
        if self.int64Type_ is None:
             self.int64Type_ = self.target.FindFirstType('long long int')
        return self.int64Type_

461
462
    def charType(self):
        if self.charType_ is None:
hjk's avatar
hjk committed
463
             self.charType_ = self.target.FindFirstType('char')
464
465
466
467
468
469
470
471
        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
472
473
474
        if self.voidPtrType_ is None:
             self.voidPtrType_ = self.target.FindFirstType('void').GetPointerType()
        return self.voidPtrType_
475

hjk's avatar
hjk committed
476
    def ptrSize(self):
477
478
479
480
481
482
483
        return self.charPtrType().GetByteSize()

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

484
485
486
    def addressOf(self, value):
        return int(value.GetLoadAddress())

hjk's avatar
hjk committed
487
488
489
490
491
492
493
494
495
    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()))

496
497
498
    def extractInt64(self, address):
        return int(self.createValue(address, self.int64Type()))

499
500
501
    def extractByte(self, address):
        return int(self.createValue(address, self.charType())) & 0xFF

502
503
504
505
506
507
    def handleCommand(self, command):
        result = lldb.SBCommandReturnObject()
        self.debugger.GetCommandInterpreter().HandleCommand(command, result)
        success = result.Succeeded()
        if success:
            self.report('output="%s"' % result.GetOutput())
508
        else:
509
510
511
512
513
514
            self.report('error="%s"' % result.GetError())
        self.reportData()

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

hjk's avatar
hjk committed
515
516
517
    def putField(self, name, value):
        self.put('%s="%s",' % (name, value))

518
    def isMovableType(self, type):
519
        if type.GetTypeClass() in (lldb.eTypeClassBuiltin, lldb.eTypeClassPointer):
520
            return True
521
        return self.isKnownMovableType(self.stripNamespaceFromType(type.GetName()))
522

523
524
    def putNumChild(self, numchild):
        #warn("NUM CHILD: '%s' '%s'" % (numchild, self.currentChildNumChild))
hjk's avatar
hjk committed
525
526
        #if numchild != self.currentChildNumChild:
        self.put('numchild="%s",' % numchild)
527

hjk's avatar
hjk committed
528
529
530
531
532
533
    def putEmptyValue(self, priority = -10):
        if priority >= self.currentValuePriority:
            self.currentValue = ""
            self.currentValuePriority = priority
            self.currentValueEncoding = None

hjk's avatar
hjk committed
534
535
536
    def putSimpleValue(self, value, encoding = None, priority = 0):
        self.putValue(value.GetValue(), encoding, priority)

537
538
539
540
541
542
    def putValue(self, value, encoding = None, priority = 0):
        # Higher priority values override lower ones.
        if priority >= self.currentValuePriority:
            self.currentValue = value
            self.currentValuePriority = priority
            self.currentValueEncoding = encoding
hjk's avatar
hjk committed
543
        #self.put('value="%s",' % value)
544

hjk's avatar
hjk committed
545
546
547
    def putName(self, name):
        self.put('name="%s",' % name)

548
549
550
551
552
553
    def isExpanded(self):
        #warn("IS EXPANDED: %s in %s: %s" % (self.currentIName,
        #    self.expandedINames, self.currentIName in self.expandedINames))
        return self.currentIName in self.expandedINames

    def tryPutArrayContents(self, typeobj, base, n):
554
        if not self.isSimpleType(typeobj):
555
556
557
            return False
        size = n * typeobj.sizeof
        self.put('childtype="%s",' % typeobj)
558
559
        self.put('addrbase="0x%x",' % int(base))
        self.put('addrstep="%d",' % typeobj.sizeof)
560
561
        self.put('arrayencoding="%s",' % simpleEncoding(typeobj))
        self.put('arraydata="')
562
        self.put(self.readMemory(base, size))
563
564
565
566
        self.put('",')
        return True

    def putPlotData(self, type, base, n, plotFormat):
hjk's avatar
hjk committed
567
        #warn("PLOTDATA: %s %s" % (type, n))
568
569
        if self.isExpanded():
            self.putArrayData(type, base, n)
hjk's avatar
hjk committed
570
571
        self.putValue(self.currentValue)
        self.putField("plottable", "0")
572
573
574
575

    def putArrayData(self, type, base, n,
            childNumChild = None, maxNumChild = 10000):
        if not self.tryPutArrayContents(type, base, n):
576
            base = self.createPointerValue(base, type)
577
578
579
580
581
            with Children(self, n, type, childNumChild, maxNumChild,
                    base, type.GetByteSize()):
                for i in self.childRange():
                    self.putSubItem(i, (base + i).dereference())

582
583
584
    def parseAndEvalute(self, expr):
        return expr

585
586
587
588
589
590
591
592
    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)

593
    def putCallItem(self, name, value, func, *args):
594
        result = self.call2(value, func, args)
595
596
597
        with SubItem(self, name):
            self.putItem(result)

598
599
600
601
602
    def childRange(self):
        if self.currentMaxNumChild is None:
            return xrange(0, self.currentNumChild)
        return xrange(min(self.currentMaxNumChild, self.currentNumChild))

hjk's avatar
hjk committed
603
604
605
606
607
608
609
    def putPlainChildren(self, value):
        self.putEmptyValue(-99)
        self.putNumChild(1)
        if self.currentIName in self.expandedINames:
            with Children(self):
               self.putFields(value)

610
    def lookupType(self, name):
hjk's avatar
hjk committed
611
        #warn("LOOKUP TYPE NAME: %s" % name)
hjk's avatar
hjk committed
612
613
614
615
        if name.endswith('*'):
            type = self.lookupType(name[:-1].strip())
            return type.GetPointerType() if type.IsValid() else None
        type = self.target.FindFirstType(name)
hjk's avatar
hjk committed
616
617
        #warn("LOOKUP RESULT: %s" % type.name)
        #warn("LOOKUP VALID: %s" % type.IsValid())
hjk's avatar
hjk committed
618
        return type if type.IsValid() else None
619

620
    def setupInferior(self, args):
621
        error = lldb.SBError()
622
623

        self.executable_ = args['executable']
624
625
626
        self.startMode_ = args.get('startMode', 1)
        self.processArgs_ = args.get('processArgs', '')
        self.attachPid_ = args.get('attachPid', 0)
Fawzi Mohamed's avatar
Fawzi Mohamed committed
627
        self.sysRoot_ = args.get('sysRoot', '')
Fawzi Mohamed's avatar
Fawzi Mohamed committed
628
        self.remoteChannel_ = args.get('remoteChannel', '')
629
        self.platform_ = args.get('platform', '')
630

631
        if self.sysRoot_:
Fawzi Mohamed's avatar
Fawzi Mohamed committed
632
            self.debugger.SetCurrentPlatformSDKRoot(self.sysRoot_)
633
634
        if self.platform_:
            self.debugger.SetCurrentPlatform(self.platform_)
635
        self.target = self.debugger.CreateTarget(self.executable_, None, None, True, error)
636
637
        self.importDumpers()

638
639
        state = "inferiorsetupok" if self.target.IsValid() else "inferiorsetupfailed"
        self.report('state="%s",msg="%s",exe="%s"' % (state, error, self.executable_))
640

641
    def runEngine(self, _):
hjk's avatar
hjk committed
642
643
644
645
        s = threading.Thread(target=self.loop, args=[])
        s.start()

    def loop(self):
646
        error = lldb.SBError()
hjk's avatar
hjk committed
647
648
        listener = self.debugger.GetListener()

649
650
651
        if self.attachPid_ > 0:
            attachInfo = lldb.SBAttachInfo(self.attachPid_)
            self.process = self.target.Attach(attachInfo, error)
652
            if not error.Success():
Fawzi Mohamed's avatar
Fawzi Mohamed committed
653
654
655
656
657
658
659
660
                self.report('state="inferiorrunfailed"')
                return
            self.report('pid="%s"' % self.process.GetProcessID())
            self.report('state="enginerunandinferiorstopok"')
        elif len(self.remoteChannel_) > 0:
            self.process = self.target.ConnectRemote(
            self.debugger.GetListener(),
            self.remoteChannel_, None, error)
661
662
663
            if not error.Success():
                self.report('state="inferiorrunfailed"')
                return
Fawzi Mohamed's avatar
Fawzi Mohamed committed
664
            self.report('state="enginerunandinferiorstopok"')
665
666
667
        else:
            launchInfo = lldb.SBLaunchInfo(self.processArgs_.split(' '))
            launchInfo.SetWorkingDirectory(os.getcwd())
668
669
            environmentList = [key + "=" + value for key,value in os.environ.items()]
            launchInfo.SetEnvironmentEntries(environmentList, False)
670
            self.process = self.target.Launch(launchInfo, error)
671
            if not error.Success():
Fawzi Mohamed's avatar
Fawzi Mohamed committed
672
673
674
675
                self.report('state="inferiorrunfailed"')
                return
            self.report('pid="%s"' % self.process.GetProcessID())
            self.report('state="enginerunandinferiorrunok"')
676

hjk's avatar
hjk committed
677
678
679
680
681
682
        event = lldb.SBEvent()
        while True:
            if listener.WaitForEvent(10000000, event):
                self.handleEvent(event)
            else:
                warn('TIMEOUT')
683

684
    def describeError(self, error):
685
686
687
688
689
690
        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()
691
692
693
694
        return result

    def reportError(self, error):
        self.report(self.describeError(error))
695
696

    def currentThread(self):
697
        return self.process.GetSelectedThread()
698
699
700
701
702
703

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

    def reportLocation(self):
        thread = self.currentThread()
704
        frame = thread.GetSelectedFrame()
705
706
707
708
709
        file = fileName(frame.line_entry.file)
        line = frame.line_entry.line
        self.report('location={file="%s",line="%s",addr="%s"}' % (file, line, frame.pc))

    def reportThreads(self):
710
711
        reasons = ['None', 'Trace', 'Breakpoint', 'Watchpoint', 'Signal', 'Exception',
            'Exec', 'PlanComplete']
712
        result = 'threads={threads=['
713
        for i in xrange(0, self.process.GetNumThreads()):
714
            thread = self.process.GetThreadAtIndex(i)
715
            stopReason = thread.GetStopReason()
716
717
            result += '{id="%d"' % thread.GetThreadID()
            result += ',index="%s"' % i
718
            result += ',details="%s"' % thread.GetQueueName()
719
720
721
            result += ',stop-reason="%s"' % stopReason
            if stopReason >= 0 and stopReason < len(reasons):
                result += ',state="%s"' % reasons[stopReason]
722
            result += ',name="%s"' % thread.GetName()
723
724
725
726
727
            result += ',frame={'
            frame = thread.GetFrameAtIndex(0)
            result += 'pc="0x%x"' % frame.pc
            result += ',addr="0x%x"' % frame.pc
            result += ',fp="0x%x"' % frame.fp
728
            result += ',func="%s"' % frame.GetFunctionName()
729
730
731
732
733
734
735
736
            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)

hjk's avatar
hjk committed
737
738
    def firstUsableFrame(self):
        thread = self.currentThread()
hjk's avatar
hjk committed
739
        for i in xrange(10):
hjk's avatar
hjk committed
740
741
742
743
744
745
746
            frame = thread.GetFrameAtIndex(i)
            lineEntry = frame.GetLineEntry()
            line = lineEntry.GetLine()
            if line != 0:
                return i
        return None

hjk's avatar
hjk committed
747
    def reportStack(self, _ = None):
748
        if not self.process:
749
            self.report('msg="No process"')
750
751
752
753
754
755
756
757
            return
        thread = self.currentThread()
        if not thread:
            self.report('msg="No thread"')
            return
        frame = thread.GetSelectedFrame()
        if frame:
            frameId = frame.GetFrameID()
758
        else:
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
            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)
779

780
781
782
783
784
    def putType(self, type, priority = 0):
        # Higher priority values override lower ones.
        if priority >= self.currentTypePriority:
            self.currentType = str(type)
            self.currentTypePriority = priority
hjk's avatar
hjk committed
785
        #warn("TYPE: %s PRIORITY: %s" % (type, priority))
786

787
788
789
790
791
    def putBetterType(self, type):
        try:
            self.currentType = type.GetName()
        except:
            self.currentType = str(type)
792
        self.currentTypePriority = self.currentTypePriority + 1
hjk's avatar
hjk committed
793
        #warn("BETTER TYPE: %s PRIORITY: %s" % (type, self.currentTypePriority))
hjk's avatar
hjk committed
794

795
    def readMemory(self, base, size):
hjk's avatar
hjk committed
796
797
        if size == 0:
            return ""
798
799
        base = int(base) & 0xFFFFFFFFFFFFFFFF
        size = int(size) & 0xFFFFFFFF
hjk's avatar
hjk committed
800
        error = lldb.SBError()
801
        contents = self.process.ReadMemory(base, size, error)
hjk's avatar
hjk committed
802
803
        return binascii.hexlify(contents)

hjk's avatar
hjk committed
804
805
806
807
808
809
810
811
812
813
814
    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

hjk's avatar
hjk committed
815
816
    def putValue(self, value, encoding = None, priority = 0):
        # Higher priority values override lower ones.
817
818
819
820
        if priority >= self.currentValuePriority:
            self.currentValue = value
            self.currentValuePriority = priority
            self.currentValueEncoding = encoding
hjk's avatar
hjk committed
821

822
823
824
825
    def qtNamespace(self):
        # FIXME
        return ""

826
827
828
    def stripNamespaceFromType(self, typeName):
        #type = stripClassTag(typeName)
        type = typeName
829
830
831
        #ns = qtNamespace()
        #if len(ns) > 0 and type.startswith(ns):
        #    type = type[len(ns):]
832
833
834
835
836
837
        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
838
839
840
841
        if type.startswith("const "):
            type = type[6:]
        if type.startswith("volatile "):
            type = type[9:]
842
843
844
        return type

    def putSubItem(self, component, value, tryDynamic=True):
845
        if not value.IsValid():
hjk's avatar
hjk committed
846
            warn("INVALID SUBITEM")
847
            return
848
849
850
        with SubItem(self, component):
            self.putItem(value, tryDynamic)

hjk's avatar
hjk committed
851
852
853
854
855
856
857
    def putAddress(self, addr):
        if self.currentPrintsAddress:
            try:
                self.currentAddress = 'addr="0x%s",' % int(addr)
            except:
                pass

hjk's avatar
hjk committed
858
859
860
    def isFunctionType(self, type):
        return type.IsFunctionType()

861
    def putItem(self, value, tryDynamic=True):
hjk's avatar
hjk committed
862
863
        #value = value.GetDynamicValue(lldb.eDynamicCanRunTarget)
        typeName = value.GetTypeName()
864
        value.SetPreferDynamicValue(tryDynamic)
hjk's avatar
hjk committed
865
        typeClass = value.GetType().GetTypeClass()
866

hjk's avatar
hjk committed
867
868
869
        if tryDynamic:
            self.putAddress(value.address)

870
        # Handle build-in LLDB visualizers if wanted.
871
        if self.useLldbDumpers and value.GetTypeSynthetic().IsValid():
872
873
874
875
876
877
878
879
880
881
            # 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
882
            self.put('iname="%s",' % self.currentIName)
hjk's avatar
hjk committed
883
            self.putType(typeName)
hjk's avatar
hjk committed
884
885
            self.put('numchild="%s",' % numchild)
            self.put('addr="0x%x",' % value.GetLoadAddress())
886
            self.putItemCount(numchild)
hjk's avatar
hjk committed
887
888
            if self.currentIName in self.expandedINames:
                with Children(self):
889
890
891
892
893
894
                    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
895
896
        # Typedefs
        if typeClass == lldb.eTypeClassTypedef:
897
            if typeName in self.qqDumpers:
hjk's avatar
hjk committed
898
899
                self.putType(typeName)
                self.context = value
900
                self.qqDumpers[typeName](self, value)
hjk's avatar
hjk committed
901
                return
hjk's avatar
hjk committed
902
903
904
905
906
907
908
            realType = value.GetType()
            if hasattr(realType, 'GetCanonicalType'):
                realType = realType.GetCanonicalType()
                value = value.Cast(realType.unqualified())
                self.putItem(value)
                self.putBetterType(typeName)
                return
hjk's avatar
hjk committed
909

910
        # Our turf now.
911
        value.SetPreferSyntheticValue(False)
912

913
        # Arrays
hjk's avatar
hjk committed
914
        if typeClass == lldb.eTypeClassArray:
915
            self.putCStyleArray(value)
916
917
            return

918
919
        # Vectors like char __attribute__ ((vector_size (8)))
        if typeClass == lldb.eTypeClassVector:
920
            self.putCStyleArray(value)
921
922
            return

923
924
        # References
        if value.GetType().IsReferenceType():
hjk's avatar
hjk committed
925
            origType = value.GetTypeName();
hjk's avatar
hjk committed
926
            type = value.GetType().GetDereferencedType().unqualified()
hjk's avatar
hjk committed
927
            addr = int(value) & 0xFFFFFFFFFFFFFFFF
hjk's avatar
hjk committed
928
            self.putItem(value.CreateValueFromAddress(None, addr, type))
hjk's avatar
hjk committed
929
            #self.putItem(value.CreateValueFromData(None, value.GetData(), type))
hjk's avatar
hjk committed
930
            self.putBetterType(origType)
931
932
            return

hjk's avatar
hjk committed
933
        # Pointers
hjk's avatar
hjk committed
934
        if value.GetType().IsPointerType():
hjk's avatar
hjk committed
935
936
            self.putFormattedPointer(value)
            return
hjk's avatar
hjk committed
937

938
        #warn("VALUE: %s" % value)
hjk's avatar
hjk committed
939
940
941
942
        #warn("FANCY: %s" % self.useFancy)
        if self.useFancy:
            stripped = self.stripNamespaceFromType(typeName).replace("::", "__")
            #warn("STRIPPED: %s" % stripped)
943
944
            #warn("DUMPABLE: %s" % (stripped in self.qqDumpers))
            if stripped in self.qqDumpers:
hjk's avatar
hjk committed
945
                self.putType(typeName)
hjk's avatar
hjk committed
946
                self.context = value
947
                self.qqDumpers[stripped](self, value)
hjk's avatar
hjk committed
948
                return
949
950
951
952

        # Normal value
        #numchild = 1 if value.MightHaveChildren() else 0
        numchild = value.GetNumChildren()
hjk's avatar
hjk committed
953
        self.putType(typeName)
hjk's avatar
hjk committed
954
955
956
957
958
959
960
961
962
963
964
965
966
967
        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()

968
969
970
971
972
        self.put('numchild="%s",' % numchild)
        self.put('addr="0x%x",' % value.GetLoadAddress())
        if self.currentIName in self.expandedINames:
            with Children(self):
                self.putFields(value)
973
974

    def putFields(self, value):
975
976
977
978
        # Suppress printing of 'name' field for arrays.
        if value.GetType().GetTypeClass() == lldb.eTypeClassArray:
            for i in xrange(value.GetNumChildren()):
                child = value.GetChildAtIndex(i)
979
                with UnnamedSubItem(self, str(i)):
980
981
982
                    self.putItem(child)
            return

983
        n = value.GetNumChildren()
984
        m = value.GetType().GetNumberOfDirectBaseClasses()
985
986
        if n > 10000:
            n = 10000
987
988
989
        # seems to happen in the 'inheritance' autotest
        if m > n:
            m = n
990
991
992
        for i in xrange(m):
            child = value.GetChildAtIndex(i)
            with UnnamedSubItem(self, "@%d" % (i + 1)):
993
                self.put('iname="%s",' % self.currentIName)
994
995
996
                self.put('name="[%s]",' % child.name)
                self.putItem(child)
        for i in xrange(m, n):
hjk's avatar
hjk committed
997
            child = value.GetChildAtIndex(i)
hjk's avatar
hjk committed
998
999
1000
            if child.IsValid():  # FIXME: Anon members?
                with SubItem(self, child):
                    self.putItem(child)
1001

hjk's avatar
hjk committed
1002
    def reportVariables(self, _ = None):
1003
        frame = self.currentThread().GetSelectedFrame()
1004
        self.currentIName = 'local'
1005
        self.put('data=[')
1006
        self.anonNumber = 0
1007
1008
1009
1010
        shadowed = {}
        values = [v for v in frame.GetVariables(True, True, False, False) if v.IsValid()]
        values.reverse() # To get shadowed vars numbered backwards.
        for value in values:
1011
1012
            if self.dummyValue is None:
                self.dummyValue = value
1013
1014
            name = value.GetName()
            if name in shadowed:
1015
1016
1017
1018
1019
1020
1021
1022
                level = shadowed[name]
                shadowed[name] = level + 1
                name += "@%s" % level
            else:
                shadowed[name] = 1
            with SubItem(self, name):
                self.put('iname="%s",' % self.currentIName)
                self.putItem(value)
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041

        # 'watchers':[{'id':'watch.0','exp':'23'},...]
        if not self.dummyValue is None:
            for watcher in self.currentWatchers:
                iname = watcher['iname']
                index = iname[iname.find('.') + 1:]
                exp = binascii.unhexlify(watcher['exp'])
                if exp == "":
                    self.put('type="",value="",exp=""')
                    continue

                value = self.dummyValue.CreateValueFromExpression(iname, exp)
                self.currentIName = 'watch'
                with SubItem(self, index):
                    self.put('exp="%s",' % exp)
                    self.put('wname="%s",' % binascii.hexlify(exp))
                    self.put('iname="%s",' % self.currentIName)
                    self.putItem(value)

1042
1043
1044
        self.put(']')
        self.report('')

hjk's avatar
hjk committed
1045
    def reportData(self, _ = None):
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
        self.reportRegisters()
        if self.process is None:
            self.report('process="none"')
        else:
            state = self.process.GetState()
            if state == lldb.eStateStopped:
                self.reportStack()
                self.reportThreads()
                self.reportLocation()
                self.reportVariables()

1057
    def reportRegisters(self, _ = None):
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
        if self.process is None:
            self.report('process="none"')
        else:
            frame = self.currentFrame()
            result = 'registers=['
            for group in frame.GetRegisters():
                for reg in group:
                    result += '{name="%s"' % reg.GetName()
                    result += ',value="%s"' % reg.GetValue()
                    result += ',type="%s"},' % reg.GetType()
            result += ']'
            self.report(result)

    def report(self, stuff):
1072
        sys.stdout.write(stuff + "@\n")
1073

hjk's avatar
hjk committed
1074
    def interruptInferior(self, _ = None):
1075
1076
        if self.process is None:
            self.report('msg="No process"')