about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--mk/debuggers.mk6
-rw-r--r--src/etc/debugger_pretty_printers_common.py328
-rwxr-xr-xsrc/etc/gdb_rust_pretty_printing.py399
-rw-r--r--src/etc/lldb_rust_formatters.py395
-rw-r--r--src/test/debuginfo/option-like-enum.rs2
-rw-r--r--src/test/debuginfo/pretty-std.rs (renamed from src/test/debuginfo/gdb-pretty-std.rs)28
6 files changed, 737 insertions, 421 deletions
diff --git a/mk/debuggers.mk b/mk/debuggers.mk
index e6a2174f84a..aa7b62e13b8 100644
--- a/mk/debuggers.mk
+++ b/mk/debuggers.mk
@@ -15,7 +15,8 @@
 
 ## 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))
@@ -27,7 +28,8 @@ DEBUGGER_BIN_SCRIPTS_GDB_ABS=\
 
 
 ## 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))
diff --git a/src/etc/debugger_pretty_printers_common.py b/src/etc/debugger_pretty_printers_common.py
new file mode 100644
index 00000000000..6e667b37a9c
--- /dev/null
+++ b/src/etc/debugger_pretty_printers_common.py
@@ -0,0 +1,328 @@
+# 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)
diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py
index fc4d15a5168..f93f3490215 100755
--- a/src/etc/gdb_rust_pretty_printing.py
+++ b/src/etc/gdb_rust_pretty_printing.py
@@ -10,246 +10,265 @@
 
 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:
@@ -259,91 +278,11 @@ 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)
diff --git a/src/etc/lldb_rust_formatters.py b/src/etc/lldb_rust_formatters.py
index 2aaa1588758..c22a60abf3f 100644
--- a/src/etc/lldb_rust_formatters.py
+++ b/src/etc/lldb_rust_formatters.py
@@ -10,58 +10,177 @@
 
 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)"
@@ -70,20 +189,18 @@ def print_struct_val_starting_from(field_start_index, val, internal_dict):
         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:
@@ -91,95 +208,38 @@ def print_struct_val_starting_from(field_start_index, val, internal_dict):
             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 += "]"
@@ -187,39 +247,38 @@ def print_fixed_size_vec_val(val, internal_dict):
 
 
 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("<")
@@ -232,72 +291,34 @@ def extract_type_name(qualified_type_name):
     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()
diff --git a/src/test/debuginfo/option-like-enum.rs b/src/test/debuginfo/option-like-enum.rs
index 65a83088d80..fba21d9a553 100644
--- a/src/test/debuginfo/option-like-enum.rs
+++ b/src/test/debuginfo/option-like-enum.rs
@@ -67,7 +67,7 @@
 // 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
diff --git a/src/test/debuginfo/gdb-pretty-std.rs b/src/test/debuginfo/pretty-std.rs
index c42f7f19839..576621737e6 100644
--- a/src/test/debuginfo/gdb-pretty-std.rs
+++ b/src/test/debuginfo/pretty-std.rs
@@ -10,10 +10,12 @@
 
 // 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
+// min-lldb-version: 310
+
+// === GDB TESTS ===================================================================================
 
 // gdb-command: run
 
@@ -35,6 +37,30 @@
 // 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() {