lldbbridge.py 63.1 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()
206
lldb.SBType.code = lambda self: self.GetTypeClass()
207
lldb.SBType.sizeof = property(lambda self: self.GetByteSize())
208
209


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

429
    def qtVersion(self):
430
        self.cachedQtVersion = 0x0
431
432
433
434
435
436
437
438
        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:
439
                    self.cachedQtVersion += v << shift
440
441
                    shift += 8
                break
442
443
444
445

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

536
537
538
539
540
541
    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
542
        #self.put('value="%s",' % value)
543

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

547
548
549
550
551
552
    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):
553
        if not self.isSimpleType(typeobj):
554
555
556
            return False
        size = n * typeobj.sizeof
        self.put('childtype="%s",' % typeobj)
557
558
        self.put('addrbase="0x%x",' % int(base))
        self.put('addrstep="%d",' % typeobj.sizeof)
559
560
        self.put('arrayencoding="%s",' % simpleEncoding(typeobj))
        self.put('arraydata="')
561
        self.put(self.readMemory(base, size))
562
563
564
565
        self.put('",')
        return True

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

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

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

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

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

597
598
599
600
601
    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
602
603
604
605
606
607
608
    def putPlainChildren(self, value):
        self.putEmptyValue(-99)
        self.putNumChild(1)
        if self.currentIName in self.expandedINames:
            with Children(self):
               self.putFields(value)

609
    def lookupType(self, name):
hjk's avatar
hjk committed
610
        #warn("LOOKUP TYPE NAME: %s" % name)
hjk's avatar
hjk committed
611
612
613
614
        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
615
616
        #warn("LOOKUP RESULT: %s" % type.name)
        #warn("LOOKUP VALID: %s" % type.IsValid())
hjk's avatar
hjk committed
617
        return type if type.IsValid() else None
618

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

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

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

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

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

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

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

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

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

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

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

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

    def reportLocation(self):
        thread = self.currentThread()
703
        frame = thread.GetSelectedFrame()
704
705
706
707
708
        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):
709
710
        reasons = ['None', 'Trace', 'Breakpoint', 'Watchpoint', 'Signal', 'Exception',
            'Exec', 'PlanComplete']
711
        result = 'threads={threads=['
712
        for i in xrange(0, self.process.GetNumThreads()):
713
            thread = self.process.GetThreadAtIndex(i)
714
            stopReason = thread.GetStopReason()
715
716
            result += '{id="%d"' % thread.GetThreadID()
            result += ',index="%s"' % i
717
            result += ',details="%s"' % thread.GetQueueName()
718
719
720
            result += ',stop-reason="%s"' % stopReason
            if stopReason >= 0 and stopReason < len(reasons):
                result += ',state="%s"' % reasons[stopReason]
721
            result += ',name="%s"' % thread.GetName()
722
723
724
725
726
            result += ',frame={'
            frame = thread.GetFrameAtIndex(0)
            result += 'pc="0x%x"' % frame.pc
            result += ',addr="0x%x"' % frame.pc
            result += ',fp="0x%x"' % frame.fp
727
            result += ',func="%s"' % frame.GetFunctionName()
728
729
730
731
732
733
734
735
            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
736
737
    def firstUsableFrame(self):
        thread = self.currentThread()
hjk's avatar
hjk committed
738
        for i in xrange(10):
hjk's avatar
hjk committed
739
740
741
742
743
744
745
            frame = thread.GetFrameAtIndex(i)
            lineEntry = frame.GetLineEntry()
            line = lineEntry.GetLine()
            if line != 0:
                return i
        return None

hjk's avatar
hjk committed
746
    def reportStack(self, _ = None):
747
748
749
750
        if self.process is None:
            self.report('msg="No process"')
        else:
            thread = self.currentThread()
751
752
753
            result = 'stack={current-frame="%s"' % thread.GetSelectedFrame().GetFrameID()
            result += ',current-thread="%s"' % thread.GetThreadID()
            result += ',frames=['
754
755
            n = thread.GetNumFrames()
            for i in xrange(n):
756
757
                frame = thread.GetFrameAtIndex(i)
                lineEntry = frame.GetLineEntry()
758
759
                line = lineEntry.GetLine()
                usable = line != 0
760
                result += '{pc="0x%x"' % frame.GetPC()
761
                result += ',level="%d"' % frame.idx
762
                result += ',addr="0x%x"' % frame.GetPCAddress().GetLoadAddress(self.target)
763
                result += ',func="%s"' % frame.GetFunctionName()
764
                result += ',line="%d"' % line
765
                result += ',fullname="%s"' % fileName(lineEntry.file)
766
                result += ',usable="%d"' % usable
767
                result += ',file="%s"},' % fileName(lineEntry.file)
hjk's avatar
hjk committed
768
            result += '],hasmore="0"},'
769
770
            self.report(result)

771
772
773
774
775
    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
776
        #warn("TYPE: %s PRIORITY: %s" % (type, priority))
777

778
779
780
781
782
    def putBetterType(self, type):
        try:
            self.currentType = type.GetName()
        except:
            self.currentType = str(type)
783
        self.currentTypePriority = self.currentTypePriority + 1
hjk's avatar
hjk committed
784
        #warn("BETTER TYPE: %s PRIORITY: %s" % (type, self.currentTypePriority))
hjk's avatar
hjk committed
785

786
    def readMemory(self, base, size):
hjk's avatar
hjk committed
787
788
        if size == 0:
            return ""
789
790
        base = int(base) & 0xFFFFFFFFFFFFFFFF
        size = int(size) & 0xFFFFFFFF
hjk's avatar
hjk committed
791
        error = lldb.SBError()
792
        contents = self.process.ReadMemory(base, size, error)
hjk's avatar
hjk committed
793
794
        return binascii.hexlify(contents)

hjk's avatar
hjk committed
795
796
797
798
799
800
801
802
803
804
805
    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
806
807
    def putValue(self, value, encoding = None, priority = 0):
        # Higher priority values override lower ones.
808
809
810
811
        if priority >= self.currentValuePriority:
            self.currentValue = value
            self.currentValuePriority = priority
            self.currentValueEncoding = encoding
hjk's avatar
hjk committed
812

813
814
815
816
    def qtNamespace(self):
        # FIXME
        return ""

817
818
819
    def stripNamespaceFromType(self, typeName):
        #type = stripClassTag(typeName)
        type = typeName
820
821
822
        #ns = qtNamespace()
        #if len(ns) > 0 and type.startswith(ns):
        #    type = type[len(ns):]
823
824
825
826
827
828
        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
829
830
831
832
        if type.startswith("const "):
            type = type[6:]
        if type.startswith("volatile "):
            type = type[9:]
833
834
835
        return type

    def putSubItem(self, component, value, tryDynamic=True):
836
        if not value.IsValid():
hjk's avatar
hjk committed
837
            warn("INVALID SUBITEM")
838
            return
839
840
841
        with SubItem(self, component):
            self.putItem(value, tryDynamic)

hjk's avatar
hjk committed
842
843
844
845
846
847
848
    def putAddress(self, addr):
        if self.currentPrintsAddress:
            try:
                self.currentAddress = 'addr="0x%s",' % int(addr)
            except:
                pass

849
    def putItem(self, value, tryDynamic=True):
hjk's avatar
hjk committed
850
851
        #value = value.GetDynamicValue(lldb.eDynamicCanRunTarget)
        typeName = value.GetTypeName()
852
        value.SetPreferDynamicValue(tryDynamic)
hjk's avatar
hjk committed
853
        typeClass = value.GetType().GetTypeClass()
854

hjk's avatar
hjk committed
855
856
857
        if tryDynamic:
            self.putAddress(value.address)

858
        # Handle build-in LLDB visualizers if wanted.
859
        if self.useLldbDumpers and value.GetTypeSynthetic().IsValid():
860
861
862
863
864
865
866
867
868
869
            # 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
870
            self.put('iname="%s",' % self.currentIName)
hjk's avatar
hjk committed
871
            self.putType(typeName)
hjk's avatar
hjk committed
872
873
            self.put('numchild="%s",' % numchild)
            self.put('addr="0x%x",' % value.GetLoadAddress())
874
            self.putItemCount(numchild)
hjk's avatar
hjk committed
875
876
            if self.currentIName in self.expandedINames:
                with Children(self):
877
878
879
880
881
882
                    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
883
884
        # Typedefs
        if typeClass == lldb.eTypeClassTypedef:
885
            if typeName in self.qqDumpers:
hjk's avatar
hjk committed
886
887
                self.putType(typeName)
                self.context = value
888
                self.qqDumpers[typeName](self, value)
hjk's avatar
hjk committed
889
                return
hjk's avatar
hjk committed
890
891
892
893
894
895
896
            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
897

898
        # Our turf now.
899
        value.SetPreferSyntheticValue(False)
900

901
        # Arrays
hjk's avatar
hjk committed
902
        if typeClass == lldb.eTypeClassArray:
903
904
905
            qdump____c_style_array__(self, value)
            return

906
907
908
909
910
        # Vectors like char __attribute__ ((vector_size (8)))
        if typeClass == lldb.eTypeClassVector:
            qdump____c_style_array__(self, value)
            return

911
912
        # References
        if value.GetType().IsReferenceType():
hjk's avatar
hjk committed
913
            origType = value.GetTypeName();
hjk's avatar
hjk committed
914
            type = value.GetType().GetDereferencedType().unqualified()
hjk's avatar
hjk committed
915
            addr = int(value) & 0xFFFFFFFFFFFFFFFF
hjk's avatar
hjk committed
916
            self.putItem(value.CreateValueFromAddress(None, addr, type))
hjk's avatar
hjk committed
917
            #self.putItem(value.CreateValueFromData(None, value.GetData(), type))
hjk's avatar
hjk committed
918
            self.putBetterType(origType)
919
920
            return

hjk's avatar
hjk committed
921
        # Pointers
hjk's avatar
hjk committed
922
        if value.GetType().IsPointerType():
923
            if self.isNull(value):
hjk's avatar
hjk committed
924
925
926
927
928
                self.putType(typeName)
                self.putValue("0x0")
                self.putNumChild(0)
                return

hjk's avatar
hjk committed
929
930
931
932
933
934
935
936
937
            try:
                value.dereference()
            except:
                # Failure to dereference a pointer should at least
                # show the value of a pointer.
                self.putValue(cleanAddress(value))
                self.putType(typeName)
                self.putNumChild(0)
                return
hjk's avatar
hjk committed
938

hjk's avatar
hjk committed
939
940
941
942
            type = value.GetType()
            innerType = value.GetType().GetPointeeType().unqualified()
            innerTypeName = str(innerType)

943
            format = self.currentItemFormat(type)
hjk's avatar
hjk committed
944
945
946
947
948
949
950
951
952
953

            if innerTypeName == "void":
                warn("VOID POINTER: %s" % format)
                self.putType(typeName)
                self.putValue(str(value))
                self.putNumChild(0)
                return

            if format == None and innerTypeName == "char":
                # Use Latin1 as default for char *.
hjk's avatar
hjk committed
954
                self.putType(typeName)
hjk's avatar
hjk committed
955
956
957
958
959
960
961
962
963
                self.putValue(self.encodeCharArray(value), Hex2EncodedLatin1)
                self.putNumChild(0)
                return

            if format == 0:
                # Explicitly requested bald pointer.
                self.putType(typeName)
                self.putPointerValue(value)
                self.putNumChild(1)
hjk's avatar
hjk committed
964
965
                if self.currentIName in self.expandedINames:
                    with Children(self):
hjk's avatar
hjk committed
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
                        with SubItem(self, '*'):
                            self.putItem(value.dereference())
                return

            if format == 1:
                # Explicitly requested Latin1 formatting.
                self.putType(typeName)
                self.putValue(self.encodeCharArray(value), Hex2EncodedLatin1)
                self.putNumChild(0)
                return

            if format == 2:
                # Explicitly requested UTF-8 formatting.
                self.putType(typeName)
                self.putValue(self.encodeCharArray(value), Hex2EncodedUtf8)
                self.putNumChild(0)
                return

            if format == 3:
                # Explicitly requested local 8 bit formatting.
                self.putType(typeName)
                self.putValue(self.encodeCharArray(value), Hex2EncodedLocal8Bit)
                self.putNumChild(0)
                return

            if format == 4:
                # Explicitly requested UTF-16 formatting.
                self.putType(typeName)
                self.putValue(self.encodeChar2Array(value), Hex4EncodedLittleEndian)
                self.putNumChild(0)
                return

            if format == 5:
                # Explicitly requested UCS-4 formatting.
                self.putType(typeName)
                self.putValue(self.encodeChar4Array(value), Hex8EncodedLittleEndian)
                self.putNumChild(0)
                return

            if format == 6:
                # Explicitly requested formatting as array of 10 items.
                self.putType(typeName)
                self.putItemCount(10)
                self.putNumChild(10)
                self.putArrayData(innerType, value, 10)
                return

            if format == 7:
                # Explicitly requested formatting as array of 1000 items.
                self.putType(typeName)
                self.putItemCount(1000)
                self.putNumChild(1000)
                self.putArrayData(innerType, value, 1000)
                return

1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
            if innerType.IsFunctionType():
                # A function pointer.
                val = str(value)
                pos = val.find(" = ")
                if pos > 0:
                    val = val[pos + 3:]
                self.putValue(val)
                self.putType(innerType)
                self.putNumChild(0)
                return
hjk's avatar
hjk committed
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093

            #warn("AUTODEREF: %s" % self.autoDerefPointers)
            #warn("INAME: %s" % self.currentIName)
            if self.autoDerefPointers or self.currentIName.endswith('.this'):
                ## Generic pointer type with format None
                #warn("GENERIC AUTODEREF POINTER: %s AT %s TO %s"
                #    % (type, value.address, innerTypeName))
                # Never dereference char types.
                if innerTypeName != "char" \
                        and innerTypeName != "signed char" \
                        and innerTypeName != "unsigned char"  \
                        and innerTypeName != "wchar_t":
                    self.putType(innerType)
                    savedCurrentChildType = self.currentChildType
                    self.currentChildType = stripClassTag(innerTypeName)
                    self.putItem(value.dereference())
                    self.currentChildType = savedCurrentChildType
                    #self.putPointerValue(value)
                    self.put('origaddr="%s",' % value.address)
                    return

            # Fall back to plain pointer printing.
            #warn("GENERIC PLAIN POINTER: %s" % value.type)
            #warn("ADDR PLAIN POINTER: %s" % value.address)
            #self.putType(typeName)
            #self.putField("aaa", "1")
            ##self.put('addr="0x%x",' % toInteger(value.address))
            ##self.putAddress(value.address)
            #self.putField("bbb", "1")
            ##self.putPointerValue(value)
            #self.putValue("0x%x" % value.cast(self.lookupType("unsigned long")))
            #self.putField("ccc", "1")
            #self.putNumChild(1)
            #if self.currentIName in self.expandedINames:
            #    with Children(self):
            #        with SubItem(self, "*"):
            #            self.putItem(value.dereference())
            #return

            #if self.autoDerefPointers:
            #    self.putType(innerType)
            #    savedCurrentChildType = self.currentChildType
            #    self.currentChildType = str(innerType)
            #    inner = value.Dereference()
            #    if inner.IsValid():
            #        self.putItem(inner)
            #        self.currentChildType = savedCurrentChildType
            #        self.put('origaddr="%s",' % value.address)
            #        return
#
#            else:

            numchild = value.GetNumChildren()
            self.put('iname="%s",' % self.currentIName)
            self.putType(typeName)
            self.putValue('0x%x' % value.GetValueAsUnsigned())
            self.put('numchild="1",')
            self.put('addr="0x%x",' % value.GetLoadAddress())
            if self.currentIName in self.expandedINames:
                with Children(self):
                    child = value.Dereference()
                    with SubItem(self, child):
                        self.putItem(child)
hjk's avatar
hjk committed
1094

hjk's avatar
hjk committed
1095

1096
        #warn("VALUE: %s" % value)
hjk's avatar
hjk committed
1097
1098
1099
1100
        #warn("FANCY: %s" % self.useFancy)
        if self.useFancy:
            stripped = self.stripNamespaceFromType(typeName).replace("::", "__")
            #warn("STRIPPED: %s" % stripped)
1101
1102
            #warn("DUMPABLE: %s" % (stripped in self.qqDumpers))
            if stripped in self.qqDumpers:
hjk's avatar
hjk committed
1103
                self.putType(typeName)
hjk's avatar
hjk committed
1104
                self.context = value
1105
                self.qqDumpers[stripped](self, value)
hjk's avatar
hjk committed
1106
                return
1107
1108
1109
1110

        # Normal value
        #numchild = 1 if value.MightHaveChildren() else 0
        numchild = value.GetNumChildren()
hjk's avatar
hjk committed
1111
        self.putType(typeName)
hjk's avatar
hjk committed
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
        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()

1126
1127
1128
1129
1130
        self.put('numchild="%s",' % numchild)
        self.put('addr="0x%x",' % value.GetLoadAddress())
        if self.currentIName in self.expandedINames:
            with Children(self):
                self.putFields(value)
1131
1132

    def putFields(self, value):
1133
1134
1135
1136
        # Suppress printing of 'name' field for arrays.
        if value.GetType().GetTypeClass() == lldb.eTypeClassArray:
            for i in xrange(value.GetNumChildren()):
                child = value.GetChildAtIndex(i)
1137
                with UnnamedSubItem(self, str(i)):
1138
1139
1140
                    self.putItem(child)
            return

1141
        n = value.GetNumChildren()
1142
        m = value.GetType().GetNumberOfDirectBaseClasses()
1143
1144
        if n > 10000:
            n = 10000
1145
1146
1147
        # seems to happen in the 'inheritance' autotest
        if m > n:
            m = n
1148
1149
1150
        for i in xrange(m):
            child = value.GetChildAtIndex(i)
            with UnnamedSubItem(self, "@%d" % (i + 1)):
1151
                self.put('iname="%s",' % self.currentIName)
1152
1153
1154
                self.put('name="[%s]",' % child.name)
                self.putItem(child)
        for i in xrange(m, n):
hjk's avatar
hjk committed
1155
            child = value.GetChildAtIndex(i)
hjk's avatar
hjk committed
1156
1157
1158
            if child.IsValid():  # FIXME: Anon members?
                with SubItem(self, child):
                    self.putItem(child)
1159

hjk's avatar
hjk committed
1160
    def