lbridge.py 54.4 KB
Newer Older
1

2
import atexit
3
import binascii
4
5
import inspect
import os
6
7
8
import threading
import select
import sys
9
10
import subprocess

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
proc = subprocess.Popen(args=[sys.argv[1], '-P'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(path, error) = proc.communicate()

if error.startswith('lldb: invalid option -- P'):
    sys.stdout.write('msg=\'Could not run "%s -P". Trying to find lldb.so from Xcode.\'@\n' % sys.argv[1])
    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/'
        sys.stdout.write('msg=\'Could not run "xcode-select --print-path"@\n')
        sys.stdout.write('msg=\'Using hardcoded fallback at %s\'@\n' % path)
    else:
        path = path.strip() + '/../SharedFrameworks/LLDB.framework/Versions/A/Resources/Python/'
        sys.stdout.write('msg=\'Using fallback at %s\'@\n' % path)
26

27
#sys.path.append(path)
28
sys.path.insert(1, path.strip())
29
30

import lldb
31
32
33

cdbLoaded = False
gdbLoaded = False
34
lldbLoaded = True
35

hjk's avatar
hjk committed
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# Encodings. Keep that synchronized with DebuggerEncoding in watchutils.h
Unencoded8Bit, \
Base64Encoded8BitWithQuotes, \
Base64Encoded16BitWithQuotes, \
Base64Encoded32BitWithQuotes, \
Base64Encoded16Bit, \
Base64Encoded8Bit, \
Hex2EncodedLatin1, \
Hex4EncodedLittleEndian, \
Hex8EncodedLittleEndian, \
Hex2EncodedUtf8, \
Hex8EncodedBigEndian, \
Hex4EncodedBigEndian, \
Hex4EncodedLittleEndianWithoutQuotes, \
Hex2EncodedLocal8Bit, \
JulianDate, \
MillisecondsSinceMidnight, \
JulianDateAndMillisecondsSinceMidnight, \
Hex2EncodedInt1, \
Hex2EncodedInt2, \
Hex2EncodedInt4, \
Hex2EncodedInt8, \
Hex2EncodedUInt1, \
Hex2EncodedUInt2, \
Hex2EncodedUInt4, \
Hex2EncodedUInt8, \
Hex2EncodedFloat4, \
Hex2EncodedFloat8 \
    = range(27)

# Display modes. Keep that synchronized with DebuggerDisplay in watchutils.h
StopDisplay, \
DisplayImageData, \
DisplayUtf16String, \
DisplayImageFile, \
DisplayProcess, \
DisplayLatin1String, \
DisplayUtf8String \
    = range(7)

76
def lookupType(name):
77
    return None
78
79
80
81
82
83

def isSimpleType(typeobj):
    typeClass = typeobj.GetTypeClass()
    #warn("TYPECLASS: %s" % typeClass)
    return typeClass == lldb.eTypeClassBuiltin

84
85
86
87
88
89
90
91
92
93
94
95
96
97
def call2(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

def call(value, func, *args):
    return call2(value, func, args)

98
99
100
101
102
103
#######################################################################
#
# Helpers
#
#######################################################################

104
qqStringCutOff = 10000
105

hjk's avatar
hjk committed
106
107
108
109
110
111
112
113
114
115
116
117
# This is a cache mapping from 'type name' to 'display alternatives'.
qqFormats = {}

# This is a cache of all known dumpers.
qqDumpers = {}

# This is a cache of all dumpers that support writing.
qqEditable = {}

# This keeps canonical forms of the typenames, without array indices etc.
qqStripForFormat = {}

118
119
def directBaseClass(typeobj, index = 0):
    return typeobj.GetDirectBaseClassAtIndex(index)
120

hjk's avatar
hjk committed
121
122
123
124
125
126
def stripForFormat(typeName):
    global qqStripForFormat
    if typeName in qqStripForFormat:
        return qqStripForFormat[typeName]
    stripped = ""
    inArray = 0
hjk's avatar
hjk committed
127
    for c in typeName:
hjk's avatar
hjk committed
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
        if c == '<':
            break
        if c == ' ':
            continue
        if c == '[':
            inArray += 1
        elif c == ']':
            inArray -= 1
        if inArray and ord(c) >= 48 and ord(c) <= 57:
            continue
        stripped +=  c
    qqStripForFormat[typeName] = stripped
    return stripped


def registerDumper(function):
144
    if hasattr(function, 'func_name'):
hjk's avatar
hjk committed
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
        funcname = function.func_name
        if funcname.startswith("qdump__"):
            type = funcname[7:]
            qqDumpers[type] = function
            qqFormats[type] = qqFormats.get(type, "")
        elif funcname.startswith("qform__"):
            type = funcname[7:]
            formats = ""
            try:
                formats = function()
            except:
                pass
            qqFormats[type] = formats
        elif funcname.startswith("qedit__"):
            type = funcname[7:]
            try:
                qqEditable[type] = function
            except:
                pass
164
165

def warn(message):
166
    print '\n\nWARNING="%s",\n' % message.encode("latin1").replace('"', "'")
167
168
169

def showException(msg, exType, exValue, exTraceback):
    warn("**** CAUGHT EXCEPTION: %s ****" % msg)
170
171
172
    import traceback
    lines = [line for line in traceback.format_exception(exType, exValue, exTraceback)]
    warn('\n'.join(lines))
173
174
175
176
177
178
179

def registerCommand(name, func):
    pass

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

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205

PointerCode = None
ArrayCode = None
StructCode = None
UnionCode = None
EnumCode = None
FlagsCode = None
FunctionCode = None
IntCode = None
FloatCode = None
VoidCode = None
SetCode = None
RangeCode = None
StringCode = None
BitStringCode = None
ErrorTypeCode = None
MethodCode = None
MethodPointerCode = None
MemberPointerCode = None
ReferenceCode = None
CharCode = None
BoolCode = None
ComplexCode = None
TypedefCode = None
NamespaceCode = None
SimpleValueCode = None # LLDB only
206
207
208


# Data members
209
210
211
SimpleValueCode = 100
StructCode = 101
PointerCode = 102
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228

# 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
BreakpointAtSysCall = 10
WatchpointAtAddress = 11
WatchpointAtExpression = 12
BreakpointOnQmlSignalEmit = 13
BreakpointAtJavaScriptThrow = 14

229
230
231
# See db.StateType
stateNames = ["invalid", "unloaded", "connected", "attaching", "launching", "stopped",
    "running", "stepping", "crashed", "detached", "exited", "suspended" ]
232

233
234
235
236
237
def loggingCallback(args):
    s = args.strip()
    s = s.replace('"', "'")
    sys.stdout.write('log="%s"@\n' % s)

hjk's avatar
hjk committed
238
239
240
241
def check(exp):
    if not exp:
        raise RuntimeError("Check failed")

242
243
244
245
246
247
248
249
250
def checkPointer(p, align = 1):
    if not isNull(p):
        p.Dereference()

def isNull(p):
    return long(p) == 0

Value = lldb.SBValue

hjk's avatar
hjk committed
251
def checkSimpleRef(ref):
252
    count = int(ref["_q_value"])
hjk's avatar
hjk committed
253
254
255
256
257
    check(count > 0)
    check(count < 1000000)

def checkRef(ref):
    try:
258
        count = int(ref["atomic"]["_q_value"]) # Qt 5.
hjk's avatar
hjk committed
259
260
        minimum = -1
    except:
261
        count = int(ref["_q_value"]) # Qt 4.
hjk's avatar
hjk committed
262
263
264
265
266
        minimum = 0
    # Assume there aren't a million references to any object.
    check(count >= minimum)
    check(count < 1000000)

267
268
269
270
def createPointerValue(context, address, pointeeType):
    addr = int(address) & 0xFFFFFFFFFFFFFFFF
    return context.CreateValueFromAddress(None, addr, pointeeType).AddressOf()

271
272
def impl_SBValue__add__(self, offset):
    if self.GetType().IsPointerType():
273
274
275
276
        if isinstance(offset, int) or isinstance(offset, long):
            pass
        else:
            offset = offset.GetValueAsSigned()
277
        itemsize = self.GetType().GetPointeeType().GetByteSize()
278
        address = self.GetValueAsUnsigned() + offset * itemsize
279
        address = address & 0xFFFFFFFFFFFFFFFF  # Force unsigned
280
        return createPointerValue(self, address, self.GetType().GetPointeeType())
281
    raise RuntimeError("SBValue.__add__ not implemented: %s" % self.GetType())
282
283
    return NotImplemented

284
def impl_SBValue__sub__(self, other):
285
    if self.GetType().IsPointerType():
286
287
288
289
        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())
290
        if other.GetType().IsPointerType():
291
292
            itemsize = self.GetType().GetPointeeType().GetByteSize()
            return (self.GetValueAsUnsigned() - other.GetValueAsUnsigned()) / itemsize
293
    raise RuntimeError("SBValue.__sub__ not implemented: %s" % self.GetType())
294
295
    return NotImplemented

296
297
298
299
300
301
302
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):
303
304
    return self.GetValueAsSigned()
    #return int(self.GetValue(), 0)
305

306
307
308
def impl_SBValue__long__(self):
    return int(self.GetValue(), 0)

309
310
311
312
313
314
315
316
317
318
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)
319
320
321
322

def childAt(value, index):
    return value.GetChildAtIndex(index)

hjk's avatar
hjk committed
323
324
325
def fieldAt(type, index):
    return type.GetFieldAtIndex(index)

326
lldb.SBValue.__add__ = impl_SBValue__add__
327
lldb.SBValue.__sub__ = impl_SBValue__sub__
328
lldb.SBValue.__le__ = impl_SBValue__le__
329

330
331
lldb.SBValue.__getitem__ = impl_SBValue__getitem__
lldb.SBValue.__int__ = impl_SBValue__int__
332
333
lldb.SBValue.__long__ = lambda self: long(self.GetValue(), 0)

334
lldb.SBValue.code = lambda self: self.GetTypeClass()
335
336
lldb.SBValue.cast = lambda self, typeObj: self.Cast(typeObj)
lldb.SBValue.dereference = lambda self: self.Dereference()
337
lldb.SBValue.address = property(lambda self: self.GetAddress())
338

339
lldb.SBType.unqualified = lambda self: self.GetUnqualifiedType()
340
lldb.SBType.pointer = lambda self: self.GetPointerType()
341
lldb.SBType.code = lambda self: self.GetTypeClass()
342
lldb.SBType.sizeof = property(lambda self: self.GetByteSize())
hjk's avatar
hjk committed
343
lldb.SBType.strip_typedefs = lambda self: self.GetCanonicalType()
344

hjk's avatar
hjk committed
345
346
347
lldb.SBType.__orig__str__ = lldb.SBType.__str__
lldb.SBType.__str__ = lldb.SBType.GetName

348
349
350
351
352
353
354
def simpleEncoding(typeobj):
    code = typeobj.GetTypeClass()
    size = typeobj.sizeof
    #if code == BoolCode or code == CharCode:
    #    return Hex2EncodedInt1
    #if code == IntCode:
    if code == lldb.eTypeClassBuiltin:
hjk's avatar
hjk committed
355
356
357
358
359
360
        name = str(typeobj)
        if name == "float":
            return Hex2EncodedFloat4
        if name == "double":
            return Hex2EncodedFloat8
        if name.find("unsigned") >= 0:
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
            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
379

380
381
382
383
class Children:
    def __init__(self, d, numChild = 1, childType = None, childNumChild = None,
            maxNumChild = None, addrBase = None, addrStep = None):
        self.d = d
384
385
386
387
388
389
390
391
392
393
394
        self.numChild = numChild
        self.childNumChild = childNumChild
        self.maxNumChild = maxNumChild
        self.addrBase = addrBase
        self.addrStep = addrStep
        self.printsAddress = True
        if childType is None:
            self.childType = None
        else:
            #self.childType = stripClassTag(str(childType))
            self.childType = childType
hjk's avatar
hjk committed
395
            self.d.put('childtype="%s",' % self.childType.GetName())
396
397
398
399
400
401
402
403
404
405
406
407
408
            if childNumChild is None:
                pass
                #if isSimpleType(childType):
                #    self.d.put('childnumchild="0",')
                #    self.childNumChild = 0
                #elif childType.code == PointerCode:
                #    self.d.put('childnumchild="1",')
                #    self.childNumChild = 1
            else:
                self.d.put('childnumchild="%s",' % childNumChild)
                self.childNumChild = childNumChild
        try:
            if not addrBase is None and not addrStep is None:
hjk's avatar
hjk committed
409
410
                self.d.put('addrbase="0x%x",' % int(addrBase))
                self.d.put('addrstep="0x%x",' % int(addrStep))
411
412
413
                self.printsAddress = False
        except:
            warn("ADDRBASE: %s" % addrBase)
hjk's avatar
hjk committed
414
            warn("ADDRSTEP: %s" % addrStep)
415
        #warn("CHILDREN: %s %s %s" % (numChild, childType, childNumChild))
416
417

    def __enter__(self):
418
419
420
421
422
423
424
425
426
427
428
        self.savedChildType = self.d.currentChildType
        self.savedChildNumChild = self.d.currentChildNumChild
        self.savedNumChild = self.d.currentNumChild
        self.savedMaxNumChild = self.d.currentMaxNumChild
        self.savedPrintsAddress = self.d.currentPrintsAddress
        self.d.currentChildType = self.childType
        self.d.currentChildNumChild = self.childNumChild
        self.d.currentNumChild = self.numChild
        self.d.currentMaxNumChild = self.maxNumChild
        self.d.currentPrintsAddress = self.printsAddress
        self.d.put("children=[")
429
430
431
432
433

    def __exit__(self, exType, exValue, exTraceBack):
        if not exType is None:
            if self.d.passExceptions:
                showException("CHILDREN", exType, exValue, exTraceBack)
434
435
436
437
438
439
440
441
442
443
444
            self.d.putNumChild(0)
            self.d.putValue("<not accessible>")
        if not self.d.currentMaxNumChild is None:
            if self.d.currentMaxNumChild < self.d.currentNumChild:
                self.d.put('{name="<incomplete>",value="",type="",numchild="0"},')
        self.d.currentChildType = self.savedChildType
        self.d.currentChildNumChild = self.savedChildNumChild
        self.d.currentNumChild = self.savedNumChild
        self.d.currentMaxNumChild = self.savedMaxNumChild
        self.d.currentPrintsAddress = self.savedPrintsAddress
        self.d.put('],')
445
446
        return True

447

448
449
450
451
452
453
454
455
456
457
458
459
class NoAddress:
    def __init__(self, d):
        self.d = d

    def __enter__(self):
        self.savedPrintsAddress = self.d.currentPrintsAddress
        self.d.currentPrintsAddress = False

    def __exit__(self, exType, exValue, exTraceBack):
        self.d.currentPrintsAddress = self.savedPrintsAddress


460

461
462
463
class SubItem:
    def __init__(self, d, component):
        self.d = d
464
        if isinstance(component, lldb.SBValue):
465
466
467
468
            # Avoid $$__synth__ suffix on Mac.
            value = component
            value.SetPreferSyntheticValue(False)
            self.name = value.GetName()
469
470
471
        else:
            self.name = component
        self.iname = "%s.%s" % (d.currentIName, self.name)
472
473
474
475
476
477
478

    def __enter__(self):
        self.d.put('{')
        #if not self.name is None:
        if isinstance(self.name, str):
            self.d.put('name="%s",' % self.name)
        self.savedIName = self.d.currentIName
hjk's avatar
hjk committed
479
        self.savedCurrentAddress = self.d.currentAddress
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
        self.savedValue = self.d.currentValue
        self.savedValuePriority = self.d.currentValuePriority
        self.savedValueEncoding = self.d.currentValueEncoding
        self.savedType = self.d.currentType
        self.savedTypePriority = self.d.currentTypePriority
        self.d.currentIName = self.iname
        self.d.currentValuePriority = -100
        self.d.currentValueEncoding = None
        self.d.currentType = ""
        self.d.currentTypePriority = -100

    def __exit__(self, exType, exValue, exTraceBack):
        if not exType is None:
            if self.d.passExceptions:
                showException("SUBITEM", exType, exValue, exTraceBack)
            self.d.putNumChild(0)
            self.d.putValue("<not accessible>")
        try:
            typeName = self.d.currentType
            if len(typeName) > 0 and typeName != self.d.currentChildType:
                self.d.put('type="%s",' % typeName) # str(type.unqualified()) ?
            if  self.d.currentValue is None:
                self.d.put('value="<not accessible>",numchild="0",')
            else:
                if not self.d.currentValueEncoding is None:
                    self.d.put('valueencoded="%d",' % self.d.currentValueEncoding)
                self.d.put('value="%s",' % self.d.currentValue)
        except:
            pass
hjk's avatar
hjk committed
509
510
        if not self.d.currentAddress is None:
            self.d.put(self.d.currentAddress)
511
512
513
514
515
516
517
        self.d.put('},')
        self.d.currentIName = self.savedIName
        self.d.currentValue = self.savedValue
        self.d.currentValuePriority = self.savedValuePriority
        self.d.currentValueEncoding = self.savedValueEncoding
        self.d.currentType = self.savedType
        self.d.currentTypePriority = self.savedTypePriority
hjk's avatar
hjk committed
518
        self.d.currentAddress = self.savedCurrentAddress
519
520
        return True

521
class Dumper:
522
523
    def __init__(self):
        self.debugger = lldb.SBDebugger.Create()
524
        #self.debugger.SetLoggingCallback(loggingCallback)
525
526
527
528
529
530
531
532
533
534
535
536
        #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")
        self.process = None
        self.target = None
        self.eventState = lldb.eStateInvalid
        self.options = {}
        self.expandedINames = {}
        self.passExceptions = True
537
        self.useLldbDumpers = False
538
        self.ns = ""
hjk's avatar
hjk committed
539
        self.autoDerefPointers = True
540
        self.useDynamicType = True
hjk's avatar
hjk committed
541
        self.useFancy = True
hjk's avatar
hjk committed
542
543
544
        self.formats = {}
        self.typeformats = {}
        self.currentAddress = None
545
546
547
548
549
550

        self.currentIName = None
        self.currentValuePriority = -100
        self.currentValueEncoding = None
        self.currentType = ""
        self.currentTypePriority = -100
551
        self.currentValue = None
552
553
554
555
556
        self.currentNumChild = None
        self.currentMaxNumChild = None
        self.currentPrintsAddress = None
        self.currentChildType = None
        self.currentChildNumChild = None
557
        self.currentWatchers = {}
558

hjk's avatar
hjk committed
559
        self.executable_ = None
560
561
562
563
564
        self.charType_ = None
        self.intType_ = None
        self.sizetType_ = None
        self.charPtrType_ = None
        self.voidType_ = None
565
        self.isShuttingDown_ = False
566
        self.dummyValue = None
567

568
569
570
    def extractTemplateArgument(self, typename, index):
        level = 0
        skipSpace = False
571
        inner = ''
572
573
574
575
576
577
578
579
580
581
582
583
        for c in typename[typename.find('<') + 1 : -1]:
            if c == '<':
                inner += c
                level += 1
            elif c == '>':
                level -= 1
                inner += c
            elif c == ',':
                if level == 0:
                    if index == 0:
                        return inner
                    index -= 1
584
                    inner = ''
585
586
587
588
589
590
591
592
593
594
595
                else:
                    inner += c
                    skipSpace = True
            else:
                if skipSpace and c == ' ':
                    pass
                else:
                    inner += c
                    skipSpace = False
        return inner

596
    def templateArgument(self, typeobj, index):
597
598
599
600
601
602
603
604
605
        type = typeobj.GetTemplateArgumentType(index)
        if len(type.GetName()):
            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)
606

607
608
    def intType(self):
        if self.intType_ is None:
hjk's avatar
hjk committed
609
             self.intType_ = self.target.FindFirstType('int')
610
611
612
613
        return self.intType_

    def charType(self):
        if self.charType_ is None:
hjk's avatar
hjk committed
614
             self.charType_ = self.target.FindFirstType('char')
615
616
617
618
619
620
621
622
        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
623
        return None
624
625
626
        return self.charPtrType()  # FIXME

    def voidPtrSize(self):
hjk's avatar
hjk committed
627
        return None
628
629
630
631
632
633
634
        return self.charPtrType().GetByteSize()

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

635
636
637
    def addressOf(self, value):
        return int(value.GetLoadAddress())

638
639
640
641
642
643
    def handleCommand(self, command):
        result = lldb.SBCommandReturnObject()
        self.debugger.GetCommandInterpreter().HandleCommand(command, result)
        success = result.Succeeded()
        if success:
            self.report('output="%s"' % result.GetOutput())
644
        else:
645
646
647
648
649
650
            self.report('error="%s"' % result.GetError())
        self.reportData()

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

hjk's avatar
hjk committed
651
652
653
    def putField(self, name, value):
        self.put('%s="%s",' % (name, value))

hjk's avatar
hjk committed
654
    def currentItemFormat(self):
hjk's avatar
hjk committed
655
656
657
658
        format = self.formats.get(self.currentIName)
        if format is None:
            format = self.typeformats.get(stripForFormat(str(self.currentType)))
        return format
hjk's avatar
hjk committed
659

660
661
662
663
664
665
666
    def isMovableType(self, type):
        if type.code == PointerCode:
            return True
        if isSimpleType(type):
            return True
        return self.stripNamespaceFromType(type.GetName()) in movableTypes

hjk's avatar
hjk committed
667
668
669
670
671
672
673
674
675
676
677
678
    def putIntItem(self, name, value):
        with SubItem(self, name):
            self.putValue(value)
            self.putType("int")
            self.putNumChild(0)

    def putBoolItem(self, name, value):
        with SubItem(self, name):
            self.putValue(value)
            self.putType("bool")
            self.putNumChild(0)

679
680
    def putNumChild(self, numchild):
        #warn("NUM CHILD: '%s' '%s'" % (numchild, self.currentChildNumChild))
hjk's avatar
hjk committed
681
682
        #if numchild != self.currentChildNumChild:
        self.put('numchild="%s",' % numchild)
683

hjk's avatar
hjk committed
684
685
686
687
688
689
    def putEmptyValue(self, priority = -10):
        if priority >= self.currentValuePriority:
            self.currentValue = ""
            self.currentValuePriority = priority
            self.currentValueEncoding = None

690
691
692
693
694
695
    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
696
        #self.put('value="%s",' % value)
697

698
699
700
701
702
703
704
705
    # Convenience function.
    def putItemCount(self, count, maximum = 1000000000):
        # This needs to override the default value, so don't use 'put' directly.
        if count > maximum:
            self.putValue('<>%s items>' % maximum)
        else:
            self.putValue('<%s items>' % count)

hjk's avatar
hjk committed
706
707
708
    def putName(self, name):
        self.put('name="%s",' % name)

709
710
711
712
713
714
715
716
717
718
    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):
        if not isSimpleType(typeobj):
            return False
        size = n * typeobj.sizeof
        self.put('childtype="%s",' % typeobj)
719
720
        self.put('addrbase="0x%x",' % int(base))
        self.put('addrstep="%d",' % typeobj.sizeof)
721
722
        self.put('arrayencoding="%s",' % simpleEncoding(typeobj))
        self.put('arraydata="')
723
        self.put(self.readRawMemory(base, size))
724
725
726
727
        self.put('",')
        return True

    def putPlotData(self, type, base, n, plotFormat):
hjk's avatar
hjk committed
728
        warn("PLOTDATA: %s %s" % (type, n))
729
730
        if self.isExpanded():
            self.putArrayData(type, base, n)
hjk's avatar
hjk committed
731
732
        self.putValue(self.currentValue)
        self.putField("plottable", "0")
733
734
735
736
737
738
739
740
741
742

    def putArrayData(self, type, base, n,
            childNumChild = None, maxNumChild = 10000):
        if not self.tryPutArrayContents(type, base, n):
            base = base.cast(type.pointer())
            with Children(self, n, type, childNumChild, maxNumChild,
                    base, type.GetByteSize()):
                for i in self.childRange():
                    self.putSubItem(i, (base + i).dereference())

743
744
745
746
747
748
749
750
    def parseAndEvalute(self, expr):
        return expr

    def putCallItem(self, name, value, func, *args):
        result = call2(value, func, args)
        with SubItem(self, name):
            self.putItem(result)

751
752
753
754
755
    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
756
757
758
759
760
761
762
    def putPlainChildren(self, value):
        self.putEmptyValue(-99)
        self.putNumChild(1)
        if self.currentIName in self.expandedINames:
            with Children(self):
               self.putFields(value)

763
    def lookupType(self, name):
764
765
        #warn("LOOKUP TYPE NAME: %s" % name)
        #warn("LOOKUP RESULT: %s" % self.target.FindFirstType(name))
hjk's avatar
hjk committed
766
        return self.target.FindFirstType(name)
767

768
    def setupInferior(self, args):
hjk's avatar
hjk committed
769
770
        executable = args['executable']
        self.executable_ = executable
771
        error = lldb.SBError()
hjk's avatar
hjk committed
772
        self.target = self.debugger.CreateTarget(executable, None, None, True, error)
773
774
        self.importDumpers()

775
        if self.target.IsValid():
hjk's avatar
hjk committed
776
            self.report('state="inferiorsetupok",msg="%s",exe="%s"' % (error, executable))
777
        else:
hjk's avatar
hjk committed
778
            self.report('state="inferiorsetupfailed",msg="%s",exe="%s"' % (error, executable))
779

780
    def runEngine(self, _):
hjk's avatar
hjk committed
781
782
783
784
        s = threading.Thread(target=self.loop, args=[])
        s.start()

    def loop(self):
785
        error = lldb.SBError()
hjk's avatar
hjk committed
786
787
788
789
        listener = self.debugger.GetListener()

        self.process = self.target.Launch(listener, None, None, None, None,
            None, None, 0, False, error)
790

hjk's avatar
hjk committed
791
        self.report('pid="%s"' % self.process.GetProcessID())
792
        self.report('state="enginerunandinferiorrunok"')
793

hjk's avatar
hjk committed
794
795
796
797
798
799
        event = lldb.SBEvent()
        while True:
            if listener.WaitForEvent(10000000, event):
                self.handleEvent(event)
            else:
                warn('TIMEOUT')
800

801
    def describeError(self, error):
802
803
804
805
806
807
        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()
808
809
810
811
        return result

    def reportError(self, error):
        self.report(self.describeError(error))
812
813

    def currentThread(self):
814
        return self.process.GetSelectedThread()
815
816
817
818
819
820

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

    def reportLocation(self):
        thread = self.currentThread()
821
        frame = thread.GetSelectedFrame()
822
823
824
825
826
        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):
827
828
        reasons = ['None', 'Trace', 'Breakpoint', 'Watchpoint', 'Signal', 'Exception',
            'Exec', 'PlanComplete']
829
        result = 'threads={threads=['
830
        for i in xrange(0, self.process.GetNumThreads()):
831
            thread = self.process.GetThreadAtIndex(i)
832
            stopReason = thread.GetStopReason()
833
834
            result += '{id="%d"' % thread.GetThreadID()
            result += ',index="%s"' % i
835
            result += ',details="%s"' % thread.GetQueueName()
836
837
838
            result += ',stop-reason="%s"' % stopReason
            if stopReason >= 0 and stopReason < len(reasons):
                result += ',state="%s"' % reasons[stopReason]
839
            result += ',name="%s"' % thread.GetName()
840
841
842
843
844
            result += ',frame={'
            frame = thread.GetFrameAtIndex(0)
            result += 'pc="0x%x"' % frame.pc
            result += ',addr="0x%x"' % frame.pc
            result += ',fp="0x%x"' % frame.fp
845
            result += ',func="%s"' % frame.GetFunctionName()
846
847
848
849
850
851
852
853
            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
854
855
856
857
858
859
860
861
862
863
    def firstUsableFrame(self):
        thread = self.currentThread()
        for i in xrange(4):
            frame = thread.GetFrameAtIndex(i)
            lineEntry = frame.GetLineEntry()
            line = lineEntry.GetLine()
            if line != 0:
                return i
        return None

hjk's avatar
hjk committed
864
    def reportStack(self, _ = None):
865
866
867
868
        if self.process is None:
            self.report('msg="No process"')
        else:
            thread = self.currentThread()
869
870
871
            result = 'stack={current-frame="%s"' % thread.GetSelectedFrame().GetFrameID()
            result += ',current-thread="%s"' % thread.GetThreadID()
            result += ',frames=['
872
873
874
875
            n = thread.GetNumFrames()
            if n > 4:
                n = 4
            for i in xrange(n):
876
877
                frame = thread.GetFrameAtIndex(i)
                lineEntry = frame.GetLineEntry()
878
879
                line = lineEntry.GetLine()
                usable = line != 0
880
                result += '{pc="0x%x"' % frame.GetPC()
881
                result += ',level="%d"' % frame.idx
882
                result += ',addr="0x%x"' % frame.GetPCAddress().GetLoadAddress(self.target)
883
                result += ',func="%s"' % frame.GetFunctionName()
884
                result += ',line="%d"' % line
885
                result += ',fullname="%s"' % fileName(lineEntry.file)
886
                result += ',usable="%d"' % usable
887
                result += ',file="%s"},' % fileName(lineEntry.file)
hjk's avatar
hjk committed
888
            result += '],hasmore="0"},'
889
890
            self.report(result)

891
892
893
894
895
    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
896
        #warn("TYPE: %s PRIORITY: %s" % (type, priority))
897

898
899
900
901
902
    def putBetterType(self, type):
        try:
            self.currentType = type.GetName()
        except:
            self.currentType = str(type)
903
        self.currentTypePriority = self.currentTypePriority + 1
hjk's avatar
hjk committed
904
        #warn("BETTER TYPE: %s PRIORITY: %s" % (type, self.currentTypePriority))
hjk's avatar
hjk committed
905
906

    def readRawMemory(self, base, size):
hjk's avatar
hjk committed
907
908
        if size == 0:
            return ""
909
910
911
912
913
914
        #warn("BASE: %s " % base)
        #warn("SIZE: %s " % size)
        base = int(base) & 0xFFFFFFFFFFFFFFFF
        size = int(size) & 0xFFFFFFFF
        #warn("BASEX: %s " % base)
        #warn("SIZEX: %s " % size)
hjk's avatar
hjk committed
915
        error = lldb.SBError()
916
        contents = self.process.ReadMemory(base, size, error)
hjk's avatar
hjk committed
917
918
919
920
921
922
923
924
925
926
927
928
        return binascii.hexlify(contents)

    def computeLimit(self, size, limit):
        if limit is None:
            return size
        if limit == 0:
            #return min(size, qqStringCutOff)
            return min(size, 100)
        return min(size, limit)

    def putValue(self, value, encoding = None, priority = 0):
        # Higher priority values override lower ones.
929
930
931
932
        if priority >= self.currentValuePriority:
            self.currentValue = value
            self.currentValuePriority = priority
            self.currentValueEncoding = encoding
hjk's avatar
hjk committed
933

934
935
936
937
938
939
940
941
942
943
944
945
946
947
    def stripNamespaceFromType(self, typeName):
        #type = stripClassTag(typeName)
        type = typeName
        #if len(self.ns) > 0 and type.startswith(self.ns):
        #    type = type[len(self.ns):]
        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("<")
        return type

    def putSubItem(self, component, value, tryDynamic=True):
948
        if not value.IsValid():
hjk's avatar
hjk committed
949
            warn("INVALID SUBITEM")
950
            return
951
952
953
        with SubItem(self, component):
            self.putItem(value, tryDynamic)

hjk's avatar
hjk committed
954
955
956
957
958
959
960
    def putAddress(self, addr):
        if self.currentPrintsAddress:
            try:
                self.currentAddress = 'addr="0x%s",' % int(addr)
            except:
                pass

961
    def putItem(self, value, tryDynamic=True):
hjk's avatar
hjk committed
962
963
        #value = value.GetDynamicValue(lldb.eDynamicCanRunTarget)
        typeName = value.GetTypeName()
964

hjk's avatar
hjk committed
965
966
967
        if tryDynamic:
            self.putAddress(value.address)

968
        # Handle build-in LLDB visualizers if wanted.
969
        if self.useLldbDumpers and value.GetTypeSynthetic().IsValid():
970
971
972
973
974
975
976
977
978
979
            # 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
980
            self.put('iname="%s",' % self.currentIName)
hjk's avatar
hjk committed
981
            self.putType(typeName)
hjk's avatar
hjk committed
982
983
            self.put('numchild="%s",' % numchild)
            self.put('addr="0x%x",' % value.GetLoadAddress())
984
            self.putItemCount(numchild)
hjk's avatar
hjk committed
985
986
            if self.currentIName in self.expandedINames:
                with Children(self):
987
988
989
990
991
992
                    for i in xrange(numchild):
                        child = formatter.get_child_at_index(i)
                        with SubItem(self, i):
                            self.putItem(child)
            return

993
        # Our turf now.
994
        value.SetPreferSyntheticValue(False)
995

996
997
998
999
1000
        # Arrays
        if value.GetType().GetTypeClass() == lldb.eTypeClassArray:
            qdump____c_style_array__(self, value)
            return

1001
1002
1003
1004
        # References
        if value.GetType().IsReferenceType():
            type = value.GetType().GetDereferencedType().GetPointerType()
            # FIXME: Find something more direct.
hjk's avatar
hjk committed
1005
            origType = value.GetTypeName();
1006
1007
1008
1009
            value = value.CreateValueFromAddress(value.GetName(),
                value.AddressOf().GetValueAsUnsigned(), type).Dereference()
            #value = value.cast(value.dynamic_type)
            self.putItem(value)
hjk's avatar
hjk committed
1010
            self.putBetterType(origType)
1011
1012
            return

hjk's avatar
hjk committed
1013
1014
        # Pointers
        if value.GetType().IsPointerType() and self.autoDerefPointers:
hjk's avatar
hjk committed
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029

            if isNull(value):
                self.putType(typeName)
                self.putValue("0x0")
                self.putNumChild(0)
                return

            origType = value.GetType()
            innerType = value.GetType().GetPointeeType()
            self.putType(innerType)
            savedCurrentChildType = self.currentChildType
            self.currentChildType = str(innerType)
            self.putItem(value.dereference())
            self.currentChildType = savedCurrentChildType
            self.put('origaddr="%s",' % value.address)
hjk's avatar
hjk committed
1030
1031
            return

1032
        #warn("VALUE: %s" % value)
hjk's avatar
hjk committed
1033
1034
1035
1036
1037
1038
1039
1040
1041
        #warn("FANCY: %s" % self.useFancy)
        if self.useFancy:
            stripped = self.stripNamespaceFromType(typeName).replace("::", "__")
            #warn("STRIPPED: %s" % stripped)
            #warn("DUMPABLE: %s" % (stripped in qqDumpers))
            if stripped in qqDumpers:
                self.putType(typeName)
                qqDumpers[stripped](self, value)
                return
1042
1043
1044
1045
1046
1047

        # Normal value
        v = value.GetValue()
        #numchild = 1 if value.MightHaveChildren() else 0
        numchild = value.GetNumChildren()
        self.put('iname="%s",' % self.currentIName)
hjk's avatar
hjk committed
1048
1049
        self.putType(typeName)
        self.putValue('' if v is None else v)
1050
1051
1052
1053
1054
        self.put('numchild="%s",' % numchild)
        self.put('addr="0x%x",' % value.GetLoadAddress())
        if self.currentIName in self.expandedINames:
            with Children(self):
                self.putFields(value)
1055
1056
1057
1058
1059
1060

    def putFields(self, value):
        n = value.GetNumChildren()
        if n > 10000:
            n = 10000
        for i in xrange(n):
hjk's avatar
hjk committed
1061
            child = value.GetChildAtIndex(i)
1062
            with SubItem(self, child):
hjk's avatar
hjk committed
1063
                self.putItem(child)
1064

hjk's avatar
hjk committed
1065
    def reportVariables(self, _ = None):
1066
        frame = self.currentThread().GetSelectedFrame()
1067
        self.currentIName = 'local'
1068
1069
        self.put('data=[')
        for value in frame.GetVariables(True, True, False, False):
1070
1071
            if self.dummyValue is None:
                self.dummyValue = value
1072
            with SubItem(self, value):
1073
                self.put('iname="%s",' % self.currentIName)
1074
                self.putItem(value)
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097

        # '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'])
                warn("EXP: %s" % exp)
                warn("INDEX: %s" % index)
                if exp == "":
                    self.put('type="",value="",exp=""')
                    continue

                value = self.dummyValue.CreateValueFromExpression(iname, exp)
                #value = self.dummyValue
                warn("VALUE: %s" % value)
                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)

1098
1099
1100
        self.put(']')
        self.report('')

hjk's avatar
hjk committed
1101
    def reportData(self, _ = None):
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
        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()

1113
    def reportRegisters(self, _ = None):
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
        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):
        sys.stdout.write(stuff)
        sys.stdout.write("@\n")

hjk's avatar
hjk committed
1131
    def interruptInferior(self, _ = None):
1132
1133
        if self.process is None:
            self.report('msg="No process"')
1134
1135
1136
1137
1138
1139
1140
1141
            return
        error = self.process.Stop()
        self.reportError(error)
        self.consumeEvents()
        if error.GetType() == 1:
            state = self.process.GetState()
            if state != lldb.eStateStopped:
                self.report('state="inferiorstopfailed"')
1142

hjk's avatar
hjk committed
1143
    def detachInferior(self, _ = None):
1144
1145
1146
1147
1148
1149
        if self.process is None:
            self.report('msg="No process"')
        else:
            error = self.process.Detach()
            self.reportError(error)
            self.reportData()
1150

hjk's avatar
hjk committed
1151
    def continueInferior(self, _ = None):
1152
1153
1154
1155
1156
1157
1158
1159
1160
        if self.process is None:
            self.report('msg="No process"')
        else:
            error = self.process.Continue()
            self.reportError(error)

    def handleEvent(self, event):
        out = lldb.SBStream()
        event.GetDescription(out)
1161
        #warn("EVENT: %s" % event)
1162
1163
1164
        type = event.GetType()
        msg = lldb.SBEvent.GetCStringFromEvent(event)
        flavor = event.GetDataFlavor()
1165
        state = lldb.SBProcess.GetStateFromEvent(event)
1166
        self.report('event={type="%s",data="%s",msg="%s",flavor="%s",state="%s"}'
1167
1168
1169
1170
            % (type, out.GetData(), msg, flavor, state))
        if state != self.eventState:
            self.report('state="%s"' % stateNames[state])
            self.eventState = state
hjk's avatar
hjk committed
1171
            if state == lldb.eStateExited:
1172
1173
1174
1175
1176
                if self.isShuttingDown_:
                    self.report('state="inferiorshutdownok"')
                else:
                    self.report('state="inferiorexited"')
                self.report('exited={status="%s",desc="%s"}'
hjk's avatar
hjk committed
1177
                    % (self.process.GetExitStatus(), self.process.GetExitDescription()))
1178
        if type == lldb.SBProcess.eBroadcastBitStateChanged:
hjk's avatar
hjk committed
1179
1180
1181
1182
1183
1184
1185
1186
1187
            state = self.process.GetState()
            if state == lldb.eStateStopped:
                usableFrame = self.firstUsableFrame()
                if usableFrame:
                    self.currentThread().SetSelectedFrame(usableFrame)
                self.reportStack()
                self.reportThreads()
                self.reportLocation()
                self.reportVariables()
1188
1189
1190
        elif type == lldb.SBProcess.eBroadcastBitInterrupt:
            pass
        elif type == lldb.SBProcess.eBroadcastBitSTDOUT:
1191
1192
1193
1194
            # FIXME: Size?
            msg = self.process.GetSTDOUT(1024)
            self.report('output={channel="stdout",data="%s"}'
                % binascii.hexlify(msg))
1195
        elif type == lldb.SBProcess.eBroadcastBitSTDERR:
1196
1197
1198
            msg = self.process.GetSTDERR(1024)
            self.report('output={channel="stdout",data="%s"}'
                % binascii.hexlify(msg))
1199
1200
1201
        elif type == lldb.SBProcess.eBroadcastBitProfileData:
            pass

1202
    def processEvents(self):
1203
        event = lldb.SBEvent()
hjk's avatar
hjk committed
1204
1205
        while self.debugger.GetListener().PeekAtNextEvent(event):
            self.debugger.GetListener().GetNextEvent(event)
1206
1207
1208
1209
            self.handleEvent(event)

    def describeBreakpoint(self, bp, modelId):
        cond = bp.GetCondition()
hjk's avatar
hjk committed
1210
        result  = 'lldbid="%s"' % bp.GetID()
1211
1212
1213
        result += ',modelid="%s"' % modelId
        result += ',hitcount="%s"' % bp.GetHitCount()
        result += ',threadid="%s"' % bp.GetThreadID()
1214