## GDB ##
DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB=gdb_load_rust_pretty_printers.py \
- gdb_rust_pretty_printing.py
+ gdb_rust_pretty_printing.py \
+ debugger_pretty_printers_common.py
DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB_ABS=\
$(foreach script,$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB), \
$(CFG_SRC_DIR)src/etc/$(script))
## LLDB ##
-DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB=lldb_rust_formatters.py
+DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB=lldb_rust_formatters.py \
+ debugger_pretty_printers_common.py
DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB_ABS=\
$(foreach script,$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB), \
$(CFG_SRC_DIR)src/etc/$(script))
--- /dev/null
+# Copyright 2015 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.
+
+"""
+This module provides an abstraction layer over common Rust pretty printing
+functionality needed by both GDB and LLDB.
+"""
+
+import re
+
+# Type codes that indicate the kind of type as it appears in DWARF debug
+# information. This code alone is not sufficient to determine the Rust type.
+# For example structs, tuples, fat pointers, or enum variants will all have
+# DWARF_TYPE_CODE_STRUCT.
+DWARF_TYPE_CODE_STRUCT = 1
+DWARF_TYPE_CODE_UNION = 2
+DWARF_TYPE_CODE_PTR = 3
+DWARF_TYPE_CODE_ARRAY = 4
+DWARF_TYPE_CODE_ENUM = 5
+
+# These constants specify the most specific kind of type that could be
+# determined for a given value.
+TYPE_KIND_UNKNOWN = -1
+TYPE_KIND_EMPTY = 0
+TYPE_KIND_SLICE = 1
+TYPE_KIND_REGULAR_STRUCT = 2
+TYPE_KIND_TUPLE = 3
+TYPE_KIND_TUPLE_STRUCT = 4
+TYPE_KIND_CSTYLE_VARIANT = 5
+TYPE_KIND_TUPLE_VARIANT = 6
+TYPE_KIND_STRUCT_VARIANT = 7
+TYPE_KIND_STR_SLICE = 8
+TYPE_KIND_STD_VEC = 9
+TYPE_KIND_STD_STRING = 10
+TYPE_KIND_REGULAR_ENUM = 11
+TYPE_KIND_COMPRESSED_ENUM = 12
+TYPE_KIND_SINGLETON_ENUM = 13
+TYPE_KIND_CSTYLE_ENUM = 14
+TYPE_KIND_PTR = 15
+TYPE_KIND_FIXED_SIZE_VEC = 16
+
+ENCODED_ENUM_PREFIX = "RUST$ENCODED$ENUM$"
+ENUM_DISR_FIELD_NAME = "RUST$ENUM$DISR"
+
+# Slice related constants
+SLICE_FIELD_NAME_DATA_PTR = "data_ptr"
+SLICE_FIELD_NAME_LENGTH = "length"
+SLICE_FIELD_NAMES = [SLICE_FIELD_NAME_DATA_PTR, SLICE_FIELD_NAME_LENGTH]
+
+# std::Vec<> related constants
+STD_VEC_FIELD_NAME_DATA_PTR = "ptr"
+STD_VEC_FIELD_NAME_LENGTH = "len"
+STD_VEC_FIELD_NAME_CAPACITY = "cap"
+STD_VEC_FIELD_NAMES = [STD_VEC_FIELD_NAME_DATA_PTR,
+ STD_VEC_FIELD_NAME_LENGTH,
+ STD_VEC_FIELD_NAME_CAPACITY]
+
+# std::String related constants
+STD_STRING_FIELD_NAMES = ["vec"]
+
+
+class Type(object):
+ """
+ This class provides a common interface for type-oriented operations.
+ Sub-classes are supposed to wrap a debugger-specific type-object and
+ provide implementations for the abstract methods in this class.
+ """
+
+ def __init__(self):
+ self.__type_kind = None
+
+ def get_unqualified_type_name(self):
+ """
+ Implementations of this method should return the unqualified name of the
+ type-object they are wrapping. Some examples:
+
+ 'int' -> 'int'
+ 'std::vec::Vec<std::string::String>' -> 'Vec<std::string::String>'
+ '&std::option::Option<std::string::String>' -> '&std::option::Option<std::string::String>'
+
+ As you can see, type arguments stay fully qualified.
+ """
+ raise NotImplementedError("Override this method")
+
+ def get_dwarf_type_kind(self):
+ """
+ Implementations of this method should return the correct
+ DWARF_TYPE_CODE_* value for the wrapped type-object.
+ """
+ raise NotImplementedError("Override this method")
+
+ def get_fields(self):
+ """
+ Implementations of this method should return a list of field-objects of
+ this type. For Rust-enums (i.e. with DWARF_TYPE_CODE_UNION) these field-
+ objects represent the variants of the enum. Field-objects must have a
+ `name` attribute that gives their name as specified in DWARF.
+ """
+ assert ((self.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT) or
+ (self.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION))
+ raise NotImplementedError("Override this method")
+
+ def get_wrapped_value(self):
+ """
+ Returns the debugger-specific type-object wrapped by this object. This
+ is sometimes needed for doing things like pointer-arithmetic in GDB.
+ """
+ raise NotImplementedError("Override this method")
+
+ def get_type_kind(self):
+ """This method returns the TYPE_KIND_* value for this type-object."""
+ if self.__type_kind is None:
+ dwarf_type_code = self.get_dwarf_type_kind()
+
+ if dwarf_type_code == DWARF_TYPE_CODE_STRUCT:
+ self.__type_kind = self.__classify_struct()
+ elif dwarf_type_code == DWARF_TYPE_CODE_UNION:
+ self.__type_kind = self.__classify_union()
+ elif dwarf_type_code == DWARF_TYPE_CODE_PTR:
+ self.__type_kind = TYPE_KIND_PTR
+ elif dwarf_type_code == DWARF_TYPE_CODE_ARRAY:
+ self.__type_kind = TYPE_KIND_FIXED_SIZE_VEC
+ else:
+ self.__type_kind = TYPE_KIND_UNKNOWN
+ return self.__type_kind
+
+ def __classify_struct(self):
+ assert self.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT
+
+ unqualified_type_name = self.get_unqualified_type_name()
+
+ # STR SLICE
+ if unqualified_type_name == "&str":
+ return TYPE_KIND_STR_SLICE
+
+ # REGULAR SLICE
+ if (unqualified_type_name.startswith("&[") and
+ unqualified_type_name.endswith("]") and
+ self.__conforms_to_field_layout(SLICE_FIELD_NAMES)):
+ return TYPE_KIND_SLICE
+
+ fields = self.get_fields()
+ field_count = len(fields)
+
+ # EMPTY STRUCT
+ if field_count == 0:
+ return TYPE_KIND_EMPTY
+
+ # STD VEC
+ if (unqualified_type_name.startswith("Vec<") and
+ self.__conforms_to_field_layout(STD_VEC_FIELD_NAMES)):
+ return TYPE_KIND_STD_VEC
+
+ # STD STRING
+ if (unqualified_type_name.startswith("String") and
+ self.__conforms_to_field_layout(STD_STRING_FIELD_NAMES)):
+ return TYPE_KIND_STD_STRING
+
+ # ENUM VARIANTS
+ if fields[0].name == ENUM_DISR_FIELD_NAME:
+ if field_count == 1:
+ return TYPE_KIND_CSTYLE_VARIANT
+ elif self.__all_fields_conform_to_tuple_field_naming(1):
+ return TYPE_KIND_TUPLE_VARIANT
+ else:
+ return TYPE_KIND_STRUCT_VARIANT
+
+ # TUPLE
+ if self.__all_fields_conform_to_tuple_field_naming(0):
+ if unqualified_type_name.startswith("("):
+ return TYPE_KIND_TUPLE
+ else:
+ return TYPE_KIND_TUPLE_STRUCT
+
+ # REGULAR STRUCT
+ return TYPE_KIND_REGULAR_STRUCT
+
+
+ def __classify_union(self):
+ assert self.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION
+
+ union_members = self.get_fields()
+ union_member_count = len(union_members)
+ if union_member_count == 0:
+ return TYPE_KIND_EMPTY
+ elif union_member_count == 1:
+ first_variant_name = union_members[0].name
+ if first_variant_name is None:
+ return TYPE_KIND_SINGLETON_ENUM
+ else:
+ assert first_variant_name.startswith(ENCODED_ENUM_PREFIX)
+ return TYPE_KIND_COMPRESSED_ENUM
+ else:
+ return TYPE_KIND_REGULAR_ENUM
+
+
+ def __conforms_to_field_layout(self, expected_fields):
+ actual_fields = self.get_fields()
+ actual_field_count = len(actual_fields)
+
+ if actual_field_count != len(expected_fields):
+ return False
+
+ for i in range(0, actual_field_count):
+ if actual_fields[i].name != expected_fields[i]:
+ return False
+
+ return True
+
+ def __all_fields_conform_to_tuple_field_naming(self, start_index):
+ fields = self.get_fields()
+ field_count = len(fields)
+
+ for i in range(start_index, field_count):
+ field_name = fields[i].name
+ if (field_name is None) or (re.match(r"__\d+$", field_name) is None):
+ return False
+ return True
+
+
+class Value(object):
+ """
+ This class provides a common interface for value-oriented operations.
+ Sub-classes are supposed to wrap a debugger-specific value-object and
+ provide implementations for the abstract methods in this class.
+ """
+ def __init__(self, ty):
+ self.type = ty
+
+ def get_child_at_index(self, index):
+ """Returns the value of the field, array element or variant at the given index"""
+ raise NotImplementedError("Override this method")
+
+ def as_integer(self):
+ """
+ Try to convert the wrapped value into a Python integer. This should
+ always succeed for values that are pointers or actual integers.
+ """
+ raise NotImplementedError("Override this method")
+
+ def get_wrapped_value(self):
+ """
+ Returns the debugger-specific value-object wrapped by this object. This
+ is sometimes needed for doing things like pointer-arithmetic in GDB.
+ """
+ raise NotImplementedError("Override this method")
+
+
+class EncodedEnumInfo(object):
+ """
+ This class provides facilities for handling enum values with compressed
+ encoding where a non-null field in one variant doubles as the discriminant.
+ """
+
+ def __init__(self, enum_val):
+ assert enum_val.type.get_type_kind() == TYPE_KIND_COMPRESSED_ENUM
+ variant_name = enum_val.type.get_fields()[0].name
+ last_separator_index = variant_name.rfind("$")
+ start_index = len(ENCODED_ENUM_PREFIX)
+ indices_substring = variant_name[start_index:last_separator_index].split("$")
+ self.__enum_val = enum_val
+ self.__disr_field_indices = [int(index) for index in indices_substring]
+ self.__null_variant_name = variant_name[last_separator_index + 1:]
+
+ def is_null_variant(self):
+ ty = self.__enum_val.type
+ sole_variant_val = self.__enum_val.get_child_at_index(0)
+ discriminant_val = sole_variant_val
+ for disr_field_index in self.__disr_field_indices:
+ discriminant_val = discriminant_val.get_child_at_index(disr_field_index)
+
+ # If the discriminant field is a fat pointer we have to consider the
+ # first word as the true discriminant
+ if discriminant_val.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT:
+ discriminant_val = discriminant_val.get_child_at_index(0)
+
+ return discriminant_val.as_integer() == 0
+
+ def get_non_null_variant_val(self):
+ return self.__enum_val.get_child_at_index(0)
+
+ def get_null_variant_name(self):
+ return self.__null_variant_name
+
+
+def get_discriminant_value_as_integer(enum_val):
+ assert enum_val.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION
+ # we can take any variant here because the discriminant has to be the same
+ # for all of them.
+ variant_val = enum_val.get_child_at_index(0)
+ disr_val = variant_val.get_child_at_index(0)
+ return disr_val.as_integer()
+
+
+def extract_length_ptr_and_cap_from_std_vec(vec_val):
+ assert vec_val.type.get_type_kind() == TYPE_KIND_STD_VEC
+ length_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_LENGTH)
+ ptr_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_DATA_PTR)
+ cap_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_CAPACITY)
+
+ length = vec_val.get_child_at_index(length_field_index).as_integer()
+ vec_ptr_val = vec_val.get_child_at_index(ptr_field_index)
+ capacity = vec_val.get_child_at_index(cap_field_index).as_integer()
+
+ unique_ptr_val = vec_ptr_val.get_child_at_index(0)
+ data_ptr = unique_ptr_val.get_child_at_index(0)
+ assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
+ return (length, data_ptr, capacity)
+
+def extract_length_and_ptr_from_slice(slice_val):
+ assert (slice_val.type.get_type_kind() == TYPE_KIND_SLICE or
+ slice_val.type.get_type_kind() == TYPE_KIND_STR_SLICE)
+
+ length_field_index = SLICE_FIELD_NAMES.index(SLICE_FIELD_NAME_LENGTH)
+ ptr_field_index = SLICE_FIELD_NAMES.index(SLICE_FIELD_NAME_DATA_PTR)
+
+ length = slice_val.get_child_at_index(length_field_index).as_integer()
+ data_ptr = slice_val.get_child_at_index(ptr_field_index)
+
+ assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
+ return (length, data_ptr)
import gdb
import re
+import debugger_pretty_printers_common as rustpp
#===============================================================================
# GDB Pretty Printing Module for Rust
#===============================================================================
+class GdbType(rustpp.Type):
-def register_printers(objfile):
- "Registers Rust pretty printers for the given objfile"
- objfile.pretty_printers.append(rust_pretty_printer_lookup_function)
+ def __init__(self, ty):
+ super(GdbType, self).__init__()
+ self.ty = ty
+ self.fields = None
+ def get_unqualified_type_name(self):
+ tag = self.ty.tag
-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
+ if tag is None:
+ return tag
- if type_code == gdb.TYPE_CODE_STRUCT:
- struct_kind = classify_struct(val.type)
+ return tag.replace("&'static ", "&")
- if struct_kind == STRUCT_KIND_SLICE:
- return RustSlicePrinter(val)
+ def get_dwarf_type_kind(self):
+ if self.ty.code == gdb.TYPE_CODE_STRUCT:
+ return rustpp.DWARF_TYPE_CODE_STRUCT
- if struct_kind == STRUCT_KIND_STR_SLICE:
- return RustStringSlicePrinter(val)
+ if self.ty.code == gdb.TYPE_CODE_UNION:
+ return rustpp.DWARF_TYPE_CODE_UNION
- if struct_kind == STRUCT_KIND_STD_VEC:
- return RustStdVecPrinter(val)
+ if self.ty.code == gdb.TYPE_CODE_PTR:
+ return rustpp.DWARF_TYPE_CODE_PTR
- if struct_kind == STRUCT_KIND_STD_STRING:
- return RustStdStringPrinter(val)
+ if self.ty.code == gdb.TYPE_CODE_ENUM:
+ return rustpp.DWARF_TYPE_CODE_ENUM
- if struct_kind == STRUCT_KIND_TUPLE:
- return RustTuplePrinter(val)
+ 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
- if struct_kind == STRUCT_KIND_TUPLE_STRUCT:
- return RustTupleStructPrinter(val, False)
+ def get_wrapped_value(self):
+ return self.ty
- 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)
+class GdbValue(rustpp.Value):
+ def __init__(self, gdb_val):
+ super(GdbValue, self).__init__(GdbType(gdb_val.type))
+ self.gdb_val = gdb_val
+ self.children = {}
- if struct_kind == STRUCT_KIND_STRUCT_VARIANT:
- return RustStructPrinter(val, True)
+ 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
- return RustStructPrinter(val, False)
+ def as_integer(self):
+ return int(self.gdb_val)
- # Enum handling
- if type_code == gdb.TYPE_CODE_UNION:
- enum_members = list(val.type.fields())
- enum_member_count = len(enum_members)
+ def get_wrapped_value(self):
+ return self.gdb_val
- 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 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]
-
- # 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)
-
- return rust_pretty_printer_lookup_function(sole_variant_val)
+def register_printers(objfile):
+ """Registers Rust pretty printers for the given objfile"""
+ objfile.pretty_printers.append(rust_pretty_printer_lookup_function)
- # 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
+def rust_pretty_printer_lookup_function(gdb_val):
+ """
+ Returns the correct Rust pretty printer for the given value
+ if there is one
+ """
-#=------------------------------------------------------------------------------
-# Pretty Printer Classes
-#=------------------------------------------------------------------------------
+ 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)
-class RustStructPrinter:
- def __init__(self, val, hide_first_field):
- self.val = val
- self.hide_first_field = hide_first_field
+ if type_kind == rustpp.TYPE_KIND_STRUCT_VARIANT:
+ return RustStructPrinter(val,
+ omit_first_field = True,
+ omit_type_name = False,
+ is_tuple_like = False)
- def to_string(self):
- return self.val.type.tag
+ if type_kind == rustpp.TYPE_KIND_SLICE:
+ return RustSlicePrinter(val)
- 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 type_kind == rustpp.TYPE_KIND_STR_SLICE:
+ return RustStringSlicePrinter(val)
- return cs
+ if type_kind == rustpp.TYPE_KIND_STD_VEC:
+ return RustStdVecPrinter(val)
+ if type_kind == rustpp.TYPE_KIND_STD_STRING:
+ return RustStdStringPrinter(val)
-class RustTuplePrinter:
- def __init__(self, val):
- self.val = val
+ if type_kind == rustpp.TYPE_KIND_TUPLE:
+ return RustStructPrinter(val,
+ omit_first_field = False,
+ omit_type_name = True,
+ is_tuple_like = True)
- def to_string(self):
- return None
+ if type_kind == rustpp.TYPE_KIND_TUPLE_STRUCT:
+ return RustStructPrinter(val,
+ omit_first_field = False,
+ omit_type_name = False,
+ is_tuple_like = True)
- def children(self):
- cs = []
- for field in self.val.type.fields():
- cs.append(("", self.val[field]))
+ if type_kind == rustpp.TYPE_KIND_CSTYLE_VARIANT:
+ return RustCStyleVariantPrinter(val.get_child_at_index(0))
- return cs
+ if type_kind == rustpp.TYPE_KIND_TUPLE_VARIANT:
+ return RustStructPrinter(val,
+ omit_first_field = True,
+ omit_type_name = False,
+ is_tuple_like = True)
- def display_hint(self):
- return "array"
+ 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())
-class RustTupleStructPrinter:
- def __init__(self, val, hide_first_field):
- self.val = val
- self.hide_first_field = hide_first_field
+ 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):
- return self.val.type.tag
+ if self.__omit_type_name:
+ return None
+ return self.__val.type.get_unqualified_type_name()
def children(self):
cs = []
- for field in self.val.type.fields():
- cs.append(("", self.val[field]))
+ 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.hide_first_field:
+ if self.__omit_first_field:
cs = cs[1:]
return cs
def display_hint(self):
- return "array"
+ if self.__is_tuple_like:
+ return "array"
+ else:
+ return ""
+
class RustSlicePrinter:
def __init__(self, val):
- self.val = val
+ self.__val = val
def display_hint(self):
return "array"
def to_string(self):
- length = int(self.val["length"])
- return self.val.type.tag + ("(len: %i)" % length)
+ (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 = int(self.val["length"])
- data_ptr = self.val["data_ptr"]
- assert data_ptr.type.code == gdb.TYPE_CODE_PTR
- pointee_type = data_ptr.type.target()
+ (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), (data_ptr + index).dereference()))
+ cs.append((str(index), (raw_ptr + index).dereference()))
return cs
+
class RustStringSlicePrinter:
def __init__(self, val):
- self.val = 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)
+ (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
+ self.__val = val
def display_hint(self):
return "array"
def to_string(self):
- length = int(self.val["len"])
- cap = int(self.val["cap"])
- return self.val.type.tag + ("(len: %i, cap: %i)" % (length, cap))
+ (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) = extract_length_and_data_ptr_from_std_vec(self.val)
- pointee_type = data_ptr.type.target()
-
+ (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), (data_ptr + index).dereference()))
+ cs.append((str(index), (gdb_ptr + index).dereference()))
return cs
+
class RustStdStringPrinter:
def __init__(self, val):
- self.val = val
+ self.__val = val
def to_string(self):
- (length, data_ptr) = extract_length_and_data_ptr_from_std_vec(self.val["vec"])
- return '"%s"' % data_ptr.string(encoding="utf-8", length=length)
+ 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 RustCStyleEnumPrinter:
+class RustCStyleVariantPrinter:
def __init__(self, val):
- assert val.type.code == gdb.TYPE_CODE_ENUM
- self.val = val
+ assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ENUM
+ self.__val = val
def to_string(self):
- return str(self.val)
+ return str(self.__val.get_wrapped_value())
class IdentityPrinter:
def to_string(self):
return self.string
-STRUCT_KIND_REGULAR_STRUCT = 0
-STRUCT_KIND_TUPLE_STRUCT = 1
-STRUCT_KIND_TUPLE = 2
-STRUCT_KIND_TUPLE_VARIANT = 3
-STRUCT_KIND_STRUCT_VARIANT = 4
-STRUCT_KIND_CSTYLE_VARIANT = 5
-STRUCT_KIND_SLICE = 6
-STRUCT_KIND_STR_SLICE = 7
-STRUCT_KIND_STD_VEC = 8
-STRUCT_KIND_STD_STRING = 9
-
-
-def classify_struct(type):
- # print("\nclassify_struct: tag=%s\n" % type.tag)
- if type.tag == "&str":
- return STRUCT_KIND_STR_SLICE
-
- if type.tag.startswith("&[") and type.tag.endswith("]"):
- return STRUCT_KIND_SLICE
-
- fields = list(type.fields())
- field_count = len(fields)
-
- if field_count == 0:
- return STRUCT_KIND_REGULAR_STRUCT
-
- if (field_count == 3 and
- fields[0].name == "ptr" and
- fields[1].name == "len" and
- fields[2].name == "cap" and
- type.tag.startswith("Vec<")):
- return STRUCT_KIND_STD_VEC
-
- if (field_count == 1 and
- fields[0].name == "vec" and
- type.tag == "String"):
- return STRUCT_KIND_STD_STRING
-
- if fields[0].name == "RUST$ENUM$DISR":
- if field_count == 1:
- return STRUCT_KIND_CSTYLE_VARIANT
- elif all_fields_conform_to_tuple_field_naming(fields, 1):
- return STRUCT_KIND_TUPLE_VARIANT
- else:
- return STRUCT_KIND_STRUCT_VARIANT
-
- if all_fields_conform_to_tuple_field_naming(fields, 0):
- 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]))
-
-
-def first_field(val):
- for field in val.type.fields():
- return field
-
-def get_field_at_index(val, index):
+def get_field_at_index(gdb_val, index):
i = 0
- for field in val.type.fields():
+ for field in gdb_val.type.fields():
if i == index:
return field
i += 1
return None
-
-def all_fields_conform_to_tuple_field_naming(fields, start_index):
- for i in range(start_index, len(fields)):
- if (fields[i].name is None) or (re.match(r"__\d+$", fields[i].name) is None):
- return False
- return True
-
-def extract_length_and_data_ptr_from_std_vec(vec_val):
- length = int(vec_val["len"])
- vec_ptr_val = vec_val["ptr"]
- unique_ptr_val = vec_ptr_val[first_field(vec_ptr_val)]
- data_ptr = unique_ptr_val[first_field(unique_ptr_val)]
- assert data_ptr.type.code == gdb.TYPE_CODE_PTR
- return (length, data_ptr)
import lldb
import re
+import debugger_pretty_printers_common as rustpp
-def print_val(val, internal_dict):
- '''Prints the given value with Rust syntax'''
- type_class = val.GetType().GetTypeClass()
+#===============================================================================
+# LLDB Pretty Printing Module for Rust
+#===============================================================================
- if type_class == lldb.eTypeClassStruct:
- return print_struct_val(val, internal_dict)
+class LldbType(rustpp.Type):
- if type_class == lldb.eTypeClassUnion:
- return print_enum_val(val, internal_dict)
+ def __init__(self, ty):
+ super(LldbType, self).__init__()
+ self.ty = ty
+ self.fields = None
- if type_class == lldb.eTypeClassPointer:
- return print_pointer_val(val, internal_dict)
+ def get_unqualified_type_name(self):
+ qualified_name = self.ty.GetName()
- if type_class == lldb.eTypeClassArray:
- return print_fixed_size_vec_val(val, internal_dict)
+ if qualified_name is None:
+ return qualified_name
- return val.GetValue()
+ return extract_type_name(qualified_name).replace("&'static ", "&")
+ def get_dwarf_type_kind(self):
+ type_class = self.ty.GetTypeClass()
-#=--------------------------------------------------------------------------------------------------
-# Type-Specialized Printing Functions
-#=--------------------------------------------------------------------------------------------------
+ if type_class == lldb.eTypeClassStruct:
+ return rustpp.DWARF_TYPE_CODE_STRUCT
+
+ if type_class == lldb.eTypeClassUnion:
+ return rustpp.DWARF_TYPE_CODE_UNION
+
+ if type_class == lldb.eTypeClassPointer:
+ return rustpp.DWARF_TYPE_CODE_PTR
+
+ if type_class == lldb.eTypeClassArray:
+ return rustpp.DWARF_TYPE_CODE_ARRAY
+
+ if type_class == lldb.eTypeClassEnumeration:
+ return rustpp.DWARF_TYPE_CODE_ENUM
+
+ return None
+
+ 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 LldbValue(rustpp.Value):
+ def __init__(self, lldb_val):
+ ty = lldb_val.type
+ wty = LldbType(ty)
+ super(LldbValue, self).__init__(wty)
+ self.lldb_val = lldb_val
+ self.children = {}
+
+ def get_child_at_index(self, index):
+ child = self.children.get(index)
+ if child is None:
+ lldb_field = self.lldb_val.GetChildAtIndex(index)
+ child = LldbValue(lldb_field)
+ self.children[index] = child
+ return child
+
+ def as_integer(self):
+ return self.lldb_val.GetValueAsUnsigned()
+
+ def get_wrapped_value(self):
+ return self.lldb_val
+
+
+def print_val(lldb_val, internal_dict):
+ val = LldbValue(lldb_val)
+ type_kind = val.type.get_type_kind()
-def print_struct_val(val, internal_dict):
- '''Prints a struct, tuple, or tuple struct value with Rust syntax'''
- assert val.GetType().GetTypeClass() == lldb.eTypeClassStruct
+ if (type_kind == rustpp.TYPE_KIND_REGULAR_STRUCT or
+ type_kind == rustpp.TYPE_KIND_EMPTY):
+ return print_struct_val(val,
+ internal_dict,
+ omit_first_field = False,
+ omit_type_name = False,
+ is_tuple_like = False)
- if is_vec_slice(val):
+ if type_kind == rustpp.TYPE_KIND_STRUCT_VARIANT:
+ return print_struct_val(val,
+ internal_dict,
+ omit_first_field = True,
+ omit_type_name = False,
+ is_tuple_like = False)
+
+ if type_kind == rustpp.TYPE_KIND_SLICE:
return print_vec_slice_val(val, internal_dict)
- elif is_std_vec(val):
+
+ if type_kind == rustpp.TYPE_KIND_STR_SLICE:
+ return print_str_slice_val(val, internal_dict)
+
+ if type_kind == rustpp.TYPE_KIND_STD_VEC:
return print_std_vec_val(val, internal_dict)
- else:
- return print_struct_val_starting_from(0, val, internal_dict)
+ if type_kind == rustpp.TYPE_KIND_STD_STRING:
+ return print_std_string_val(val, internal_dict)
+
+ if type_kind == rustpp.TYPE_KIND_TUPLE:
+ return print_struct_val(val,
+ internal_dict,
+ omit_first_field = False,
+ omit_type_name = True,
+ is_tuple_like = True)
+
+ if type_kind == rustpp.TYPE_KIND_TUPLE_STRUCT:
+ return print_struct_val(val,
+ internal_dict,
+ omit_first_field = False,
+ omit_type_name = False,
+ is_tuple_like = True)
+
+ if type_kind == rustpp.TYPE_KIND_CSTYLE_VARIANT:
+ return val.type.get_unqualified_type_name()
+
+ if type_kind == rustpp.TYPE_KIND_TUPLE_VARIANT:
+ return print_struct_val(val,
+ internal_dict,
+ omit_first_field = True,
+ omit_type_name = False,
+ is_tuple_like = True)
+
+ if type_kind == rustpp.TYPE_KIND_SINGLETON_ENUM:
+ return print_val(lldb_val.GetChildAtIndex(0), internal_dict)
+
+ if type_kind == rustpp.TYPE_KIND_PTR:
+ return print_pointer_val(val, internal_dict)
+
+ if type_kind == rustpp.TYPE_KIND_FIXED_SIZE_VEC:
+ return print_fixed_size_vec_val(val, internal_dict)
+
+ 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)
+ return print_val(lldb_val.GetChildAtIndex(discriminant_val), internal_dict)
+
+ if type_kind == rustpp.TYPE_KIND_COMPRESSED_ENUM:
+ encoded_enum_info = rustpp.EncodedEnumInfo(val)
+ if encoded_enum_info.is_null_variant():
+ return encoded_enum_info.get_null_variant_name()
-def print_struct_val_starting_from(field_start_index, val, internal_dict):
+ non_null_val = encoded_enum_info.get_non_null_variant_val()
+ return print_val(non_null_val.get_wrapped_value(), internal_dict)
+
+ # No pretty printer has been found
+ return lldb_val.GetValue()
+
+
+#=--------------------------------------------------------------------------------------------------
+# Type-Specialized Printing Functions
+#=--------------------------------------------------------------------------------------------------
+
+def print_struct_val(val, internal_dict, omit_first_field, omit_type_name, is_tuple_like):
'''
Prints a struct, tuple, or tuple struct value with Rust syntax.
Ignores any fields before field_start_index.
'''
- assert val.GetType().GetTypeClass() == lldb.eTypeClassStruct
-
- t = val.GetType()
- type_name = extract_type_name(t.GetName())
- num_children = val.num_children
-
- if (num_children - field_start_index) == 0:
- # The only field of this struct is the enum discriminant
- return type_name
+ assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT
- is_tuple_like = type_is_tuple_like(t)
+ if omit_type_name:
+ type_name = ""
+ else:
+ type_name = val.type.get_unqualified_type_name()
if is_tuple_like:
template = "%(type_name)s(%(body)s)"
template = "%(type_name)s {\n%(body)s\n}"
separator = ", \n"
- if type_name.startswith("("):
- # this is a tuple, so don't print the type name
- type_name = ""
+ fields = val.type.get_fields()
def render_child(child_index):
this = ""
if not is_tuple_like:
- field_name = t.GetFieldAtIndex(child_index).GetName()
+ field_name = fields[child_index].name
this += field_name + ": "
- field_val = val.GetChildAtIndex(child_index)
+ field_val = val.get_child_at_index(child_index)
- if not field_val.IsValid():
- field = t.GetFieldAtIndex(child_index)
+ if not field_val.get_wrapped_value().IsValid():
+ field = fields[child_index]
# LLDB is not good at handling zero-sized values, so we have to help
# it a little
if field.GetType().GetByteSize() == 0:
else:
return this + "<invalid value>"
- return this + print_val(field_val, internal_dict)
+ return this + print_val(field_val.get_wrapped_value(), internal_dict)
+
+ if omit_first_field:
+ field_start_index = 1
+ else:
+ field_start_index = 0
- body = separator.join([render_child(idx) for idx in range(field_start_index, num_children)])
+ body = separator.join([render_child(idx) for idx in range(field_start_index, len(fields))])
return template % {"type_name": type_name,
"body": body}
-
-def print_enum_val(val, internal_dict):
- '''Prints an enum value with Rust syntax'''
-
- assert val.GetType().GetTypeClass() == lldb.eTypeClassUnion
-
- if val.num_children == 1:
- # This is either an enum with just one variant, or it is an Option-like
- # enum where the discriminant is encoded in a non-nullable pointer
- # field. We find out which one it is by looking at the member name of
- # the sole union variant. If it starts with "RUST$ENCODED$ENUM$" then
- # we have an Option-like enum.
- first_variant_name = val.GetChildAtIndex(0).GetName()
- if first_variant_name and first_variant_name.startswith("RUST$ENCODED$ENUM$"):
-
- # This is an Option-like enum. The position of the discriminator field is
- # encoded in the name which has the format:
- # RUST$ENCODED$ENUM$<index of discriminator field>$<name of null variant>
- last_separator_index = first_variant_name.rfind("$")
- if last_separator_index == -1:
- return "<invalid enum encoding: %s>" % first_variant_name
-
- start_index = len("RUST$ENCODED$ENUM$")
-
- # Extract indices of the discriminator field
- try:
- disr_field_indices = first_variant_name[start_index:last_separator_index].split("$")
- disr_field_indices = [int(index) for index in disr_field_indices]
- except:
- return "<invalid enum encoding: %s>" % first_variant_name
-
- # Read the discriminant
- disr_val = val.GetChildAtIndex(0)
- for index in disr_field_indices:
- disr_val = disr_val.GetChildAtIndex(index)
-
- # If the discriminant field is a fat pointer we have to consider the
- # first word as the true discriminant
- if disr_val.GetType().GetTypeClass() == lldb.eTypeClassStruct:
- disr_val = disr_val.GetChildAtIndex(0)
-
- if disr_val.GetValueAsUnsigned() == 0:
- # Null case: Print the name of the null-variant
- null_variant_name = first_variant_name[last_separator_index + 1:]
- return null_variant_name
- else:
- # Non-null case: Interpret the data as a value of the non-null variant type
- return print_struct_val_starting_from(0, val.GetChildAtIndex(0), internal_dict)
- else:
- # This is just a regular uni-variant enum without discriminator field
- return print_struct_val_starting_from(0, val.GetChildAtIndex(0), internal_dict)
-
- # If we are here, this is a regular enum with more than one variant
- disr_val = val.GetChildAtIndex(0).GetChildMemberWithName("RUST$ENUM$DISR")
- disr_type = disr_val.GetType()
-
- if disr_type.GetTypeClass() != lldb.eTypeClassEnumeration:
- return "<Invalid enum value encountered: Discriminator is not an enum>"
-
- variant_index = disr_val.GetValueAsUnsigned()
- return print_struct_val_starting_from(1, val.GetChildAtIndex(variant_index), internal_dict)
-
-
def print_pointer_val(val, internal_dict):
'''Prints a pointer value with Rust syntax'''
- assert val.GetType().IsPointerType()
+ assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR
sigil = "&"
- type_name = extract_type_name(val.GetType().GetName())
- if type_name and type_name[0:1] in ["&", "~", "*"]:
+ type_name = val.type.get_unqualified_type_name()
+ if type_name and type_name[0:1] in ["&", "*"]:
sigil = type_name[0:1]
- return sigil + hex(val.GetValueAsUnsigned()) #print_val(val.Dereference(), internal_dict)
+ return sigil + hex(val.as_integer())
def print_fixed_size_vec_val(val, internal_dict):
- assert val.GetType().GetTypeClass() == lldb.eTypeClassArray
+ assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ARRAY
+ lldb_val = val.get_wrapped_value()
output = "["
- for i in range(val.num_children):
- output += print_val(val.GetChildAtIndex(i), internal_dict)
- if i != val.num_children - 1:
+ for i in range(lldb_val.num_children):
+ output += print_val(lldb_val.GetChildAtIndex(i), internal_dict)
+ if i != lldb_val.num_children - 1:
output += ", "
output += "]"
def print_vec_slice_val(val, internal_dict):
- length = val.GetChildAtIndex(1).GetValueAsUnsigned()
-
- data_ptr_val = val.GetChildAtIndex(0)
- data_ptr_type = data_ptr_val.GetType()
-
- return "&[%s]" % print_array_of_values(val.GetName(),
- data_ptr_val,
+ (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(val)
+ return "&[%s]" % print_array_of_values(val.get_wrapped_value().GetName(),
+ data_ptr,
length,
internal_dict)
def print_std_vec_val(val, internal_dict):
- length = val.GetChildAtIndex(1).GetValueAsUnsigned()
-
- # Vec<> -> Unique<> -> NonZero<> -> *T
- data_ptr_val = val.GetChildAtIndex(0).GetChildAtIndex(0).GetChildAtIndex(0)
- data_ptr_type = data_ptr_val.GetType()
-
- return "vec![%s]" % print_array_of_values(val.GetName(),
- data_ptr_val,
+ (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(val)
+ return "vec![%s]" % print_array_of_values(val.get_wrapped_value().GetName(),
+ data_ptr,
length,
internal_dict)
+def print_str_slice_val(val, internal_dict):
+ (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(val)
+ return read_utf8_string(data_ptr, length)
+
+def print_std_string_val(val, internal_dict):
+ vec = val.get_child_at_index(0)
+ (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(vec)
+ return read_utf8_string(data_ptr, length)
+
#=--------------------------------------------------------------------------------------------------
# Helper Functions
#=--------------------------------------------------------------------------------------------------
-unqualified_type_markers = frozenset(["(", "[", "&", "*"])
-
+UNQUALIFIED_TYPE_MARKERS = frozenset(["(", "[", "&", "*"])
def extract_type_name(qualified_type_name):
'''Extracts the type name from a fully qualified path'''
- if qualified_type_name[0] in unqualified_type_markers:
+ if qualified_type_name[0] in UNQUALIFIED_TYPE_MARKERS:
return qualified_type_name
end_of_search = qualified_type_name.find("<")
else:
return qualified_type_name[index + 2:]
-
-def type_is_tuple_like(ty):
- '''Returns true of this is a type with field names (struct, struct-like enum variant)'''
- for field in ty.fields:
- if field.GetName() == "RUST$ENUM$DISR":
- # Ignore the enum discriminant field if there is one.
- continue
- if (field.GetName() is None) or (re.match(r"__\d+$", field.GetName()) is None):
- return False
- return True
-
-
-def is_vec_slice(val):
- ty = val.GetType()
- if ty.GetTypeClass() != lldb.eTypeClassStruct:
- return False
-
- if ty.GetNumberOfFields() != 2:
- return False
-
- if ty.GetFieldAtIndex(0).GetName() != "data_ptr":
- return False
-
- if ty.GetFieldAtIndex(1).GetName() != "length":
- return False
-
- type_name = extract_type_name(ty.GetName()).replace("&'static", "&").replace(" ", "")
- return type_name.startswith("&[") and type_name.endswith("]")
-
-def is_std_vec(val):
- ty = val.GetType()
- if ty.GetTypeClass() != lldb.eTypeClassStruct:
- return False
-
- if ty.GetNumberOfFields() != 3:
- return False
-
- if ty.GetFieldAtIndex(0).GetName() != "ptr":
- return False
-
- if ty.GetFieldAtIndex(1).GetName() != "len":
- return False
-
- if ty.GetFieldAtIndex(2).GetName() != "cap":
- return False
-
- return ty.GetName().startswith("collections::vec::Vec<")
-
-
def print_array_of_values(array_name, data_ptr_val, length, internal_dict):
'''Prints a contigous memory range, interpreting it as values of the
pointee-type of data_ptr_val.'''
- data_ptr_type = data_ptr_val.GetType()
- assert data_ptr_type.IsPointerType()
+ data_ptr_type = data_ptr_val.type
+ assert data_ptr_type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR
- element_type = data_ptr_type.GetPointeeType()
+ element_type = data_ptr_type.get_wrapped_value().GetPointeeType()
element_type_size = element_type.GetByteSize()
- start_address = data_ptr_val.GetValueAsUnsigned()
+ start_address = data_ptr_val.as_integer()
+ raw_value = data_ptr_val.get_wrapped_value()
def render_element(i):
address = start_address + i * element_type_size
- element_val = data_ptr_val.CreateValueFromAddress(array_name + ("[%s]" % i),
- address,
- element_type)
+ element_val = raw_value.CreateValueFromAddress(array_name + ("[%s]" % i),
+ address,
+ element_type)
return print_val(element_val, internal_dict)
return ', '.join([render_element(i) for i in range(length)])
+
+
+def read_utf8_string(ptr_val, byte_count):
+ error = lldb.SBError()
+ process = ptr_val.get_wrapped_value().GetProcess()
+ data = process.ReadMemory(ptr_val.as_integer(), byte_count, error)
+ if error.Success():
+ return '"%s"' % data.decode(encoding='UTF-8')
+ else:
+ return '<error: %s>' % error.GetCString()
+++ /dev/null
-// Copyright 2013-2015 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.
-
-// ignore-windows failing on win32 bot
-// ignore-freebsd: gdb package too new
-// ignore-lldb
-// ignore-android: FIXME(#10381)
-// compile-flags:-g
-// min-gdb-version 7.7
-
-// gdb-command: run
-
-// gdb-command: print slice
-// gdb-check:$1 = &[i32](len: 4) = {0, 1, 2, 3}
-
-// gdb-command: print vec
-// gdb-check:$2 = Vec<u64>(len: 4, cap: [...]) = {4, 5, 6, 7}
-
-// gdb-command: print str_slice
-// gdb-check:$3 = "IAMA string slice!"
-
-// gdb-command: print string
-// gdb-check:$4 = "IAMA string!"
-
-// gdb-command: print some
-// gdb-check:$5 = Some = {8}
-
-// gdb-command: print none
-// gdb-check:$6 = None
-
-#![allow(unused_variables)]
-
-fn main() {
-
- // &[]
- let slice: &[i32] = &[0, 1, 2, 3];
-
- // Vec
- let vec = vec![4u64, 5, 6, 7];
-
- // &str
- let str_slice = "IAMA string slice!";
-
- // String
- let string = "IAMA string!".to_string();
-
- // Option
- let some = Some(8i16);
- let none: Option<i64> = None;
-
- zzz(); // #break
-}
-
-fn zzz() { () }
// lldb-check:[...]$5 = Void
// lldb-command:print some_str
-// lldb-check:[...]$6 = Some(&str { data_ptr: [...], length: 3 })
+// lldb-check:[...]$6 = Some("abc")
// lldb-command:print none_str
// lldb-check:[...]$7 = None
--- /dev/null
+// Copyright 2013-2015 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.
+
+// ignore-windows failing on win32 bot
+// ignore-freebsd: gdb package too new
+// ignore-android: FIXME(#10381)
+// compile-flags:-g
+// min-gdb-version 7.7
+// min-lldb-version: 310
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command: run
+
+// gdb-command: print slice
+// gdb-check:$1 = &[i32](len: 4) = {0, 1, 2, 3}
+
+// gdb-command: print vec
+// gdb-check:$2 = Vec<u64>(len: 4, cap: [...]) = {4, 5, 6, 7}
+
+// gdb-command: print str_slice
+// gdb-check:$3 = "IAMA string slice!"
+
+// gdb-command: print string
+// gdb-check:$4 = "IAMA string!"
+
+// gdb-command: print some
+// gdb-check:$5 = Some = {8}
+
+// gdb-command: print none
+// gdb-check:$6 = None
+
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command: run
+
+// lldb-command: print slice
+// lldb-check:[...]$0 = &[0, 1, 2, 3]
+
+// lldb-command: print vec
+// lldb-check:[...]$1 = vec![4, 5, 6, 7]
+
+// lldb-command: print str_slice
+// lldb-check:[...]$2 = "IAMA string slice!"
+
+// lldb-command: print string
+// lldb-check:[...]$3 = "IAMA string!"
+
+// lldb-command: print some
+// lldb-check:[...]$4 = Some(8)
+
+// lldb-command: print none
+// lldb-check:[...]$5 = None
+
+
+#![allow(unused_variables)]
+
+fn main() {
+
+ // &[]
+ let slice: &[i32] = &[0, 1, 2, 3];
+
+ // Vec
+ let vec = vec![4u64, 5, 6, 7];
+
+ // &str
+ let str_slice = "IAMA string slice!";
+
+ // String
+ let string = "IAMA string!".to_string();
+
+ // Option
+ let some = Some(8i16);
+ let none: Option<i64> = None;
+
+ zzz(); // #break
+}
+
+fn zzz() { () }