diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands index ef0c3740f0326..508296c3a5aec 100644 --- a/src/etc/lldb_commands +++ b/src/etc/lldb_commands @@ -1,43 +1,80 @@ -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)String$" --category Rust +# 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 +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 +## 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(_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 +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.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 +# 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 type category enable Rust diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 2f32ed833af1e..98426e4242398 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -1,14 +1,19 @@ +from __future__ import annotations import sys +from typing import List, TYPE_CHECKING from lldb import ( SBData, SBError, - SBValue, eBasicTypeLong, eBasicTypeUnsignedLong, eBasicTypeUnsignedChar, + eFormatChar, ) +if TYPE_CHECKING: + from lldb import SBValue, SBType, SBTypeStaticField + # from lldb.formatters import Logger #################################################################################################### @@ -127,6 +132,36 @@ def has_children(self) -> bool: return False +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 + 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()) @@ -141,11 +176,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: @@ -205,6 +261,31 @@ 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) + + 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: + output = output[:-2] + + return output + + class StructSyntheticProvider: """Pretty-printer for structs and struct enum variants""" @@ -246,6 +327,89 @@ def has_children(self) -> bool: 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"] + + 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""" @@ -308,6 +472,242 @@ def _getCurrentVariantIndex(self, all_variants: SBValue) -> int: 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() + 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( + 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" + ) + 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 + + 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""" @@ -348,6 +748,50 @@ def has_children(self) -> bool: 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: 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: """Pretty-printer for alloc::vec::Vec @@ -396,6 +840,11 @@ def update(self): ) self.element_type = self.valobj.GetType().GetTemplateArgumentType(0) + + if not self.element_type.IsValid(): + 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() def has_children(self) -> bool: @@ -403,6 +852,8 @@ def has_children(self) -> bool: class StdSliceSyntheticProvider: + __slots__ = ["valobj", "length", "data_ptr", "element_type", "element_size"] + def __init__(self, valobj: SBValue, _dict: LLDBOpaque): self.valobj = valobj self.update() @@ -419,7 +870,7 @@ def get_child_index(self, name: str) -> int: 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 ) @@ -430,12 +881,34 @@ def update(self): 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 @@ -627,7 +1100,16 @@ def update(self): 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() diff --git a/tests/debuginfo/empty-string.rs b/tests/debuginfo/empty-string.rs index 014465c27cabd..6cf61e177714d 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 d60a7b81944e7..06bc25dc5d59c 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 d7c640a5bea3e..53835d41be24e 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 3d6589db34b88..ffdad303d5150 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' }