dumper.py 27.9 KB
Newer Older
hjk's avatar
hjk committed
1
2
3
4
5
6
7
8

#Note: Keep name-type-value-numchild-extra order

#return

import sys
import traceback
import gdb
9
import base64
hjk's avatar
hjk committed
10
11
import curses.ascii

12
13
14
15
# only needed for gdb 7.0
import os
import tempfile

hjk's avatar
hjk committed
16
17
18
verbosity = 0
verbosity = 1

19
20
21
22
23
def select(condition, if_expr, else_expr):
    if condition:
        return if_expr
    return else_expr

24
25
26
27
28
def qmin(n, m):
    if n < m:
        return n
    return m

hjk's avatar
hjk committed
29
30
31
32
def isGoodGdb():
    return gdb.VERSION.startswith("6.8.50.2009") \
       and gdb.VERSION != "6.8.50.20090630-cvs"

33
def parseAndEvaluate(exp):
hjk's avatar
hjk committed
34
    if isGoodGdb():
35
36
37
38
39
40
41
42
43
44
45
46
47
        return gdb.parse_and_eval(exp)
    # Work around non-existing gdb.parse_and_eval as in released 7.0
    gdb.execute("set logging redirect on")
    gdb.execute("set logging on")
    gdb.execute("print %s" % exp)
    gdb.execute("set logging off")
    return gdb.history(0)

def listOfLocals():
    try:
        frame = gdb.selected_frame()
        #warn("FRAME %s: " % frame)
    except RuntimeError:
hjk's avatar
hjk committed
48
        return []
49
50

    items = []
hjk's avatar
hjk committed
51
    if isGoodGdb():
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
        # archer-tromey-python
        block = frame.block()
        while True:
            if block is None:
                warn("UNEXPECTED 'None' BLOCK")
                break
            for symbol in block:
                name = symbol.print_name
                
                if name == "__in_chrg":
                    continue

                # "NotImplementedError: Symbol type not yet supported in
                # Python scripts."
                #warn("SYMBOL %s: " % symbol.value)
                #warn("SYMBOL %s  (%s): " % (symbol, name))
                item = Item(0, "local", name, name)
                try:
                    item.value = frame.read_var(name)  # this is a gdb value
                except RuntimeError:
                    # happens for  void foo() { std::string s; std::wstring w; }
                    #warn("  FRAME READ VAR ERROR: %s (%s): " % (symbol, name))
                    continue
                #warn("ITEM %s: " % item.value)
                items.append(item)
            # The outermost block in a function has the function member
            # FIXME: check whether this is guaranteed.
            if not block.function is None:
                break

            block = block.superblock
    else:
hjk's avatar
hjk committed
84
        # Assuming gdb 7.0 release or 6.8-symbianelf.
85
86
        file = tempfile.mkstemp(prefix="gdbpy_")
        filename = file[1]
hjk's avatar
hjk committed
87
88
        gdb.execute("set logging off")
        gdb.execute("set logging redirect off")
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
        gdb.execute("set logging file %s" % filename)
        gdb.execute("set logging redirect on")
        gdb.execute("set logging on")
        gdb.execute("info locals")
        gdb.execute("info args")
        gdb.execute("set logging off")
        gdb.execute("set logging redirect off")
        file = open(filename, "r")
        for line in file:
            if len(line) == 0 or line.startswith(" "):
                continue
            pos = line.find(" = ")
            if pos < 0:
                continue
            name = line[0:pos]
            item = Item(0, "local", name, name)
            try:
                item.value = frame.read_var(name)  # this is a gdb value
            except RuntimeError:
                continue
            items.append(item)
        file.close()
        os.remove(filename)

    return items


116
def value(expr):
117
    value = parseAndEvaluate(expr)
118
119
120
121
122
    try:
        return int(value)
    except:
        return str(value)

123

hjk's avatar
hjk committed
124
125
126
127
128
129
130
131
132
133
134
135
def isSimpleType(typeobj):
    type = str(typeobj)
    return type == "bool" \
        or type == "char" \
        or type == "double" \
        or type == "float" \
        or type == "int" \
        or type == "long" or type.startswith("long ") \
        or type == "short" or type.startswith("short ") \
        or type == "signed" or  type.startswith("signed ") \
        or type == "unsigned" or type.startswith("unsigned ")

136

hjk's avatar
hjk committed
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
def isStringType(d, typeobj):
    type = str(typeobj)
    return type == d.ns + "QString" \
        or type == d.ns + "QByteArray" \
        or type == "std::string" \
        or type == "std::wstring" \
        or type == "wstring"

def warn(message):
    if verbosity > 0:
        print "XXX: %s " % message.encode("latin1")
    pass

def check(exp):
    if not exp:
        raise RuntimeError("Check failed")

154
155
156
157
158
def checkRef(ref):
    count = ref["_q_value"]
    check(count > 0)
    check(count < 1000000) # assume there aren't a million references to any object

hjk's avatar
hjk committed
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
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
206
207
#def couldBePointer(p, align):
#    type = gdb.lookup_type("unsigned int")
#    ptr = gdb.Value(p).cast(type)
#    d = int(str(ptr))
#    warn("CHECKING : %s %d " % (p, ((d & 3) == 0 and (d > 1000 or d == 0))))
#    return (d & (align - 1)) and (d > 1000 or d == 0)


def checkAccess(p, align = 1):
    return p.dereference()

def checkContents(p, expected, align = 1):
    if int(p.dereference()) != expected:
        raise RuntimeError("Contents check failed")

def checkPointer(p, align = 1):
    if not isNull(p):
        p.dereference()


def isNull(p):
    s = str(p)
    return s == "0x0" or s.startswith("0x0 ")

movableTypes = set([
    "QBrush", "QBitArray", "QByteArray",
    "QCustomTypeInfo", "QChar",
    "QDate", "QDateTime",
    "QFileInfo", "QFixed", "QFixedPoint", "QFixedSize",
    "QHashDummyValue",
    "QIcon", "QImage",
    "QLine", "QLineF", "QLatin1Char", "QLocal",
    "QMatrix", "QModelIndex",
    "QPoint", "QPointF", "QPen", "QPersistentModelIndex",
    "QResourceRoot", "QRect", "QRectF", "QRegExp",
    "QSize", "QSizeF", "QString",
    "QTime", "QTextBlock",
    "QUrl",
    "QVariant",
    "QXmlStreamAttribute", "QXmlStreamNamespaceDeclaration",
    "QXmlStreamNotationDeclaration", "QXmlStreamEntityDeclaration"])


def stripClassTag(type):
    if type.startswith("class "):
        return type[6:]
    return type

def checkPointerRange(p, n):
208
    for i in xrange(n):
hjk's avatar
hjk committed
209
210
211
212
213
214
        checkPointer(p)
        ++p

def call(value, func):
    #warn("CALL: %s -> %s" % (value, func))
    type = stripClassTag(str(value.type))
215
    if type.find(":") >= 0:
hjk's avatar
hjk committed
216
217
218
        type = "'" + type + "'"
    exp = "((%s*)%s)->%s" % (type, value.address, func)
    #warn("CALL: %s" % exp)
219
    result = parseAndEvaluate(exp)
hjk's avatar
hjk committed
220
221
222
    #warn("  -> %s" % result)
    return result

223
224
def qtNamespace():
    try:
225
        type = str(parseAndEvaluate("&QString::null").type.target().unqualified())
226
227
228
        return type[0:len(type) - len("QString::null")]
    except RuntimeError:
        return ""
hjk's avatar
hjk committed
229

230
231
def encodeCharArray(p, size):
    s = ""
232
    for i in xrange(size):
233
234
235
236
        s += "%02x" % int(p.dereference())
        p += 1
    return s

237
238
239
240
241
242
def encodeByteArray(value):
    d_ptr = value['d'].dereference()
    data = d_ptr['data']
    size = d_ptr['size']
    alloc = d_ptr['alloc']
    check(0 <= size and size <= alloc and alloc <= 100*1000*1000)
243
    checkRef(d_ptr["ref"])
244
245
246
247
248
249
    if size > 0:
        checkAccess(data, 4)
        checkAccess(data + size) == 0

    innerType = gdb.lookup_type("char")
    p = gdb.Value(data.cast(innerType.pointer()))
250
    return encodeCharArray(p, size)
251
252
253
254
255
256
257
258
259
260

def encodeString(value):
    d_ptr = value['d'].dereference()
    data = d_ptr['data']
    size = d_ptr['size']
    alloc = d_ptr['alloc']
    check(0 <= size and size <= alloc and alloc <= 100*1000*1000)
    if size > 0:
        checkAccess(data, 4)
        checkAccess(data + size * 2) == 0
261
    checkRef(d_ptr["ref"])
262
263
    p = gdb.Value(d_ptr["data"])
    s = ""
264
    for i in xrange(size):
265
266
267
268
269
270
        val = int(p.dereference())
        s += "%02x" % (val % 256)
        s += "%02x" % (val / 256)
        p += 1
    return s

hjk's avatar
hjk committed
271
272
273
274
275
276
277
#######################################################################
#
# Item
#
#######################################################################

class Item:
278
    def __init__(self, value, parentiname, iname, name = None):
hjk's avatar
hjk committed
279
        self.value = value
280
281
282
283
        if iname is None:
            self.iname = parentiname
        else:
            self.iname = "%s.%s" % (parentiname, iname)
hjk's avatar
hjk committed
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
        self.name = name


#######################################################################
#
# FrameCommand
#
#######################################################################

class FrameCommand(gdb.Command):
    """Do fancy stuff. Usage bb --verbose expandedINames"""

    def __init__(self):
        super(FrameCommand, self).__init__("bb", gdb.COMMAND_OBSCURE)

    def invoke(self, arg, from_tty):
        args = arg.split(' ')
        #warn("ARG: %s" % arg)
        #warn("ARGS: %s" % args)
        useFancy = int(args[0])
        passExceptions = int(args[1])
        expandedINames = set()
        if len(args) > 2:
307
            expandedINames = set(args[2].split(","))
hjk's avatar
hjk committed
308
309
310
311
        #warn("EXPANDED INAMES: %s" % expandedINames)
        module = sys.modules[__name__]
        self.dumpers = {}

hjk's avatar
hjk committed
312
313
314
        if useFancy == -1:
            output = "dumpers=["
            for key, value in module.__dict__.items():
315
                if key.startswith("qdump__"):
hjk's avatar
hjk committed
316
317
                    if output != "dumpers=[":
                        output += ","
318
                    output += '"' + key[7:] + '"'
hjk's avatar
hjk committed
319
320
321
322
323
324
325
326
327
328
329
            output += "],"
            #output += "qtversion=[%d,%d,%d]"
            output += "qtversion=[4,6,0],"
            output += "namespace=\"%s\"," % qtNamespace()
            output += "dumperversion=\"2.0\","
            output += "sizes=[],"
            output += "expressions=[]"
            output += "]"
            print output
            return
  
330

hjk's avatar
hjk committed
331
332
333
        if useFancy:
            for key, value in module.__dict__.items():
                #if callable(value):
334
335
                if key.startswith("qdump__"):
                    self.dumpers[key[7:]] = value
hjk's avatar
hjk committed
336
337
338
339

        d = Dumper()
        d.dumpers = self.dumpers
        d.passExceptions = passExceptions
340
        d.ns = qtNamespace()
341
342
        d.expandedINames = expandedINames
        d.useFancy = useFancy
hjk's avatar
hjk committed
343
344
        #warn(" NAMESPACE IS: '%s'" % d.ns)

345
346
347
        #
        # Locals
        #
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
        for item in listOfLocals():
            #warn("ITEM %s: " % item.value)

            type = item.value.type
            if type.code == gdb.TYPE_CODE_PTR \
                    and item.name == "argv" and str(type) == "char **":
                # Special handling for char** argv:
                n = 0
                p = item.value
                while not isNull(p.dereference()) and n <= 100:
                    p += 1
                    n += 1

                d.beginHash()
                d.put('iname="%s",' % item.iname)
                d.putName(item.name)
                d.putItemCount(select(n <= 100, n, "> 100"))
                d.putType(type)
                d.putNumChild(n)
                if d.isExpanded(item):
368
                    p = item.value
369
                    d.beginChildren(n)
370
                    for i in xrange(n):
371
372
                        value = p.dereference()
                        d.putItem(Item(value, item.iname, i, None))
373
                        p += 1
374
375
376
377
378
379
380
381
382
383
384
385
                    if n > 100:
                        d.putEllipsis()
                    d.endChildren()
                d.endHash()

            else:
                # A "normal" local variable or parameter
                d.beginHash()
                d.put('iname="%s",' % item.iname)
                d.put('addr="%s",' % item.value.address)
                d.safePutItemHelper(item)
                d.endHash()
hjk's avatar
hjk committed
386

387
388
389
390
        d.pushOutput()
        locals = d.safeoutput


391
392
393
        #
        # Watchers
        #
394
395
396
397
        d.safeoutput = ""
        watchers = ""
        if len(args) > 3:
            watchers = base64.b16decode(args[3], True)
398
399
400
401
        if len(watchers) > 0:
            for watcher in watchers.split("$$"):
                (exp, name) = watcher.split("$")
                self.handleWatch(d, exp, name)
402
403
404
405
406
407
408
409
410
411
        d.pushOutput()
        watchers = d.safeoutput

        print('locals={iname="local",name="Locals",value=" ",type=" ",'
            + 'children=[' + locals + ']},'
            + 'watchers={iname="watch",name="Watchers",value=" ",type=" ",'
            + 'children=[' + watchers + ']}')


    def handleWatch(self, d, exp, name):
412
        #warn("HANDLING WATCH %s, NAME: %s" % (exp, name))
413
        if exp.startswith("["):
414
            #warn("EVAL: EXP: %s" % exp)
415
416
417
            d.beginHash()
            d.put('iname="watch.%s",' % name)
            d.put('name="%s",' % exp)
418
            d.put('exp="%s",' % exp)
419
420
            try:
                list = eval(exp)
421
                #warn("EVAL: LIST: %s" % list)
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
                d.put('value=" "')
                d.put('type=" "')
                d.put('numchild="%d"' % len(list))
                # This is a list of expressions to evaluate
                d.beginChildren(len(list))
                itemNumber = 0
                for item in list:
                    self.handleWatch(d, item, "%s.%d" % (name, itemNumber))
                    itemNumber += 1
                d.endChildren()
            except:
                warn("EVAL: ERROR CAUGHT")
                d.put('value="<syntax error>"')
                d.put('type=" "')
                d.put('numchild="0"')
                d.beginChildren(0)
                d.endChildren()
            d.endHash()
            return

        d.beginHash()
        d.put('iname="watch.%s",' % name)
        d.put('name="%s",' % exp)
445
        d.put('exp="%s",' % exp)
446
447
448
449
450
        handled = False
        if exp == "<Edit>":
            d.put(',value=" ",')
            d.put('type=" ",numchild="0"')
        else:
451
            try:
452
                value = parseAndEvaluate(exp)
453
                item = Item(value, "watch", None, None)
454
                d.safePutItemHelper(item)
455
            except RuntimeError:
456
457
458
                d.put(',value="<invalid>",')
                d.put('type="<unknown>",numchild="0"')
        d.endHash()
459

hjk's avatar
hjk committed
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476

FrameCommand()



#######################################################################
#
# The Dumper Class
#
#######################################################################

class Dumper:
    def __init__(self):
        self.output = ""
        self.safeoutput = ""
        self.childTypes = [""]
        self.childNumChilds = [-1]
477
478
        self.maxNumChilds = [-1]
        self.numChilds = [-1]
hjk's avatar
hjk committed
479
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

    def put(self, value):
        self.output += value

    def putCommaIfNeeded(self):
        c = self.output[-1:]
        if c == '}' or c == '"' or c == ']' or c == '\n':
            self.put(',')
        #warn("C:'%s' COND:'%d' OUT:'%s'" %
        #    (c, c == '}' or c == '"' or c == ']' or c == '\n', self.output))

    def putField(self, name, value):
        self.putCommaIfNeeded()
        self.put('%s="%s"' % (name, value))

    def beginHash(self):
        self.putCommaIfNeeded()
        self.put('{')

    def endHash(self):
        self.put('}')

    def beginItem(self, name):
        self.putCommaIfNeeded()
        self.put(name)
        self.put('="')

    def endItem(self):
        self.put('"')

509
    def beginChildren(self, numChild_ = 1, childType_ = None, childNumChild_ = None):
hjk's avatar
hjk committed
510
511
        childType = ""
        childNumChild = -1
512
513
514
515
516
517
        if type(numChild_) is list:
            numChild = numChild_[0]
            maxNumChild = numChild_[1]
        else:
            numChild = numChild_
            maxNumChild = numChild_
518
        if numChild == 0:
519
            childType_ = None
520
        self.putCommaIfNeeded()
521
522
        if not childType_ is None:
            childType = stripClassTag(str(childType_))
523
            self.put('childtype="%s",' % childType)
524
            if isSimpleType(childType_) or isStringType(self, childType_):
525
                self.put('childnumchild="0",')
hjk's avatar
hjk committed
526
                childNumChild = 0
527
            elif childType_.code == gdb.TYPE_CODE_PTR:
528
                self.put('childnumchild="1",')
hjk's avatar
hjk committed
529
                childNumChild = 1
530
531
532
        if not childNumChild_ is None:
            self.put('childnumchild="%s",' % childNumChild_)
            childNumChild = childNumChild_
hjk's avatar
hjk committed
533
534
        self.childTypes.append(childType)
        self.childNumChilds.append(childNumChild)
535
536
        self.numChilds.append(numChild)
        self.maxNumChilds.append(maxNumChild)
hjk's avatar
hjk committed
537
538
539
540
541
        #warn("BEGIN: %s" % self.childTypes)
        self.put("children=[")

    def endChildren(self):
        #warn("END: %s" % self.childTypes)
542
543
544
545
        numChild = self.numChilds.pop()
        maxNumChild = self.maxNumChilds.pop()
        if maxNumChild < numChild:
            self.putEllipsis();
hjk's avatar
hjk committed
546
547
548
549
        self.childTypes.pop()
        self.childNumChilds.pop()
        self.put(']')

550
551
552
    def childRange(self):
        return xrange(qmin(self.maxNumChilds[-1], self.numChilds[-1]))

hjk's avatar
hjk committed
553
554
555
556
557
558
559
560
561
562
563
564
565
566
    # convenience
    def putItemCount(self, count):
        self.putCommaIfNeeded()
        self.put('value="<%s items>"' % count)

    def putEllipsis(self):
        self.putCommaIfNeeded()
        self.put('{name="<incomplete>",value="",type="",numchild="0"}')

    def putType(self, type):
        #warn("TYPES: '%s' '%s'" % (type, self.childTypes))
        #warn("  EQUAL 2: %s " % (str(type) == self.childTypes[-1]))
        type = stripClassTag(str(type))
        if len(type) > 0 and type != self.childTypes[-1]:
567
568
            self.putCommaIfNeeded()
            self.put('type="%s"' % type) # str(type.unqualified()) ?
hjk's avatar
hjk committed
569
570
571

    def putNumChild(self, numchild):
        #warn("NUM CHILD: '%s' '%s'" % (numchild, self.childNumChilds[-1]))
572
573
        if numchild != self.childNumChilds[-1]:
            self.put(',numchild="%s"' % numchild)
hjk's avatar
hjk committed
574

575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
    def putValue(self, value, encoding = None):
        if not encoding is None:
            self.putField("valueencoded", encoding)
        self.putField("value", value)

    def putStringValue(self, value):
        str = encodeString(value)
        self.putCommaIfNeeded()
        self.put('valueencoded="%d",value="%s"' % (7, str))

    def putByteArrayValue(self, value):
        str = encodeByteArray(value)
        self.putCommaIfNeeded()
        self.put('valueencoded="%d",value="%s"' % (6, str))
    
    def putName(self, name):
        self.putCommaIfNeeded()
        self.put('name="%s"' % name)

hjk's avatar
hjk committed
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
    def isExpanded(self, item):
        #warn("IS EXPANDED: %s in %s" % (item.iname, self.expandedINames))
        if item.iname is None:
            raise "Illegal iname 'None'"
        if item.iname.startswith("None"):
            raise "Illegal iname '%s'" % item.iname
        #warn("   --> %s" % (item.iname in self.expandedINames))
        return item.iname in self.expandedINames

    def isExpandedIName(self, iname):
        return iname in self.expandedINames

    def unputField(self, name):
        pos = self.output.rfind(",")
        if self.output[pos + 1:].startswith(name):
            self.output = self.output[0:pos]

    def stripNamespaceFromType(self, typeobj):
612
613
614
615
616
        # This breaks for dumpers type names containing '__star'.
        # But this should not happen as identifiers containing two
        # subsequent underscores are reserved for the implemention.
        if typeobj.code == gdb.TYPE_CODE_PTR:
            return self.stripNamespaceFromType(typeobj.target()) + "__star"
hjk's avatar
hjk committed
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
        # FIXME: pass ns from plugin
        type = stripClassTag(str(typeobj))
        if len(self.ns) > 0 and type.startswith(self.ns):
            type = type[len(self.ns):]
        pos = type.find("<")
        if pos != -1:
            type = type[0:pos]
        return type

    def isMovableType(self, type):
        if type.code == gdb.TYPE_CODE_PTR:
            return True
        if isSimpleType(type):
            return True
        return self.stripNamespaceFromType(type) in movableTypes

    def putIntItem(self, name, value):
        self.beginHash()
635
636
        self.putName(name)
        self.putValue(value)
hjk's avatar
hjk committed
637
638
639
640
641
642
        self.putType("int")
        self.putNumChild(0)
        self.endHash()

    def putBoolItem(self, name, value):
        self.beginHash()
643
644
        self.putName(name)
        self.putValue(value)
hjk's avatar
hjk committed
645
646
647
648
649
650
651
652
653
        self.putType("bool")
        self.putNumChild(0)
        self.endHash()

    def pushOutput(self):
        #warn("PUSH OUTPUT: %s " % self.output)
        self.safeoutput += self.output
        self.output = ""

654
    def dumpInnerValueHelper(self, item):
hjk's avatar
hjk committed
655
        if isSimpleType(item.value.type):
656
            self.safePutItemHelper(item)
hjk's avatar
hjk committed
657

658
659
660
661
662
    def safePutItem(self, item):
        self.beginHash()
        self.safePutItemHelper(item)
        self.endHash()

hjk's avatar
hjk committed
663
664
665
666
667
668
669
670
671
672
673
674
    def safePutItemHelper(self, item):
        self.pushOutput()
        # This is only used at the top level to ensure continuation
        # after failures due to uninitialized or corrupted data.
        if self.passExceptions:
            # for debugging reasons propagate errors.
            self.putItemHelper(item)

        else:
            try:
                self.putItemHelper(item)

675
            except RuntimeError:
hjk's avatar
hjk committed
676
677
678
679
                self.output = ""
                # FIXME: Only catch debugger related exceptions
                #exType, exValue, exTraceback = sys.exc_info()
                #tb = traceback.format_exception(exType, exValue, exTraceback)
680
                #warn("Exception: %s" % ex.message)
hjk's avatar
hjk committed
681
682
683
684
685
                # DeprecationWarning: BaseException.message
                # has been deprecated
                #warn("Exception.")
                #for line in tb:
                #    warn("%s" % line)
686
687
688
689
                self.putName(item.name)
                self.putValue("<invalid>")
                self.putType(str(item.value.type))
                self.putNumChild(0)
hjk's avatar
hjk committed
690
691
692
693
694
695
696
                #if self.isExpanded(item):
                self.beginChildren()
                self.endChildren()
        self.pushOutput()

    def putItem(self, item):
        self.beginHash()
hjk's avatar
hjk committed
697
        self.safePutItemHelper(item)
hjk's avatar
hjk committed
698
699
700
701
702
703
        self.endHash()

    def putCallItem(self, name, item, func):
        result = call(item.value, func)
        self.putItem(Item(result, item.iname, name, name))

704
    def putItemHelper(self, item):
hjk's avatar
hjk committed
705
706
        name = getattr(item, "name", None)
        if not name is None:
707
            self.putName(name)
hjk's avatar
hjk committed
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731

        # FIXME: Gui shows references stripped?
        #warn("REAL INAME: %s " % item.iname)
        #warn("REAL TYPE: %s " % item.value.type)
        #warn("REAL VALUE: %s " % item.value)

        value = item.value
        type = value.type

        if type.code == gdb.TYPE_CODE_REF:
            type = type.target()
            value = value.cast(type)

        if type.code == gdb.TYPE_CODE_TYPEDEF:
            type = type.target()

        strippedType = self.stripNamespaceFromType(
            type.strip_typedefs().unqualified()).replace("::", "__")
        
        #warn(" STRIPPED: %s" % strippedType)
        #warn(" DUMPERS: %s" % self.dumpers)
        #warn(" DUMPERS: %s" % (strippedType in self.dumpers))

        if isSimpleType(type):
732
733
            #warn("IS SIMPLE: %s " % type)
            self.putType(item.value.type)
734
735
            self.putValue(value)
            self.putNumChild(0)
hjk's avatar
hjk committed
736
737

        elif strippedType in self.dumpers:
738
739
            #warn("IS DUMPABLE: %s " % type)
            self.putType(item.value.type)
hjk's avatar
hjk committed
740
741
742
743
            self.dumpers[strippedType](self, item)

        elif type.code == gdb.TYPE_CODE_ENUM:
            #warn("GENERIC ENUM: %s" % value)
744
            self.putType(item.value.type)
745
            self.putValue(value)
hjk's avatar
hjk committed
746
747
748
749
            self.putNumChild(0)
            

        elif type.code == gdb.TYPE_CODE_PTR:
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
            if self.useFancy:
                #warn("A POINTER: %s" % value.type)
                isHandled = False
                if isNull(value):
                    self.putValue("0x0")
                    self.putType(item.value.type)
                    self.putNumChild(0)
                    isHandled = True

                target = str(type.target().unqualified())
                if target == "void" and not isHandled:
                    self.putType(item.value.type)
                    self.putValue(str(value))
                    self.putNumChild(0)
                    isHandled = True

                if target == "char" and not isHandled:
                    # Display values up to given length directly
                    self.putType(item.value.type)
                    firstNul = -1
                    p = value
771
                    for i in xrange(100):
772
773
774
775
776
777
778
779
780
781
782
783
784
                        if p.dereference() == 0:
                            # Found terminating NUL
                            self.putValue(encodeCharArray(value, i), "6")
                            self.putNumChild(0)
                            isHandled = True
                            break
                        p += 1

                if not isHandled:
                    ## Generic pointer type.
                    #warn("GENERIC POINTER: %s" % value)
                    innerType = item.value.type.target()
                    self.putType(innerType)
785
                    self.childTypes.append(
786
787
                        stripClassTag(str(innerType)))
                    self.putItemHelper(
788
                        Item(item.value.dereference(), item.iname, None, None))
789
                    self.childTypes.pop()
790
791
792
793
794
795
796
797
798
            else:
                self.putType(item.value.type)
                self.putValue(str(value.address))
                self.putNumChild(1)
                if self.isExpanded(item):
                    self.beginChildren()
                    self.putItem(
                          Item(item.value.dereference(), item.iname, "*", "*"))
                    self.endChildren()
hjk's avatar
hjk committed
799
800
801
802

        else:
            #warn("INAME: %s " % item.iname)
            #warn("INAMES: %s " % self.expandedINames)
803
            #warn("EXPANDED: %s " % (item.iname in self.expandedINames))
hjk's avatar
hjk committed
804
805
806
807
808

            # insufficient, see http://sourceware.org/bugzilla/show_bug.cgi?id=10953
            #fields = value.type.fields()
            fields = value.type.strip_typedefs().fields()

809
            self.putType(item.value.type)
810
            self.putValue("{...}")
hjk's avatar
hjk committed
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825

            if False:
                numfields = 0
                for field in fields:
                    bitpos = getattr(field, "bitpos", None)
                    if not bitpos is None:
                        ++numfields
            else:
                numfields = len(fields)
            self.putNumChild(numfields)

            if self.isExpanded(item):
                innerType = None
                if len(fields) == 1 and fields[0].name is None:
                    innerType = value.type.target()
826
                self.beginChildren(1, innerType)
hjk's avatar
hjk committed
827

828
                baseNumber = 0
hjk's avatar
hjk committed
829
830
831
832
833
834
835
836
837
838
839
                for field in fields:
                    #warn("FIELD: %s" % field)
                    #warn("  BITSIZE: %s" % field.bitsize)
                    #warn("  ARTIFICIAL: %s" % field.artificial)
                    bitpos = getattr(field, "bitpos", None)
                    if bitpos is None: # FIXME: Is check correct?
                        continue  # A static class member(?).

                    if field.name is None:
                        innerType = value.type.target()
                        p = value.cast(innerType.pointer())
840
                        for i in xrange(value.type.sizeof / innerType.sizeof):
hjk's avatar
hjk committed
841
842
843
844
845
846
847
848
849
850
851
                            self.putItem(Item(p.dereference(), item.iname, i, None))
                            p = p + 1
                        continue

                    # ignore vtable pointers for virtual inheritance
                    if field.name.startswith("_vptr."):
                        continue

                    #warn("FIELD NAME: %s" % field.name)
                    #warn("FIELD TYPE: %s" % field.type)
                    if field.name == stripClassTag(str(field.type)):
852
853
854
855
856
857
858
859
860
861
                        # Field is base type. We cannot use field.name as part
                        # of the iname as it might contain spaces and other
                        # strange characters.
                        child = Item(value.cast(field.type),
                            item.iname, "@%d" % baseNumber, field.name)
                        baseNumber += 1
                        self.beginHash()
                        self.putField("iname", child.iname)
                        self.safePutItemHelper(child)
                        self.endHash()
hjk's avatar
hjk committed
862
863
                    else:
                        # Data member.
864
865
866
867
868
869
870
                        child = Item(value[field.name],
                            item.iname, field.name, field.name)
                        if not child.name:
                            child.name = "<anon>"
                        self.beginHash()
                        self.safePutItemHelper(child)
                        self.endHash()
hjk's avatar
hjk committed
871
                self.endChildren()