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\$ >" --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 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)?\$ >" --category Rust +type synthetic add -l lldb_lookup.MSVCStdSliceSyntheticProvider -x "^ref(_mut)?\$ >" --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$ >" + name = name[17:-3] + ref = "&mut " + else: + # remove "ref$ >" + 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 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\$ >" --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)?\$ >" --category Rust -type synthetic add -l lldb_lookup.MSVCStdSliceSyntheticProvider -x "^ref(_mut)?\$ >" --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\$ >" --category Rust +type summary add -F lldb_lookup.StdSliceSummaryProvider -e -x -h "^ref(_mut)?\$ >" --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\$ >" --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)?\$ >" --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)?\$$" --category Rust +type summary add -F lldb_lookup.StdStrSummaryProvider -e -h -x "^ref(_mut)?\$$" --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\$ >" --category Rust +type synthetic add -l lldb_lookup.MSVCStdSliceSyntheticProvider -x "^ref(_mut)?\$ >" --category Rust type summary add -F lldb_lookup.StdSliceSummaryProvider -e -x -h "^ref(_mut)?\$ >" --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, D>` and returns a list of its generic args + `["A", "tuple$", "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` -> `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) 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) 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) 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' }