diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py index b6770c99975f..c5587bb10d1d 100755 --- a/src/etc/gdb_rust_pretty_printing.py +++ b/src/etc/gdb_rust_pretty_printing.py @@ -14,181 +14,189 @@ import gdb # GDB Pretty Printing Module for Rust #=============================================================================== + def register_printers(objfile): - "Registers Rust pretty printers for the given objfile" - objfile.pretty_printers.append(rust_pretty_printer_lookup_function) + "Registers Rust pretty printers for the given objfile" + objfile.pretty_printers.append(rust_pretty_printer_lookup_function) + def rust_pretty_printer_lookup_function(val): - "Returns the correct Rust pretty printer for the given value if there is one" - type_code = val.type.code + "Returns the correct Rust pretty printer for the given value if there is one" + type_code = val.type.code - if type_code == gdb.TYPE_CODE_STRUCT: - struct_kind = classify_struct(val.type) + if type_code == gdb.TYPE_CODE_STRUCT: + struct_kind = classify_struct(val.type) - if struct_kind == STRUCT_KIND_STR_SLICE: - return RustStringSlicePrinter(val) + if struct_kind == STRUCT_KIND_STR_SLICE: + return RustStringSlicePrinter(val) - if struct_kind == STRUCT_KIND_TUPLE: - return RustTuplePrinter(val) + if struct_kind == STRUCT_KIND_TUPLE: + return RustTuplePrinter(val) - if struct_kind == STRUCT_KIND_TUPLE_STRUCT: - return RustTupleStructPrinter(val, False) + if struct_kind == STRUCT_KIND_TUPLE_STRUCT: + return RustTupleStructPrinter(val, False) - if struct_kind == STRUCT_KIND_CSTYLE_VARIANT: - return RustCStyleEnumPrinter(val[get_field_at_index(val, 0)]) + if struct_kind == STRUCT_KIND_CSTYLE_VARIANT: + return RustCStyleEnumPrinter(val[get_field_at_index(val, 0)]) - if struct_kind == STRUCT_KIND_TUPLE_VARIANT: - return RustTupleStructPrinter(val, True) + if struct_kind == STRUCT_KIND_TUPLE_VARIANT: + return RustTupleStructPrinter(val, True) - if struct_kind == STRUCT_KIND_STRUCT_VARIANT: - return RustStructPrinter(val, True) + if struct_kind == STRUCT_KIND_STRUCT_VARIANT: + return RustStructPrinter(val, True) - return RustStructPrinter(val, False) + return RustStructPrinter(val, False) - # Enum handling - if type_code == gdb.TYPE_CODE_UNION: - enum_members = list(val.type.fields()) - enum_member_count = len(enum_members) + # Enum handling + if type_code == gdb.TYPE_CODE_UNION: + enum_members = list(val.type.fields()) + enum_member_count = len(enum_members) - if enum_member_count == 0: - return RustStructPrinter(val, False) + if enum_member_count == 0: + return RustStructPrinter(val, False) - if enum_member_count == 1: - first_variant_name = enum_members[0].name - if first_variant_name == None: - # This is a singleton enum - return rust_pretty_printer_lookup_function(val[enum_members[0]]) - else: - assert first_variant_name.startswith("RUST$ENCODED$ENUM$") - # This is a space-optimized enum. - # This means this enum has only two states, and Rust uses one of the - # fields somewhere in the struct to determine which of the two states - # it's in. The location of the field is encoded in the name as something - # like RUST$ENCODED$ENUM$(num$)*name_of_zero_state - last_separator_index = first_variant_name.rfind("$") - start_index = len("RUST$ENCODED$ENUM$") - disr_field_indices = first_variant_name[start_index : - last_separator_index].split("$") - disr_field_indices = [int(index) for index in disr_field_indices] + if enum_member_count == 1: + first_variant_name = enum_members[0].name + if first_variant_name is None: + # This is a singleton enum + return rust_pretty_printer_lookup_function(val[enum_members[0]]) + else: + assert first_variant_name.startswith("RUST$ENCODED$ENUM$") + # This is a space-optimized enum. + # This means this enum has only two states, and Rust uses one + # of the fields somewhere in the struct to determine which of + # the two states it's in. The location of the field is encoded + # in the name as something like + # RUST$ENCODED$ENUM$(num$)*name_of_zero_state + last_separator_index = first_variant_name.rfind("$") + start_index = len("RUST$ENCODED$ENUM$") + disr_field_indices = first_variant_name[start_index:last_separator_index].split("$") + disr_field_indices = [int(index) for index in disr_field_indices] - sole_variant_val = val[enum_members[0]] - discriminant = sole_variant_val - for disr_field_index in disr_field_indices: - disr_field = get_field_at_index(discriminant, disr_field_index) - discriminant = discriminant[disr_field] + sole_variant_val = val[enum_members[0]] + discriminant = sole_variant_val + for disr_field_index in disr_field_indices: + disr_field = get_field_at_index(discriminant, disr_field_index) + discriminant = discriminant[disr_field] - # If the discriminant field is a fat pointer we have to consider the - # first word as the true discriminant - if discriminant.type.code == gdb.TYPE_CODE_STRUCT: - discriminant = discriminant[get_field_at_index(discriminant, 0)] + # If the discriminant field is a fat pointer we have to consider the + # first word as the true discriminant + if discriminant.type.code == gdb.TYPE_CODE_STRUCT: + discriminant = discriminant[get_field_at_index(discriminant, 0)] - if discriminant == 0: - null_variant_name = first_variant_name[last_separator_index + 1:] - return IdentityPrinter(null_variant_name) + if discriminant == 0: + null_variant_name = first_variant_name[last_separator_index + 1:] + return IdentityPrinter(null_variant_name) - return rust_pretty_printer_lookup_function(sole_variant_val) + return rust_pretty_printer_lookup_function(sole_variant_val) - # This is a regular enum, extract the discriminant - discriminant_name, discriminant_val = extract_discriminant_value(val) - return rust_pretty_printer_lookup_function(val[enum_members[discriminant_val]]) + # This is a regular enum, extract the discriminant + discriminant_name, discriminant_val = extract_discriminant_value(val) + return rust_pretty_printer_lookup_function(val[enum_members[discriminant_val]]) - # No pretty printer has been found - return None + # No pretty printer has been found + return None #=------------------------------------------------------------------------------ # Pretty Printer Classes #=------------------------------------------------------------------------------ + class RustStructPrinter: - def __init__(self, val, hide_first_field): - self.val = val - self.hide_first_field = hide_first_field + def __init__(self, val, hide_first_field): + self.val = val + self.hide_first_field = hide_first_field - def to_string(self): - return self.val.type.tag + def to_string(self): + return self.val.type.tag - def children(self): - cs = [] - for field in self.val.type.fields(): - field_name = field.name - # Normally the field name is used as a key to access the field value, - # because that's also supported in older versions of GDB... - field_key = field_name - if field_name == None: - field_name = "" - # ... but for fields without a name (as in tuples), we have to fall back - # to the newer method of using the field object directly as key. In - # older versions of GDB, this will just fail. - field_key = field - name_value_tuple = ( field_name, self.val[field_key] ) - cs.append( name_value_tuple ) + def children(self): + cs = [] + for field in self.val.type.fields(): + field_name = field.name + # Normally the field name is used as a key to access the field + # value, because that's also supported in older versions of GDB... + field_key = field_name + if field_name is None: + field_name = "" + # ... but for fields without a name (as in tuples), we have to + # fall back to the newer method of using the field object + # directly as key. In older versions of GDB, this will just + # fail. + field_key = field + name_value_tuple = (field_name, self.val[field_key]) + cs.append(name_value_tuple) - if self.hide_first_field: - cs = cs[1:] + if self.hide_first_field: + cs = cs[1:] + + return cs - return cs class RustTuplePrinter: - def __init__(self, val): - self.val = val + def __init__(self, val): + self.val = val - def to_string(self): - return None + def to_string(self): + return None - def children(self): - cs = [] - for field in self.val.type.fields(): - cs.append( ("", self.val[field]) ) + def children(self): + cs = [] + for field in self.val.type.fields(): + cs.append(("", self.val[field])) - return cs + return cs + + def display_hint(self): + return "array" - def display_hint(self): - return "array" class RustTupleStructPrinter: - def __init__(self, val, hide_first_field): - self.val = val - self.hide_first_field = hide_first_field + def __init__(self, val, hide_first_field): + self.val = val + self.hide_first_field = hide_first_field - def to_string(self): - return self.val.type.tag + def to_string(self): + return self.val.type.tag - def children(self): - cs = [] - for field in self.val.type.fields(): - cs.append( ("", self.val[field]) ) + def children(self): + cs = [] + for field in self.val.type.fields(): + cs.append(("", self.val[field])) - if self.hide_first_field: - cs = cs[1:] + if self.hide_first_field: + cs = cs[1:] - return cs + return cs + + def display_hint(self): + return "array" - def display_hint(self): - return "array" class RustStringSlicePrinter: - def __init__(self, val): - self.val = val + def __init__(self, val): + self.val = val + + def to_string(self): + slice_byte_len = self.val["length"] + return '"%s"' % self.val["data_ptr"].string(encoding="utf-8", length=slice_byte_len) - def to_string(self): - slice_byte_len = self.val["length"] - return '"%s"' % self.val["data_ptr"].string(encoding = "utf-8", - length = slice_byte_len) class RustCStyleEnumPrinter: - def __init__(self, val): - assert val.type.code == gdb.TYPE_CODE_ENUM - self.val = val + def __init__(self, val): + assert val.type.code == gdb.TYPE_CODE_ENUM + self.val = val + + def to_string(self): + return str(self.val) - def to_string(self): - return str(self.val) class IdentityPrinter: - def __init__(self, string): - self.string = string + def __init__(self, string): + self.string = string - def to_string(self): - return self.string + def to_string(self): + return self.string STRUCT_KIND_REGULAR_STRUCT = 0 STRUCT_KIND_TUPLE_STRUCT = 1 @@ -198,47 +206,51 @@ STRUCT_KIND_STRUCT_VARIANT = 4 STRUCT_KIND_CSTYLE_VARIANT = 5 STRUCT_KIND_STR_SLICE = 6 + def classify_struct(type): - if type.tag == "&str": - return STRUCT_KIND_STR_SLICE + if type.tag == "&str": + return STRUCT_KIND_STR_SLICE - fields = list(type.fields()) - field_count = len(fields) + fields = list(type.fields()) + field_count = len(fields) + + if field_count == 0: + return STRUCT_KIND_REGULAR_STRUCT + + if fields[0].name == "RUST$ENUM$DISR": + if field_count == 1: + return STRUCT_KIND_CSTYLE_VARIANT + elif fields[1].name is None: + return STRUCT_KIND_TUPLE_VARIANT + else: + return STRUCT_KIND_STRUCT_VARIANT + + if fields[0].name is None: + if type.tag.startswith("("): + return STRUCT_KIND_TUPLE + else: + return STRUCT_KIND_TUPLE_STRUCT - if field_count == 0: return STRUCT_KIND_REGULAR_STRUCT - if fields[0].name == "RUST$ENUM$DISR": - if field_count == 1: - return STRUCT_KIND_CSTYLE_VARIANT - elif fields[1].name == None: - return STRUCT_KIND_TUPLE_VARIANT - else: - return STRUCT_KIND_STRUCT_VARIANT - - if fields[0].name == None: - if type.tag.startswith("("): - return STRUCT_KIND_TUPLE - else: - return STRUCT_KIND_TUPLE_STRUCT - - return STRUCT_KIND_REGULAR_STRUCT def extract_discriminant_value(enum_val): - assert enum_val.type.code == gdb.TYPE_CODE_UNION - for variant_descriptor in enum_val.type.fields(): - variant_val = enum_val[variant_descriptor] - for field in variant_val.type.fields(): - return (field.name, int(variant_val[field])) + assert enum_val.type.code == gdb.TYPE_CODE_UNION + for variant_descriptor in enum_val.type.fields(): + variant_val = enum_val[variant_descriptor] + for field in variant_val.type.fields(): + return (field.name, int(variant_val[field])) + def first_field(val): - for field in val.type.fields(): - return field + for field in val.type.fields(): + return field + def get_field_at_index(val, index): - i = 0 - for field in val.type.fields(): - if i == index: - return field - i += 1 - return None + i = 0 + for field in val.type.fields(): + if i == index: + return field + i += 1 + return None