# Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT # file at the top-level directory of this distribution and at # http://rust-lang.org/COPYRIGHT. # # 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. import gdb import re import debugger_pretty_printers_common as rustpp #=============================================================================== # GDB Pretty Printing Module for Rust #=============================================================================== class GdbType(rustpp.Type): def __init__(self, ty): super(GdbType, self).__init__() self.ty = ty self.fields = None def get_unqualified_type_name(self): tag = self.ty.tag if tag is None: return tag return tag.replace("&'static ", "&") def get_dwarf_type_kind(self): if self.ty.code == gdb.TYPE_CODE_STRUCT: return rustpp.DWARF_TYPE_CODE_STRUCT if self.ty.code == gdb.TYPE_CODE_UNION: return rustpp.DWARF_TYPE_CODE_UNION if self.ty.code == gdb.TYPE_CODE_PTR: return rustpp.DWARF_TYPE_CODE_PTR if self.ty.code == gdb.TYPE_CODE_ENUM: return rustpp.DWARF_TYPE_CODE_ENUM def get_fields(self): assert ((self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT) or (self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_UNION)) if self.fields is None: self.fields = list(self.ty.fields()) return self.fields def get_wrapped_value(self): return self.ty class GdbValue(rustpp.Value): def __init__(self, gdb_val): super(GdbValue, self).__init__(GdbType(gdb_val.type)) self.gdb_val = gdb_val self.children = {} def get_child_at_index(self, index): child = self.children.get(index) if child is None: gdb_field = get_field_at_index(self.gdb_val, index) child = GdbValue(self.gdb_val[gdb_field]) self.children[index] = child return child def as_integer(self): return int(self.gdb_val) def get_wrapped_value(self): return self.gdb_val def register_printers(objfile): """Registers Rust pretty printers for the given objfile""" objfile.pretty_printers.append(rust_pretty_printer_lookup_function) def rust_pretty_printer_lookup_function(gdb_val): """ Returns the correct Rust pretty printer for the given value if there is one """ val = GdbValue(gdb_val) type_kind = val.type.get_type_kind() if (type_kind == rustpp.TYPE_KIND_REGULAR_STRUCT or type_kind == rustpp.TYPE_KIND_EMPTY): return RustStructPrinter(val, omit_first_field = False, omit_type_name = False, is_tuple_like = False) if type_kind == rustpp.TYPE_KIND_STRUCT_VARIANT: return RustStructPrinter(val, omit_first_field = True, omit_type_name = False, is_tuple_like = False) if type_kind == rustpp.TYPE_KIND_SLICE: return RustSlicePrinter(val) if type_kind == rustpp.TYPE_KIND_STR_SLICE: return RustStringSlicePrinter(val) if type_kind == rustpp.TYPE_KIND_STD_VEC: return RustStdVecPrinter(val) if type_kind == rustpp.TYPE_KIND_STD_STRING: return RustStdStringPrinter(val) if type_kind == rustpp.TYPE_KIND_TUPLE: return RustStructPrinter(val, omit_first_field = False, omit_type_name = True, is_tuple_like = True) if type_kind == rustpp.TYPE_KIND_TUPLE_STRUCT: return RustStructPrinter(val, omit_first_field = False, omit_type_name = False, is_tuple_like = True) if type_kind == rustpp.TYPE_KIND_CSTYLE_VARIANT: return RustCStyleVariantPrinter(val.get_child_at_index(0)) if type_kind == rustpp.TYPE_KIND_TUPLE_VARIANT: return RustStructPrinter(val, omit_first_field = True, omit_type_name = False, is_tuple_like = True) if type_kind == rustpp.TYPE_KIND_SINGLETON_ENUM: variant = get_field_at_index(gdb_val, 0) return rust_pretty_printer_lookup_function(gdb_val[variant]) if type_kind == rustpp.TYPE_KIND_REGULAR_ENUM: # This is a regular enum, extract the discriminant discriminant_val = rustpp.get_discriminant_value_as_integer(val) variant = get_field_at_index(gdb_val, discriminant_val) return rust_pretty_printer_lookup_function(gdb_val[variant]) if type_kind == rustpp.TYPE_KIND_COMPRESSED_ENUM: encoded_enum_info = rustpp.EncodedEnumInfo(val) if encoded_enum_info.is_null_variant(): return IdentityPrinter(encoded_enum_info.get_null_variant_name()) non_null_val = encoded_enum_info.get_non_null_variant_val() return rust_pretty_printer_lookup_function(non_null_val.get_wrapped_value()) # No pretty printer has been found return None #=------------------------------------------------------------------------------ # Pretty Printer Classes #=------------------------------------------------------------------------------ class RustStructPrinter: def __init__(self, val, omit_first_field, omit_type_name, is_tuple_like): self.__val = val self.__omit_first_field = omit_first_field self.__omit_type_name = omit_type_name self.__is_tuple_like = is_tuple_like def to_string(self): if self.__omit_type_name: return None return self.__val.type.get_unqualified_type_name() def children(self): cs = [] wrapped_value = self.__val.get_wrapped_value() for field in self.__val.type.get_fields(): field_value = wrapped_value[field.name] if self.__is_tuple_like: cs.append(("", field_value)) else: cs.append((field.name, field_value)) if self.__omit_first_field: cs = cs[1:] return cs def display_hint(self): if self.__is_tuple_like: return "array" else: return "" class RustSlicePrinter: def __init__(self, val): self.__val = val def display_hint(self): return "array" def to_string(self): (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val) return (self.__val.type.get_unqualified_type_name() + ("(len: %i)" % length)) def children(self): cs = [] (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val) assert data_ptr.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR raw_ptr = data_ptr.get_wrapped_value() for index in range(0, length): cs.append((str(index), (raw_ptr + index).dereference())) return cs class RustStringSlicePrinter: def __init__(self, val): self.__val = val def to_string(self): (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val) raw_ptr = data_ptr.get_wrapped_value() return '"%s"' % raw_ptr.string(encoding="utf-8", length=length) class RustStdVecPrinter: def __init__(self, val): self.__val = val def display_hint(self): return "array" def to_string(self): (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val) return (self.__val.type.get_unqualified_type_name() + ("(len: %i, cap: %i)" % (length, cap))) def children(self): cs = [] (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val) gdb_ptr = data_ptr.get_wrapped_value() for index in range(0, length): cs.append((str(index), (gdb_ptr + index).dereference())) return cs class RustStdStringPrinter: def __init__(self, val): self.__val = val def to_string(self): vec = self.__val.get_child_at_index(0) (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(vec) return '"%s"' % data_ptr.get_wrapped_value().string(encoding="utf-8", length=length) class RustCStyleVariantPrinter: def __init__(self, val): assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ENUM self.__val = val def to_string(self): return str(self.__val.get_wrapped_value()) class IdentityPrinter: def __init__(self, string): self.string = string def to_string(self): return self.string def get_field_at_index(gdb_val, index): i = 0 for field in gdb_val.type.fields(): if i == index: return field i += 1 return None