diff options
| author | Walnut <39544927+Walnut356@users.noreply.github.com> | 2025-01-10 21:13:52 -0600 |
|---|---|---|
| committer | Walnut <39544927+Walnut356@users.noreply.github.com> | 2025-01-10 21:13:52 -0600 |
| commit | c425660858fb19e13dde3a28fef824b1c4dd5f48 (patch) | |
| tree | 8498cd4ba8268ee68f2c709d5e91048833358f9a | |
| parent | 71b6d49282ee68a980aada44a65d4f6e8f1c8991 (diff) | |
| download | rust-c425660858fb19e13dde3a28fef824b1c4dd5f48.tar.gz rust-c425660858fb19e13dde3a28fef824b1c4dd5f48.zip | |
add msvc enum providers
| -rw-r--r-- | src/etc/lldb_commands | 6 | ||||
| -rw-r--r-- | 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""" |
