rust/src/etc/gdb_rust_pretty_printing.py
Michael Woerister d136714e04 debuginfo: Create common debugger pretty printer module.
GDB and LLDB pretty printers have some common functionality
and also access some common information, such as the layout of
standard library types. So far, this information has been
duplicated in the two pretty printing python modules. This
commit introduces a common module used by both debuggers.
2015-05-30 20:06:08 +02:00

289 lines
9.2 KiB
Python
Executable File

# 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 <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.
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