aboutsummaryrefslogtreecommitdiffstats
path: root/etc/servo_gdb.py
blob: 0d535b1b27910d7e45a658ab4bf3f335c7f04e8c (plain) (blame)
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
29
30
31
32
33
34
35
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
76
77
78
79
80
81
82
83
84
85
86
87
88
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# Copyright 2013 The Servo Project Developers. See the COPYRIGHT
# file at the top-level directory of this distribution.
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms.

"""
A set of simple pretty printers for gdb to make debugging Servo a bit easier.

To load these, you need to add something like the following to your .gdbinit file:

python
import sys
sys.path.insert(0, '/home/<path to git checkout>/servo/src/etc')
import servo_gdb
servo_gdb.register_printers(None)
end
"""

import gdb


# Print Au in both raw value and CSS pixels
class AuPrinter:
    def __init__(self, val):
        self.val = val

    def to_string(self):
        i32_type = gdb.lookup_type("i32")
        au = self.val.cast(i32_type)
        return "{0}px".format(au / 60.0)


# Print a U8 bitfield as binary
class BitFieldU8Printer:
    def __init__(self, val):
        self.val = val

    def to_string(self):
        u8_type = gdb.lookup_type("u8")
        value = self.val.cast(u8_type)
        return "[{0:#010b}]".format(int(value))


# Print a struct with fields as children
class ChildPrinter:
    def __init__(self, val):
        self.val = val

    def children(self):
        children = []
        for f in self.val.type.fields():
            children.append((f.name, self.val[f.name]))
        return children

    def to_string(self):
        return None


# Allow a trusted node to be dereferenced in the debugger
class TrustedNodeAddressPrinter:
    def __init__(self, val):
        self.val = val

    def children(self):
        node_type = gdb.lookup_type("struct script::dom::node::Node").pointer()
        value = self.val.cast(node_type)
        return [('Node', value)]

    def to_string(self):
        return self.val.address


# Extract a node type ID from enum
class NodeTypeIdPrinter:
    def __init__(self, val):
        self.val = val

    def to_string(self):
        u8_ptr_type = gdb.lookup_type("u8").pointer()
        enum_0 = self.val.address.cast(u8_ptr_type).dereference()
        enum_type = self.val.type.fields()[int(enum_0)].type
        return str(enum_type).lstrip('struct ')


# Printer for std::Option<>
class OptionPrinter:
    def __init__(self, val):
        self.val = val

    def is_some(self):
        # Get size of discriminator
        d_size = self.val.type.fields()[0].type.sizeof

        if d_size > 0 and d_size <= 8:
            # Read first byte to check if None or Some
            ptr = self.val.address.cast(gdb.lookup_type("unsigned char").pointer())
            discriminator = int(ptr.dereference())
            return discriminator != 0

        raise "unhandled discriminator size"

    def children(self):
        if self.is_some():
            option_type = self.val.type

            # Get total size and size of value
            ptr = self.val.address.cast(gdb.lookup_type("unsigned char").pointer())
            t_size = option_type.sizeof
            value_type = option_type.fields()[1].type.fields()[1].type
            v_size = value_type.sizeof
            data_ptr = (ptr + t_size - v_size).cast(value_type.pointer()).dereference()
            return [('Some', data_ptr)]
        return [('None', None)]

    def to_string(self):
        return None


# Useful for debugging when type is unknown
class TestPrinter:
    def __init__(self, val):
        self.val = val

    def to_string(self):
        return "[UNKNOWN - type = {0}]".format(str(self.val.type))


type_map = [
    ('struct Au', AuPrinter),
    ('FlowFlags', BitFieldU8Printer),
    ('IntrinsicWidths', ChildPrinter),
    ('PlacementInfo', ChildPrinter),
    ('TrustedNodeAddress', TrustedNodeAddressPrinter),
    ('NodeTypeId', NodeTypeIdPrinter),
    ('Option', OptionPrinter),
]


def lookup_servo_type(val):
    val_type = str(val.type)
    for (type_name, printer) in type_map:
        if val_type == type_name or val_type.endswith("::" + type_name):
            return printer(val)
    return None
    # return TestPrinter(val)


def register_printers(obj):
    gdb.pretty_printers.append(lookup_servo_type)