From 8b14227aa96cf1bfdfdf46e879837b0763073a1b Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356@users.noreply.github.com>
Date: Fri, 10 Jan 2025 01:53:25 -0600
Subject: [PATCH 01/14] add MSVC tuple providers

---
 src/etc/lldb_commands     |  6 ++++-
 src/etc/lldb_providers.py | 53 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands
index ef0c3740f03..71968f2dbe6 100644
--- a/src/etc/lldb_commands
+++ b/src/etc/lldb_commands
@@ -18,7 +18,10 @@ type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)NonZ
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^core::num::([a-z_]+::)*NonZero.+$" --category Rust
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::([a-z_]+::)+)PathBuf$" --category Rust
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust
-type synthetic add -l lldb_lookup.synthetic_lookup -x "^(.*)$" --category Rust
+type synthetic add -l lldb_lookup.MSVCStdSliceSyntheticProvider -x "^ref\$<slice2\$<.+> >" --category Rust
+type synthetic add -l lldb_lookup.MSVCTupleSyntheticProvider -x "^tuple\$<.+>$" --category Rust
+type summary add -F lldb_lookup.TupleSummaryProvider -e -x -h "^tuple\$<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^\(.*\)$" --category Rust
 type summary add -F _ -e -x -h "^.*$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?str$" --category Rust
@@ -40,4 +43,5 @@ type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)N
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^core::num::([a-z_]+::)*NonZero.+$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::([a-z_]+::)+)PathBuf$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust
+type summary add -F lldb_lookup.TupleSummaryProvider -e -x -h "^tuple\$<.+>$" --category Rust
 type category enable Rust
diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index 2f32ed833af..9f2b2c85e65 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -205,6 +205,24 @@ def StdPathSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:
     return '"%s"' % data
 
 
+def sequence_formatter(output: str, valobj: SBValue, _dict: LLDBOpaque):
+    length: int = valobj.GetNumChildren()
+
+    long: bool = False
+    for i in range(0, length):
+        if len(output) > 32:
+            long = True
+            break
+        child: SBValue = valobj.GetChildAtIndex(i)
+        output += f"{child.value}, "
+    if long:
+        output = f"(len: {length}) " + output + "..."
+    else:
+        output = output[:-2]
+
+    return output
+
+
 class StructSyntheticProvider:
     """Pretty-printer for structs and struct enum variants"""
 
@@ -348,6 +366,41 @@ class TupleSyntheticProvider:
         return True
 
 
+class MSVCTupleSyntheticProvider:
+    __slots__ = ["valobj"]
+
+    def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
+        self.valobj = valobj
+
+    def num_children(self) -> int:
+        return self.valobj.GetNumChildren()
+
+    def get_child_index(self, name: str) -> int:
+        return self.valobj.GetIndexOfChildWithName(name)
+
+    def get_child_at_index(self, index: int) -> SBValue:
+        child: SBValue = self.valobj.GetChildAtIndex(index)
+        return child.CreateChildAtOffset(str(index), 0, child.GetType())
+
+    def update(self):
+        pass
+
+    def has_children(self) -> bool:
+        return self.valobj.MightHaveChildren()
+
+    def get_type_name(self) -> str:
+        name = self.valobj.GetTypeName()
+        # remove "tuple$<" and ">", str.removeprefix and str.removesuffix require python 3.9+
+        name = name[7:-1]
+        return "(" + name + ")"
+
+
+def TupleSummaryProvider(valobj: SBValue, _dict: LLDBOpaque):
+    output: str = sequence_formatter("(", valobj, dict)
+    output += ")"
+    return output
+
+
 class StdVecSyntheticProvider:
     """Pretty-printer for alloc::vec::Vec<T>
 

From 71b6d49282ee68a980aada44a65d4f6e8f1c8991 Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356@users.noreply.github.com>
Date: Fri, 10 Jan 2025 02:02:01 -0600
Subject: [PATCH 02/14] add MSVC slice providers

---
 src/etc/lldb_commands     |  2 ++
 src/etc/lldb_providers.py | 27 +++++++++++++++++++++++++--
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands
index 71968f2dbe6..23282d2d25b 100644
--- a/src/etc/lldb_commands
+++ b/src/etc/lldb_commands
@@ -44,4 +44,6 @@ type summary add -F lldb_lookup.summary_lookup  -e -x -h "^core::num::([a-z_]+::
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::([a-z_]+::)+)PathBuf$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust
 type summary add -F lldb_lookup.TupleSummaryProvider -e -x -h "^tuple\$<.+>$" --category Rust
+type summary add -F lldb_lookup.StdSliceSummaryProvider -e -x -h "^ref(_mut)?\$<slice2\$<.+> >" --category Rust
+type synthetic add -l lldb_lookup.MSVCStdSliceSyntheticProvider -x "^ref(_mut)?\$<slice2\$<.+> >" --category Rust
 type category enable Rust
diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index 9f2b2c85e65..7be40068b90 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -456,6 +456,8 @@ class StdVecSyntheticProvider:
 
 
 class StdSliceSyntheticProvider:
+    __slots__ = ["valobj", "length", "ptr", "element_type", "element_size"]
+
     def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
         self.valobj = valobj
         self.update()
@@ -472,7 +474,7 @@ class StdSliceSyntheticProvider:
 
     def get_child_at_index(self, index: int) -> SBValue:
         start = self.data_ptr.GetValueAsUnsigned()
-        address = start + index * self.element_type_size
+        address = start + index * self.element_size
         element = self.data_ptr.CreateValueFromAddress(
             "[%s]" % index, address, self.element_type
         )
@@ -483,12 +485,33 @@ class StdSliceSyntheticProvider:
         self.data_ptr = self.valobj.GetChildMemberWithName("data_ptr")
 
         self.element_type = self.data_ptr.GetType().GetPointeeType()
-        self.element_type_size = self.element_type.GetByteSize()
+        self.element_size = self.element_type.GetByteSize()
 
     def has_children(self) -> bool:
         return True
 
 
+class MSVCStdSliceSyntheticProvider(StdSliceSyntheticProvider):
+    def get_type_name(self) -> str:
+        name = self.valobj.GetTypeName()
+
+        if name.startswith("ref_mut"):
+            # remove "ref_mut$<slice2$<" and trailing "> >"
+            name = name[17:-3]
+            ref = "&mut "
+        else:
+            # remove "ref$<slice2$<" and trailing "> >"
+            name = name[13:-3]
+            ref = "&"
+
+        return "".join([ref, "[", name, "]"])
+
+def StdSliceSummaryProvider(valobj, dict):
+    output = sequence_formatter("[", valobj, dict)
+    output += "]"
+    return output
+
+
 class StdVecDequeSyntheticProvider:
     """Pretty-printer for alloc::collections::vec_deque::VecDeque<T>
 

From c425660858fb19e13dde3a28fef824b1c4dd5f48 Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356@users.noreply.github.com>
Date: Fri, 10 Jan 2025 21:13:52 -0600
Subject: [PATCH 03/14] add msvc enum providers

---
 src/etc/lldb_commands     |   6 +-
 src/etc/lldb_providers.py | 175 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 179 insertions(+), 2 deletions(-)

diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands
index 23282d2d25b..24c485b3533 100644
--- a/src/etc/lldb_commands
+++ b/src/etc/lldb_commands
@@ -18,9 +18,10 @@ type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)NonZ
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^core::num::([a-z_]+::)*NonZero.+$" --category Rust
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::([a-z_]+::)+)PathBuf$" --category Rust
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust
+type synthetic add -l lldb_lookup.MSVCEnumSyntheticProvider -x "^enum2\$<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^enum2\$<.+>::.*$" --category Rust
 type synthetic add -l lldb_lookup.MSVCStdSliceSyntheticProvider -x "^ref\$<slice2\$<.+> >" --category Rust
 type synthetic add -l lldb_lookup.MSVCTupleSyntheticProvider -x "^tuple\$<.+>$" --category Rust
-type summary add -F lldb_lookup.TupleSummaryProvider -e -x -h "^tuple\$<.+>$" --category Rust
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^\(.*\)$" --category Rust
 type summary add -F _ -e -x -h "^.*$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust
@@ -45,5 +46,6 @@ type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::([a-z_]+::)+)Pa
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust
 type summary add -F lldb_lookup.TupleSummaryProvider -e -x -h "^tuple\$<.+>$" --category Rust
 type summary add -F lldb_lookup.StdSliceSummaryProvider -e -x -h "^ref(_mut)?\$<slice2\$<.+> >" --category Rust
-type synthetic add -l lldb_lookup.MSVCStdSliceSyntheticProvider -x "^ref(_mut)?\$<slice2\$<.+> >" --category Rust
+type summary add -F lldb_lookup.MSVCEnumSummaryProvider -e -x -h "^enum2\$<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^enum2\$<.+>::.*$" --category Rust
 type category enable Rust
diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index 7be40068b90..b05dd5162f0 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -3,6 +3,8 @@ import sys
 from lldb import (
     SBData,
     SBError,
+    SBType,
+    SBTypeStaticField,
     SBValue,
     eBasicTypeLong,
     eBasicTypeUnsignedLong,
@@ -325,6 +327,179 @@ class ClangEncodedEnumProvider:
                 default_index = i
         return default_index
 
+class MSVCEnumSyntheticProvider:
+    """
+    Synthetic provider for sum-type enums on MSVC. For a detailed explanation of the internals,
+    see:
+
+    https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
+    """
+
+    __slots__ = ["valobj", "variant", "value"]
+    def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
+        self.valobj = valobj
+        self.variant: SBValue
+        self.value: SBValue
+        self.update()
+
+    def update(self):
+        tag: SBValue = self.valobj.GetChildMemberWithName("tag")
+
+        if tag.IsValid():
+            tag: int = tag.GetValueAsUnsigned()
+            for child in self.valobj.GetNonSyntheticValue().children:
+                if not child.name.startswith("variant"):
+                    continue
+
+                variant_type: SBType = child.GetType()
+                exact: SBTypeStaticField = variant_type.GetStaticFieldWithName(
+                    "DISCR_EXACT"
+                )
+
+                if exact.IsValid():
+                    discr: int = exact.GetConstantValue(
+                        self.valobj.target
+                    ).GetValueAsUnsigned()
+                    if tag == discr:
+                        self.variant = child
+                        self.value = child.GetChildMemberWithName("value").GetSyntheticValue()
+                        return
+                else:  # if invalid, DISCR must be a range
+                    begin: int = variant_type.GetStaticFieldWithName(
+                        "DISCR_BEGIN"
+                    ).GetConstantValue(self.valobj.target).GetValueAsUnsigned()
+                    end: int = variant_type.GetStaticFieldWithName(
+                        "DISCR_END"
+                    ).GetConstantValue(self.valobj.target).GetValueAsUnsigned()
+
+                    # begin isn't necessarily smaller than end, so we must test for both cases
+                    if begin < end:
+                        if begin <= tag <= end:
+                            self.variant = child
+                            self.value = child.GetChildMemberWithName("value").GetSyntheticValue()
+                            return
+                    else:
+                        if tag >= begin or tag <= end:
+                            self.variant = child
+                            self.value = child.GetChildMemberWithName("value").GetSyntheticValue()
+                            return
+        else:  # if invalid, tag is a 128 bit value
+            tag_lo: int = self.valobj.GetChildMemberWithName("tag128_lo").GetValueAsUnsigned()
+            tag_hi: int = self.valobj.GetChildMemberWithName("tag128_hi").GetValueAsUnsigned()
+
+            tag: int = (tag_hi << 64) | tag_lo
+
+            for child in self.valobj.GetNonSyntheticValue().children:
+                if not child.name.startswith("variant"):
+                    continue
+
+                variant_type: SBType = child.GetType()
+                exact_lo: SBTypeStaticField = variant_type.GetStaticFieldWithName(
+                    "DISCR128_EXACT_LO"
+                )
+
+                if exact_lo.IsValid():
+                    exact_lo: int = exact_lo.GetConstantValue(self.valobj.target).GetValueAsUnsigned()
+                    exact_hi: int = variant_type.GetStaticFieldWithName(
+                    "DISCR128_EXACT_HI"
+                    ).GetConstantValue(self.valobj.target).GetValueAsUnsigned()
+
+                    discr: int = (exact_hi << 64) | exact_lo
+                    if tag == discr:
+                        self.variant = child
+                        self.value = child.GetChildMemberWithName("value").GetSyntheticValue()
+                        return
+                else:  # if invalid, DISCR must be a range
+                    begin_lo: int = variant_type.GetStaticFieldWithName(
+                    "DISCR128_BEGIN_LO"
+                    ).GetConstantValue(self.valobj.target).GetValueAsUnsigned()
+                    begin_hi: int = variant_type.GetStaticFieldWithName(
+                    "DISCR128_BEGIN_HI"
+                    ).GetConstantValue(self.valobj.target).GetValueAsUnsigned()
+
+                    end_lo: int = variant_type.GetStaticFieldWithName(
+                    "DISCR128_END_LO"
+                    ).GetConstantValue(self.valobj.target).GetValueAsUnsigned()
+                    end_hi: int = variant_type.GetStaticFieldWithName(
+                    "DISCR128_END_HI"
+                    ).GetConstantValue(self.valobj.target).GetValueAsUnsigned()
+
+                    begin = (begin_hi << 64) | begin_lo
+                    end = (end_hi << 64) | end_lo
+
+                    # begin isn't necessarily smaller than end, so we must test for both cases
+                    if begin < end:
+                        if begin <= tag <= end:
+                            self.variant = child
+                            self.value = child.GetChildMemberWithName("value").GetSyntheticValue()
+                            return
+                    else:
+                        if tag >= begin or tag <= end:
+                            self.variant = child
+                            self.value = child.GetChildMemberWithName("value").GetSyntheticValue()
+                            return
+
+    def num_children(self) -> int:
+        return self.value.GetNumChildren()
+
+    def get_child_index(self, name: str) -> int:
+        return self.value.GetIndexOfChildWithName(name)
+
+    def get_child_at_index(self, index: int) -> SBValue:
+        return self.value.GetChildAtIndex(index)
+
+    def has_children(self) -> bool:
+        return self.value.MightHaveChildren()
+
+    def get_type_name(self) -> str:
+        name = self.valobj.GetTypeName()
+        # remove "enum2$<", str.removeprefix() is python 3.9+
+        name = name[7:]
+
+        # MSVC misinterprets ">>" as a shift operator, so spaces are inserted by rust to
+        # avoid that
+        if name.endswith(" >"):
+            name = name[:-2]
+        elif name.endswith(">"):
+            name = name[:-1]
+
+        return name
+
+
+def MSVCEnumSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:
+    enum_synth = MSVCEnumSyntheticProvider(valobj.GetNonSyntheticValue(), _dict)
+    variant_names: SBType = valobj.target.FindFirstType(
+        f"{enum_synth.valobj.GetTypeName()}::VariantNames"
+    )
+    name_idx = (
+        enum_synth.variant.GetType()
+        .GetStaticFieldWithName("NAME")
+        .GetConstantValue(valobj.target)
+        .GetValueAsUnsigned()
+    )
+
+    name: str = variant_names.enum_members[name_idx].name
+
+    if enum_synth.num_children() == 0:
+        return name
+
+    child_name: str = enum_synth.value.GetChildAtIndex(0).name
+    if child_name == "0" or child_name == "__0":
+        # enum variant is a tuple struct
+        return name + TupleSummaryProvider(enum_synth.value, _dict)
+    else:
+        # enum variant is a regular struct
+        var_list = (
+            str(enum_synth.value.GetNonSyntheticValue()).split("= ", 1)[1].splitlines()
+        )
+        vars = [x.strip() for x in var_list if x not in ("{", "}")]
+        if vars[0][0] == "(":
+            vars[0] = vars[0][1:]
+        if vars[-1][-1] == ")":
+            vars[-1] = vars[-1][:-1]
+
+        return f'{name}{{{", ".join(vars)}}}'
+
 
 class TupleSyntheticProvider:
     """Pretty-printer for tuples and tuple enum variants"""

From 009994a8499d1156b2d54429bfa2622c8140bf5b Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356@users.noreply.github.com>
Date: Fri, 10 Jan 2025 21:21:44 -0600
Subject: [PATCH 04/14] organize lldb_commands

---
 src/etc/lldb_commands | 75 ++++++++++++++++++++++++++++---------------
 1 file changed, 50 insertions(+), 25 deletions(-)

diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands
index 24c485b3533..b2ec8aa2399 100644
--- a/src/etc/lldb_commands
+++ b/src/etc/lldb_commands
@@ -1,51 +1,76 @@
+# Std String
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)String$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust
+# Std str
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?str$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?str$" --category Rust
+# Array
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?\\[.+\\]$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?\\[.+\\]$" --category Rust
+# Slice
+## MSVC
+type synthetic add -l lldb_lookup.MSVCStdSliceSyntheticProvider -x "^ref\$<slice2\$<.+> >" --category Rust
+type summary add -F lldb_lookup.StdSliceSummaryProvider -e -x -h "^ref(_mut)?\$<slice2\$<.+> >" --category Rust
+# OsString
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust
+# Vec
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust
+# VecDeque
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust
+# BTreeSet
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust
+# BTreeMap
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust
+# HashMap
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust
+# HashSet
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust
+# Rc
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust
+# Arc
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust
+# Cell
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust
+# RefCell
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust
-type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)NonZero<.+>$" --category Rust
-type synthetic add -l lldb_lookup.synthetic_lookup -x "^core::num::([a-z_]+::)*NonZero.+$" --category Rust
-type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::([a-z_]+::)+)PathBuf$" --category Rust
-type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust
-type synthetic add -l lldb_lookup.MSVCEnumSyntheticProvider -x "^enum2\$<.+>$" --category Rust
-type synthetic add -l lldb_lookup.synthetic_lookup -x "^enum2\$<.+>::.*$" --category Rust
-type synthetic add -l lldb_lookup.MSVCStdSliceSyntheticProvider -x "^ref\$<slice2\$<.+> >" --category Rust
-type synthetic add -l lldb_lookup.MSVCTupleSyntheticProvider -x "^tuple\$<.+>$" --category Rust
-type synthetic add -l lldb_lookup.synthetic_lookup -x "^\(.*\)$" --category Rust
-type summary add -F _ -e -x -h "^.*$" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?str$" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?\\[.+\\]$" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust
+# NonZero
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)NonZero<.+>$" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^core::num::([a-z_]+::)*NonZero.+$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)NonZero<.+>$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^core::num::([a-z_]+::)*NonZero.+$" --category Rust
+# PathBuf
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::([a-z_]+::)+)PathBuf$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::([a-z_]+::)+)PathBuf$" --category Rust
+# Path
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust
-type summary add -F lldb_lookup.TupleSummaryProvider -e -x -h "^tuple\$<.+>$" --category Rust
-type summary add -F lldb_lookup.StdSliceSummaryProvider -e -x -h "^ref(_mut)?\$<slice2\$<.+> >" --category Rust
+# Enum
+## MSVC
+type synthetic add -l lldb_lookup.MSVCEnumSyntheticProvider -x "^enum2\$<.+>$" --category Rust
 type summary add -F lldb_lookup.MSVCEnumSummaryProvider -e -x -h "^enum2\$<.+>$" --category Rust
+## MSVC Variants
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^enum2\$<.+>::.*$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^enum2\$<.+>::.*$" --category Rust
+# Tuple
+type synthetic add -l lldb_lookup.synthetic_lookup -x "^\(.*\)$" --category Rust
+## MSVC
+type synthetic add -l lldb_lookup.MSVCTupleSyntheticProvider -x "^tuple\$<.+>$" --category Rust
+type summary add -F lldb_lookup.TupleSummaryProvider -e -x -h "^tuple\$<.+>$" --category Rust
+# Forces test-compliant formatting to all other types
+type summary add -F _ -e -x -h "^.*$" --category Rust
 type category enable Rust

From 2b8ff7534a085271d3803cfd9401ef3ec9112563 Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356@users.noreply.github.com>
Date: Fri, 10 Jan 2025 21:47:27 -0600
Subject: [PATCH 05/14] add MSVC str providers

---
 src/etc/lldb_commands     |   9 ++-
 src/etc/lldb_providers.py | 138 +++++++++++++++++++++++++++++---------
 2 files changed, 113 insertions(+), 34 deletions(-)

diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands
index b2ec8aa2399..e2c30acfc85 100644
--- a/src/etc/lldb_commands
+++ b/src/etc/lldb_commands
@@ -1,15 +1,20 @@
+# Forces test-compliant formatting to all other types
+type summary add -F _ -e -x -h "^.*$" --category Rust
 # Std String
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)String$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust
 # Std str
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?str$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?str$" --category Rust
+## MSVC
+type synthetic add -l lldb_lookup.MSVCStrSyntheticProvider -x "^ref(_mut)?\$<str\$>$" --category Rust
+type summary add -F lldb_lookup.StdStrSummaryProvider -e -h -x "^ref(_mut)?\$<str\$>$" --category Rust
 # Array
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?\\[.+\\]$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?\\[.+\\]$" --category Rust
 # Slice
 ## MSVC
-type synthetic add -l lldb_lookup.MSVCStdSliceSyntheticProvider -x "^ref\$<slice2\$<.+> >" --category Rust
+type synthetic add -l lldb_lookup.MSVCStdSliceSyntheticProvider -x "^ref(_mut)?\$<slice2\$<.+> >" --category Rust
 type summary add -F lldb_lookup.StdSliceSummaryProvider -e -x -h "^ref(_mut)?\$<slice2\$<.+> >" --category Rust
 # OsString
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust
@@ -71,6 +76,4 @@ type synthetic add -l lldb_lookup.synthetic_lookup -x "^\(.*\)$" --category Rust
 ## MSVC
 type synthetic add -l lldb_lookup.MSVCTupleSyntheticProvider -x "^tuple\$<.+>$" --category Rust
 type summary add -F lldb_lookup.TupleSummaryProvider -e -x -h "^tuple\$<.+>$" --category Rust
-# Forces test-compliant formatting to all other types
-type summary add -F _ -e -x -h "^.*$" --category Rust
 type category enable Rust
diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index b05dd5162f0..b1bf6f9b06c 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -266,6 +266,47 @@ class StructSyntheticProvider:
         return True
 
 
+class MSVCStrSyntheticProvider:
+    __slots__ = ["valobj", "data_ptr", "length"]
+
+    def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
+        self.valobj = valobj
+        self.update()
+
+    def update(self):
+        self.data_ptr = self.valobj.GetChildMemberWithName("data_ptr")
+        self.length = self.valobj.GetChildMemberWithName("length").GetValueAsUnsigned()
+
+    def has_children(self) -> bool:
+        return True
+
+    def num_children(self) -> int:
+        return self.length
+
+    def get_child_index(self, name: str) -> int:
+        index = name.lstrip("[").rstrip("]")
+        if index.isdigit():
+            return int(index)
+
+        return -1
+
+    def get_child_at_index(self, index: int) -> SBValue:
+        if not 0 <= index < self.length:
+            return None
+        start = self.data_ptr.GetValueAsUnsigned()
+        address = start + index
+        element = self.data_ptr.CreateValueFromAddress(
+            f"[{index}]", address, self.data_ptr.GetType().GetPointeeType()
+        )
+        return element
+
+    def get_type_name(self):
+        if self.valobj.GetTypeName().startswith("ref_mut"):
+            return "&mut str"
+        else:
+            return "&str"
+
+
 class ClangEncodedEnumProvider:
     """Pretty-printer for 'clang-encoded' enums support implemented in LLDB"""
 
@@ -327,6 +368,7 @@ class ClangEncodedEnumProvider:
                 default_index = i
         return default_index
 
+
 class MSVCEnumSyntheticProvider:
     """
     Synthetic provider for sum-type enums on MSVC. For a detailed explanation of the internals,
@@ -336,6 +378,7 @@ class MSVCEnumSyntheticProvider:
     """
 
     __slots__ = ["valobj", "variant", "value"]
+
     def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
         self.valobj = valobj
         self.variant: SBValue
@@ -362,30 +405,44 @@ class MSVCEnumSyntheticProvider:
                     ).GetValueAsUnsigned()
                     if tag == discr:
                         self.variant = child
-                        self.value = child.GetChildMemberWithName("value").GetSyntheticValue()
+                        self.value = child.GetChildMemberWithName(
+                            "value"
+                        ).GetSyntheticValue()
                         return
                 else:  # if invalid, DISCR must be a range
-                    begin: int = variant_type.GetStaticFieldWithName(
-                        "DISCR_BEGIN"
-                    ).GetConstantValue(self.valobj.target).GetValueAsUnsigned()
-                    end: int = variant_type.GetStaticFieldWithName(
-                        "DISCR_END"
-                    ).GetConstantValue(self.valobj.target).GetValueAsUnsigned()
+                    begin: int = (
+                        variant_type.GetStaticFieldWithName("DISCR_BEGIN")
+                        .GetConstantValue(self.valobj.target)
+                        .GetValueAsUnsigned()
+                    )
+                    end: int = (
+                        variant_type.GetStaticFieldWithName("DISCR_END")
+                        .GetConstantValue(self.valobj.target)
+                        .GetValueAsUnsigned()
+                    )
 
                     # begin isn't necessarily smaller than end, so we must test for both cases
                     if begin < end:
                         if begin <= tag <= end:
                             self.variant = child
-                            self.value = child.GetChildMemberWithName("value").GetSyntheticValue()
+                            self.value = child.GetChildMemberWithName(
+                                "value"
+                            ).GetSyntheticValue()
                             return
                     else:
                         if tag >= begin or tag <= end:
                             self.variant = child
-                            self.value = child.GetChildMemberWithName("value").GetSyntheticValue()
+                            self.value = child.GetChildMemberWithName(
+                                "value"
+                            ).GetSyntheticValue()
                             return
         else:  # if invalid, tag is a 128 bit value
-            tag_lo: int = self.valobj.GetChildMemberWithName("tag128_lo").GetValueAsUnsigned()
-            tag_hi: int = self.valobj.GetChildMemberWithName("tag128_hi").GetValueAsUnsigned()
+            tag_lo: int = self.valobj.GetChildMemberWithName(
+                "tag128_lo"
+            ).GetValueAsUnsigned()
+            tag_hi: int = self.valobj.GetChildMemberWithName(
+                "tag128_hi"
+            ).GetValueAsUnsigned()
 
             tag: int = (tag_hi << 64) | tag_lo
 
@@ -399,30 +456,44 @@ class MSVCEnumSyntheticProvider:
                 )
 
                 if exact_lo.IsValid():
-                    exact_lo: int = exact_lo.GetConstantValue(self.valobj.target).GetValueAsUnsigned()
-                    exact_hi: int = variant_type.GetStaticFieldWithName(
-                    "DISCR128_EXACT_HI"
-                    ).GetConstantValue(self.valobj.target).GetValueAsUnsigned()
+                    exact_lo: int = exact_lo.GetConstantValue(
+                        self.valobj.target
+                    ).GetValueAsUnsigned()
+                    exact_hi: int = (
+                        variant_type.GetStaticFieldWithName("DISCR128_EXACT_HI")
+                        .GetConstantValue(self.valobj.target)
+                        .GetValueAsUnsigned()
+                    )
 
                     discr: int = (exact_hi << 64) | exact_lo
                     if tag == discr:
                         self.variant = child
-                        self.value = child.GetChildMemberWithName("value").GetSyntheticValue()
+                        self.value = child.GetChildMemberWithName(
+                            "value"
+                        ).GetSyntheticValue()
                         return
                 else:  # if invalid, DISCR must be a range
-                    begin_lo: int = variant_type.GetStaticFieldWithName(
-                    "DISCR128_BEGIN_LO"
-                    ).GetConstantValue(self.valobj.target).GetValueAsUnsigned()
-                    begin_hi: int = variant_type.GetStaticFieldWithName(
-                    "DISCR128_BEGIN_HI"
-                    ).GetConstantValue(self.valobj.target).GetValueAsUnsigned()
+                    begin_lo: int = (
+                        variant_type.GetStaticFieldWithName("DISCR128_BEGIN_LO")
+                        .GetConstantValue(self.valobj.target)
+                        .GetValueAsUnsigned()
+                    )
+                    begin_hi: int = (
+                        variant_type.GetStaticFieldWithName("DISCR128_BEGIN_HI")
+                        .GetConstantValue(self.valobj.target)
+                        .GetValueAsUnsigned()
+                    )
 
-                    end_lo: int = variant_type.GetStaticFieldWithName(
-                    "DISCR128_END_LO"
-                    ).GetConstantValue(self.valobj.target).GetValueAsUnsigned()
-                    end_hi: int = variant_type.GetStaticFieldWithName(
-                    "DISCR128_END_HI"
-                    ).GetConstantValue(self.valobj.target).GetValueAsUnsigned()
+                    end_lo: int = (
+                        variant_type.GetStaticFieldWithName("DISCR128_END_LO")
+                        .GetConstantValue(self.valobj.target)
+                        .GetValueAsUnsigned()
+                    )
+                    end_hi: int = (
+                        variant_type.GetStaticFieldWithName("DISCR128_END_HI")
+                        .GetConstantValue(self.valobj.target)
+                        .GetValueAsUnsigned()
+                    )
 
                     begin = (begin_hi << 64) | begin_lo
                     end = (end_hi << 64) | end_lo
@@ -431,12 +502,16 @@ class MSVCEnumSyntheticProvider:
                     if begin < end:
                         if begin <= tag <= end:
                             self.variant = child
-                            self.value = child.GetChildMemberWithName("value").GetSyntheticValue()
+                            self.value = child.GetChildMemberWithName(
+                                "value"
+                            ).GetSyntheticValue()
                             return
                     else:
                         if tag >= begin or tag <= end:
                             self.variant = child
-                            self.value = child.GetChildMemberWithName("value").GetSyntheticValue()
+                            self.value = child.GetChildMemberWithName(
+                                "value"
+                            ).GetSyntheticValue()
                             return
 
     def num_children(self) -> int:
@@ -498,7 +573,7 @@ def MSVCEnumSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:
         if vars[-1][-1] == ")":
             vars[-1] = vars[-1][:-1]
 
-        return f'{name}{{{", ".join(vars)}}}'
+        return f"{name}{{{', '.join(vars)}}}"
 
 
 class TupleSyntheticProvider:
@@ -681,6 +756,7 @@ class MSVCStdSliceSyntheticProvider(StdSliceSyntheticProvider):
 
         return "".join([ref, "[", name, "]"])
 
+
 def StdSliceSummaryProvider(valobj, dict):
     output = sequence_formatter("[", valobj, dict)
     output += "]"

From 4f595334f5771b28d85c46f29859d2e48af270b5 Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356@users.noreply.github.com>
Date: Fri, 10 Jan 2025 22:02:45 -0600
Subject: [PATCH 06/14] add alternate inner type lookup for vec/string for
 missing template args

---
 src/etc/lldb_commands     |  4 +-
 src/etc/lldb_providers.py | 89 ++++++++++++++++++++++++++++++++++++---
 2 files changed, 86 insertions(+), 7 deletions(-)

diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands
index e2c30acfc85..5f24d0da047 100644
--- a/src/etc/lldb_commands
+++ b/src/etc/lldb_commands
@@ -1,8 +1,8 @@
 # Forces test-compliant formatting to all other types
 type summary add -F _ -e -x -h "^.*$" --category Rust
 # Std String
-type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)String$" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust
+type synthetic add -l lldb_lookup.StdStringSyntheticProvider -x "^(alloc::([a-z_]+::)+)String$" --category Rust
+type summary add -F lldb_lookup.StdStringSummaryProvider  -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust
 # Std str
 type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?str$" --category Rust
 type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&(mut )?str$" --category Rust
diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index b1bf6f9b06c..063db7abb3c 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -9,6 +9,7 @@ from lldb import (
     eBasicTypeLong,
     eBasicTypeUnsignedLong,
     eBasicTypeUnsignedChar,
+    eFormatChar,
 )
 
 # from lldb.formatters import Logger
@@ -143,11 +144,32 @@ def vec_to_string(vec: SBValue) -> str:
     )
 
 
-def StdStringSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:
-    # logger = Logger.Logger()
-    # logger >> "[StdStringSummaryProvider] for " + str(valobj.GetName())
-    vec = valobj.GetChildAtIndex(0)
-    return '"%s"' % vec_to_string(vec)
+def StdStringSummaryProvider(valobj, dict):
+    inner_vec = (
+        valobj.GetNonSyntheticValue()
+        .GetChildMemberWithName("vec")
+        .GetNonSyntheticValue()
+    )
+
+    pointer = (
+        inner_vec.GetChildMemberWithName("buf")
+        .GetChildMemberWithName("inner")
+        .GetChildMemberWithName("ptr")
+        .GetChildMemberWithName("pointer")
+        .GetChildMemberWithName("pointer")
+    )
+
+    length = inner_vec.GetChildMemberWithName("len").GetValueAsUnsigned()
+
+    if length <= 0:
+        return ""
+    error = SBError()
+    process = pointer.GetProcess()
+    data = process.ReadMemory(pointer.GetValueAsUnsigned(), length, error)
+    if error.Success():
+        return '"' + data.decode("utf8", "replace") + '"'
+    else:
+        raise Exception("ReadMemory error: %s", error.GetCString())
 
 
 def StdOsStringSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:
@@ -266,6 +288,48 @@ class StructSyntheticProvider:
         return True
 
 
+class StdStringSyntheticProvider:
+    def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
+        self.valobj = valobj
+        self.update()
+
+    def update(self):
+        inner_vec = self.valobj.GetChildMemberWithName("vec").GetNonSyntheticValue()
+        self.data_ptr = (
+            inner_vec.GetChildMemberWithName("buf")
+            .GetChildMemberWithName("inner")
+            .GetChildMemberWithName("ptr")
+            .GetChildMemberWithName("pointer")
+            .GetChildMemberWithName("pointer")
+        )
+        self.length = inner_vec.GetChildMemberWithName("len").GetValueAsUnsigned()
+        self.element_type = self.data_ptr.GetType().GetPointeeType()
+
+    def has_children(self) -> bool:
+        return True
+
+    def num_children(self) -> int:
+        return self.length
+
+    def get_child_index(self, name: str) -> int:
+        index = name.lstrip("[").rstrip("]")
+        if index.isdigit():
+            return int(index)
+
+        return -1
+
+    def get_child_at_index(self, index: int) -> SBValue:
+        if not 0 <= index < self.length:
+            return None
+        start = self.data_ptr.GetValueAsUnsigned()
+        address = start + index
+        element = self.data_ptr.CreateValueFromAddress(
+            f"[{index}]", address, self.element_type
+        )
+        element.SetFormat(eFormatChar)
+        return element
+
+
 class MSVCStrSyntheticProvider:
     __slots__ = ["valobj", "data_ptr", "length"]
 
@@ -699,6 +763,21 @@ class StdVecSyntheticProvider:
         )
 
         self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
+
+        if not self.element_type.IsValid():
+            # annoyingly, vec's constituent type isn't guaranteed to be contained anywhere useful.
+            # Some functions have it, but those functions only exist in binary when they're used.
+            # that means it's time for string-based garbage.
+
+            # acquire the first generic parameter via its type name
+            _, _, end = self.valobj.GetTypeName().partition("<")
+            element_name, _, _ = end.partition(",")
+
+            # this works even for built-in rust types like `u32` because internally it's just a
+            # `typedef` i really REALLY wish there was a better way to do this, but at the moment
+            # LLDB flat out ignores template parameters due to piggybacking off of TypeSystemClang.
+            self.element_type = self.valobj.target.FindFirstType(element_name)
+
         self.element_type_size = self.element_type.GetByteSize()
 
     def has_children(self) -> bool:

From f725ad7f1d7485ee78feae1db03a37245682b7b0 Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356@users.noreply.github.com>
Date: Fri, 10 Jan 2025 22:21:49 -0600
Subject: [PATCH 07/14] more robust tuple summary

---
 src/etc/lldb_providers.py | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index 063db7abb3c..d928f1d0cf5 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -1,4 +1,5 @@
 import sys
+from typing import List
 
 from lldb import (
     SBData,
@@ -710,9 +711,18 @@ class MSVCTupleSyntheticProvider:
 
 
 def TupleSummaryProvider(valobj: SBValue, _dict: LLDBOpaque):
-    output: str = sequence_formatter("(", valobj, dict)
-    output += ")"
-    return output
+    output: List[str] = []
+
+    for i in range(0, valobj.GetNumChildren()):
+        child: SBValue = valobj.GetChildAtIndex(i)
+        summary = child.summary
+        if summary is None:
+            summary = child.value
+            if summary is None:
+                summary = "{...}"
+        output.append(summary)
+
+    return "(" + ", ".join(output) + ")"
 
 
 class StdVecSyntheticProvider:

From 0bf0817dd50b2784c46660ce5778325053e2237d Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356@users.noreply.github.com>
Date: Sat, 11 Jan 2025 00:38:48 -0600
Subject: [PATCH 08/14] More robust sequence formatter

---
 src/etc/lldb_providers.py | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index d928f1d0cf5..a1470c4c1a4 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -238,8 +238,15 @@ def sequence_formatter(output: str, valobj: SBValue, _dict: LLDBOpaque):
         if len(output) > 32:
             long = True
             break
+
         child: SBValue = valobj.GetChildAtIndex(i)
-        output += f"{child.value}, "
+
+        summary = child.summary
+        if summary is None:
+            summary = child.value
+            if summary is None:
+                summary = "{...}"
+        output += f"{summary}, "
     if long:
         output = f"(len: {length}) " + output + "..."
     else:

From a3adcd24db6b25b1bf85ef8c3314ee9664c7228c Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356@users.noreply.github.com>
Date: Sat, 11 Jan 2025 03:33:41 -0600
Subject: [PATCH 09/14] add alternate inner type lookup for hashmap/set when
 template args missing

---
 src/etc/lldb_providers.py | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index a1470c4c1a4..b380db81eec 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -130,6 +130,23 @@ class EmptySyntheticProvider:
     def has_children(self) -> bool:
         return False
 
+def get_template_args(type_name: str) -> List[str]:
+    params = []
+    level = 0
+    start = 0
+    for i, c in enumerate(type_name):
+        if c == "<":
+            level += 1
+            if level == 1:
+                start = i + 1
+        elif c == ">":
+            level -= 1
+            if level == 0:
+                params.append(type_name[start:i].strip())
+        elif c == "," and level == 1:
+            params.append(type_name[start:i].strip())
+            start = i + 1
+    return params
 
 def SizeSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:
     return "size=" + str(valobj.GetNumChildren())
@@ -1050,7 +1067,16 @@ class StdHashMapSyntheticProvider:
         ctrl = inner_table.GetChildMemberWithName("ctrl").GetChildAtIndex(0)
 
         self.size = inner_table.GetChildMemberWithName("items").GetValueAsUnsigned()
-        self.pair_type = table.type.template_args[0]
+
+        template_args = table.type.template_args
+
+        if template_args is None:
+            type_name = table.GetTypeName()
+            args = get_template_args(type_name)
+            self.pair_type = self.valobj.target.FindFirstType(args[0])
+        else:
+            self.pair_type = template_args[0]
+
         if self.pair_type.IsTypedefType():
             self.pair_type = self.pair_type.GetTypedefedType()
         self.pair_type_size = self.pair_type.GetByteSize()

From 2be88129f9fc67071df8542035825d74197ac879 Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356@users.noreply.github.com>
Date: Sat, 11 Jan 2025 03:40:07 -0600
Subject: [PATCH 10/14] tidy

---
 src/etc/lldb_providers.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index b380db81eec..c0371699ed7 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -130,6 +130,7 @@ class EmptySyntheticProvider:
     def has_children(self) -> bool:
         return False
 
+
 def get_template_args(type_name: str) -> List[str]:
     params = []
     level = 0
@@ -148,6 +149,7 @@ def get_template_args(type_name: str) -> List[str]:
             start = i + 1
     return params
 
+
 def SizeSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:
     return "size=" + str(valobj.GetNumChildren())
 

From e8c5e09e4f5df601943c2cfb20d3447a6caed043 Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356@users.noreply.github.com>
Date: Sat, 11 Jan 2025 19:09:08 -0600
Subject: [PATCH 11/14] doc comment for get_template_args

---
 src/etc/lldb_providers.py | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index c0371699ed7..3cfec8a6a29 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -131,7 +131,18 @@ class EmptySyntheticProvider:
         return False
 
 
-def get_template_args(type_name: str) -> List[str]:
+def get_template_args(type_name: str) -> list[str]:
+    """
+    Takes a type name `T<A, tuple$<B, C>, D>` and returns a list of its generic args
+    `["A", "tuple$<B, C>", "D"]`.
+
+    String-based replacement for LLDB's `SBType.template_args`, as LLDB is currently unable to
+    populate this field for targets with PDB debug info. Also useful for manually altering the type
+    name of generics (e.g. `Vec<ref$<str$>` -> `Vec<&str>`).
+
+    Each element of the returned list can be looked up for its `SBType` value via
+    `SBTarget.FindFirstType()`
+    """
     params = []
     level = 0
     start = 0
@@ -801,17 +812,7 @@ class StdVecSyntheticProvider:
         self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
 
         if not self.element_type.IsValid():
-            # annoyingly, vec's constituent type isn't guaranteed to be contained anywhere useful.
-            # Some functions have it, but those functions only exist in binary when they're used.
-            # that means it's time for string-based garbage.
-
-            # acquire the first generic parameter via its type name
-            _, _, end = self.valobj.GetTypeName().partition("<")
-            element_name, _, _ = end.partition(",")
-
-            # this works even for built-in rust types like `u32` because internally it's just a
-            # `typedef` i really REALLY wish there was a better way to do this, but at the moment
-            # LLDB flat out ignores template parameters due to piggybacking off of TypeSystemClang.
+            element_name = get_template_args(self.valobj.GetTypeName())[0]
             self.element_type = self.valobj.target.FindFirstType(element_name)
 
         self.element_type_size = self.element_type.GetByteSize()

From 0f12b8cf121365ba48703fda854e5b5b523e8938 Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356@users.noreply.github.com>
Date: Sat, 18 Jan 2025 21:12:23 -0600
Subject: [PATCH 12/14] slots fix

---
 src/etc/lldb_providers.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index 3cfec8a6a29..319682a1c8c 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -822,7 +822,7 @@ class StdVecSyntheticProvider:
 
 
 class StdSliceSyntheticProvider:
-    __slots__ = ["valobj", "length", "ptr", "element_type", "element_size"]
+    __slots__ = ["valobj", "length", "data_ptr", "element_type", "element_size"]
 
     def __init__(self, valobj: SBValue, _dict: LLDBOpaque):
         self.valobj = valobj

From 0819c1638c6fdb41884d7aadd1528611b2f09d7b Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356@users.noreply.github.com>
Date: Fri, 7 Feb 2025 20:41:57 -0600
Subject: [PATCH 13/14] Fix import/attribute errors related to
 `SBTypeStaticField`

---
 src/etc/lldb_providers.py | 56 ++++++++++++++++++++++++++++++---------
 1 file changed, 43 insertions(+), 13 deletions(-)

diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index 319682a1c8c..573cc50a868 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -1,18 +1,19 @@
+from __future__ import annotations
 import sys
-from typing import List
+from typing import List, TYPE_CHECKING
 
 from lldb import (
     SBData,
     SBError,
-    SBType,
-    SBTypeStaticField,
-    SBValue,
     eBasicTypeLong,
     eBasicTypeUnsignedLong,
     eBasicTypeUnsignedChar,
     eFormatChar,
 )
 
+if TYPE_CHECKING:
+    from lldb import SBValue, SBType, SBTypeStaticField
+
 # from lldb.formatters import Logger
 
 ####################################################################################################
@@ -497,9 +498,18 @@ class MSVCEnumSyntheticProvider:
                     continue
 
                 variant_type: SBType = child.GetType()
-                exact: SBTypeStaticField = variant_type.GetStaticFieldWithName(
-                    "DISCR_EXACT"
-                )
+                try:
+                    exact: SBTypeStaticField = variant_type.GetStaticFieldWithName(
+                        "DISCR_EXACT"
+                    )
+                except AttributeError:
+                    # LLDB versions prior to 19.0.0 do not have the `SBTypeGetStaticField` API.
+                    # With current DI generation there's not a great way to provide a "best effort"
+                    # evaluation either, so we just return the object itself with no further
+                    # attempts to inspect the type information
+                    self.variant = self.valobj
+                    self.value = self.valobj
+                    return
 
                 if exact.IsValid():
                     discr: int = exact.GetConstantValue(
@@ -648,12 +658,32 @@ def MSVCEnumSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str:
     variant_names: SBType = valobj.target.FindFirstType(
         f"{enum_synth.valobj.GetTypeName()}::VariantNames"
     )
-    name_idx = (
-        enum_synth.variant.GetType()
-        .GetStaticFieldWithName("NAME")
-        .GetConstantValue(valobj.target)
-        .GetValueAsUnsigned()
-    )
+    try:
+        name_idx = (
+            enum_synth.variant.GetType()
+            .GetStaticFieldWithName("NAME")
+            .GetConstantValue(valobj.target)
+            .GetValueAsUnsigned()
+        )
+    except AttributeError:
+        # LLDB versions prior to 19 do not have the `SBTypeGetStaticField` API, and have no way
+        # to determine the value based on the tag field.
+        tag: SBValue = valobj.GetChildMemberWithName("tag")
+
+        if tag.IsValid():
+            discr: int = tag.GetValueAsUnsigned()
+            return "".join(["{tag = ", str(tag.unsigned), "}"])
+        else:
+            tag_lo: int = valobj.GetChildMemberWithName(
+                "tag128_lo"
+            ).GetValueAsUnsigned()
+            tag_hi: int = valobj.GetChildMemberWithName(
+                "tag128_hi"
+            ).GetValueAsUnsigned()
+
+            discr: int = (tag_hi << 64) | tag_lo
+
+        return "".join(["{tag = ", str(discr), "}"])
 
     name: str = variant_names.enum_members[name_idx].name
 

From d6f5d34744a2e2b6823d103353b3e9e3d525c714 Mon Sep 17 00:00:00 2001
From: Walnut <39544927+Walnut356@users.noreply.github.com>
Date: Wed, 12 Feb 2025 01:30:09 -0600
Subject: [PATCH 14/14] fix string and tuple struct formatting

---
 src/etc/lldb_commands                | 1 +
 src/etc/lldb_providers.py            | 2 +-
 tests/debuginfo/empty-string.rs      | 2 +-
 tests/debuginfo/msvc-pretty-enums.rs | 2 +-
 tests/debuginfo/pretty-std.rs        | 3 ++-
 tests/debuginfo/strings-and-strs.rs  | 2 +-
 6 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands
index 5f24d0da047..508296c3a5a 100644
--- a/src/etc/lldb_commands
+++ b/src/etc/lldb_commands
@@ -1,4 +1,5 @@
 # Forces test-compliant formatting to all other types
+type synthetic add -l lldb_lookup.synthetic_lookup -x ".*" --category Rust
 type summary add -F _ -e -x -h "^.*$" --category Rust
 # Std String
 type synthetic add -l lldb_lookup.StdStringSyntheticProvider -x "^(alloc::([a-z_]+::)+)String$" --category Rust
diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index 573cc50a868..98426e42423 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -194,7 +194,7 @@ def StdStringSummaryProvider(valobj, dict):
     length = inner_vec.GetChildMemberWithName("len").GetValueAsUnsigned()
 
     if length <= 0:
-        return ""
+        return '""'
     error = SBError()
     process = pointer.GetProcess()
     data = process.ReadMemory(pointer.GetValueAsUnsigned(), length, error)
diff --git a/tests/debuginfo/empty-string.rs b/tests/debuginfo/empty-string.rs
index 014465c27ca..6cf61e17771 100644
--- a/tests/debuginfo/empty-string.rs
+++ b/tests/debuginfo/empty-string.rs
@@ -17,7 +17,7 @@
 // lldb-command:run
 
 // lldb-command:fr v empty_string
-// lldb-check:[...] empty_string = "" { vec = size=0 }
+// lldb-check:[...] empty_string = ""
 
 // lldb-command:fr v empty_str
 // lldb-check:[...] empty_str = ""
diff --git a/tests/debuginfo/msvc-pretty-enums.rs b/tests/debuginfo/msvc-pretty-enums.rs
index d60a7b81944..06bc25dc5d5 100644
--- a/tests/debuginfo/msvc-pretty-enums.rs
+++ b/tests/debuginfo/msvc-pretty-enums.rs
@@ -30,7 +30,7 @@
 // lldb-check:(msvc_pretty_enums::CStyleEnum) j = High
 
 // lldb-command:v k
-// lldb-check:(core::option::Option<alloc::string::String>) k = { value = { 0 = "IAMA optional string!" { vec = size=21 { [0] = 'I' [1] = 'A' [2] = 'M' [3] = 'A' [4] = ' ' [5] = 'o' [6] = 'p' [7] = 't' [8] = 'i' [9] = 'o' [10] = 'n' [11] = 'a' [12] = 'l' [13] = ' ' [14] = 's' [15] = 't' [16] = 'r' [17] = 'i' [18] = 'n' [19] = 'g' [20] = '!' } } } }
+// lldb-check:(core::option::Option<alloc::string::String>) k = { value = { 0 = "IAMA optional string!" { [0] = 'I' [1] = 'A' [2] = 'M' [3] = 'A' [4] = ' ' [5] = 'o' [6] = 'p' [7] = 't' [8] = 'i' [9] = 'o' [10] = 'n' [11] = 'a' [12] = 'l' [13] = ' ' [14] = 's' [15] = 't' [16] = 'r' [17] = 'i' [18] = 'n' [19] = 'g' [20] = '!' } } }
 
 // lldb-command:v l
 // lldb-check:(core::result::Result<u32, msvc_pretty_enums::Empty>) l = { value = { 0 = {} } }
diff --git a/tests/debuginfo/pretty-std.rs b/tests/debuginfo/pretty-std.rs
index d7c640a5bea..53835d41be2 100644
--- a/tests/debuginfo/pretty-std.rs
+++ b/tests/debuginfo/pretty-std.rs
@@ -51,7 +51,8 @@
 // lldb-check:[...] str_slice = "IAMA string slice!" { [0] = 'I' [1] = 'A' [2] = 'M' [3] = 'A' [4] = ' ' [5] = 's' [6] = 't' [7] = 'r' [8] = 'i' [9] = 'n' [10] = 'g' [11] = ' ' [12] = 's' [13] = 'l' [14] = 'i' [15] = 'c' [16] = 'e' [17] = '!' }
 
 // lldb-command:v string
-// lldb-check:[...] string = "IAMA string!" { vec = size=12 { [0] = 'I' [1] = 'A' [2] = 'M' [3] = 'A' [4] = ' ' [5] = 's' [6] = 't' [7] = 'r' [8] = 'i' [9] = 'n' [10] = 'g' [11] = '!' } }
+// lldb-check:[...] string = "IAMA string!" { [0] = 'I' [1] = 'A' [2] = 'M' [3] = 'A' [4] = ' ' [5] = 's' [6] = 't' [7] = 'r' [8] = 'i' [9] = 'n' [10] = 'g' [11] = '!' }
+
 
 // lldb-command:v some
 // lldb-check:[...] some = Some(8)
diff --git a/tests/debuginfo/strings-and-strs.rs b/tests/debuginfo/strings-and-strs.rs
index 3d6589db34b..ffdad303d51 100644
--- a/tests/debuginfo/strings-and-strs.rs
+++ b/tests/debuginfo/strings-and-strs.rs
@@ -24,7 +24,7 @@
 // === LLDB TESTS ==================================================================================
 // lldb-command:run
 // lldb-command:v plain_string
-// lldb-check:(alloc::string::String) plain_string = "Hello" { vec = size=5 { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } }
+// lldb-check:(alloc::string::String) plain_string = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' }
 
 // lldb-command:v plain_str
 // lldb-check:(&str) plain_str = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' }