DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Git (ada95b9878)

VCS Links

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