# 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 or the MIT license # , 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//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)