diff --git a/cross-project-tests/CMakeLists.txt b/cross-project-tests/CMakeLists.txt index e83d374f025d7..14e2f65059ed4 100644 --- a/cross-project-tests/CMakeLists.txt +++ b/cross-project-tests/CMakeLists.txt @@ -18,6 +18,12 @@ add_executable(check-lldb-llvm-support-arrayref target_link_libraries(check-lldb-llvm-support-arrayref PRIVATE LLVMSupport) target_compile_options(check-lldb-llvm-support-arrayref PRIVATE -g -O0) +add_executable(check-lldb-llvm-support-pointer-int-pair + debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.cpp +) +target_link_libraries(check-lldb-llvm-support-pointer-int-pair PRIVATE LLVMSupport) +target_compile_options(check-lldb-llvm-support-pointer-int-pair PRIVATE -g -O0) + set(CROSS_PROJECT_TESTS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(CROSS_PROJECT_TESTS_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) @@ -25,6 +31,7 @@ set(CROSS_PROJECT_TEST_DEPS FileCheck check-gdb-llvm-support check-lldb-llvm-support-arrayref + check-lldb-llvm-support-pointer-int-pair count llvm-ar llvm-config diff --git a/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.cpp b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.cpp new file mode 100644 index 0000000000000..55596c6aaf866 --- /dev/null +++ b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.cpp @@ -0,0 +1,30 @@ +#include "llvm/ADT/PointerIntPair.h" + +int main() { + float a = 5; + llvm::PointerIntPair float_pair(&a, true); + llvm::PointerIntPair void_pair(&a, false); + llvm::PointerIntPair, 1, bool> nested( + void_pair, true); + + struct S { + int i; + }; + S s; + + enum class E : unsigned { + Case1, + Case2, + Case3, + Case4, + }; + llvm::PointerIntPair enum_pair(&s, E::Case2); + + S s2; + + __builtin_debugtrap(); + + enum_pair.setPointerAndInt(&s2, E::Case3); + + __builtin_debugtrap(); +} diff --git a/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.test b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.test new file mode 100644 index 0000000000000..e7b3e1c05dc74 --- /dev/null +++ b/cross-project-tests/debuginfo-tests/llvm-prettyprinters/lldb/pointer-int-pair.test @@ -0,0 +1,67 @@ +# RUN: split-file %s %t +# RUN: lldb -x \ +# RUN: -o 'command script import %llvm_src_root/utils/lldbDataFormatters.py' \ +# RUN: -s %t/commands.input %llvm_tools_dir/check-lldb-llvm-support-pointer-int-pair \ +# RUN: -o quit \ +# RUN: | FileCheck %t/checks + +#--- commands.input +run + +p &a +v -T float_pair +v -T nested +p &s +v -T enum_pair + +continue + +p &s2 +p enum_pair +p enum_pair.Pointer +p enum_pair.Int + +#--- checks +# CHECK: (lldb) p &a +# CHECK-NEXT: (float *) [[PTR_A:0x[0-9a-zA-Z]+]] + +# CHECK: (lldb) v -T float_pair +# CHECK-NEXT: (llvm::PointerIntPair) float_pair = { +# CHECK-NEXT: (float *) Pointer = [[PTR_A]] +# CHECK-NEXT: (bool) Int = true +# CHECK-NEXT: } + +# CHECK: (lldb) v -T nested +# CHECK-NEXT: (llvm::PointerIntPair, 1, bool>) nested = { +# CHECK-NEXT: (llvm::PointerIntPair) Pointer = { +# CHECK-NEXT: (void *) Pointer = [[PTR_A]] +# CHECK-NEXT: (bool) Int = false +# CHECK-NEXT: } +# CHECK-NEXT: Int = true +# CHECK-NEXT: } + +# CHECK: (lldb) p &s +# CHECK-NEXT: (S *) [[PTR_S:0x[0-9a-zA-Z]+]] + +# CHECK: (lldb) v -T enum_pair +# CHECK-NEXT: (llvm::PointerIntPair) enum_pair = { +# CHECK-NEXT: (S *) Pointer = [[PTR_S]] +# CHECK-NEXT: (E) Int = Case2 +# CHECK-NEXT: } + +# CHECK: (lldb) continue + +# CHECK: (lldb) p &s2 +# CHECK-NEXT: (S *) [[PTR_S2:0x[0-9a-zA-Z]+]] + +# CHECK: (lldb) p enum_pair +# CHECK-NEXT: (llvm::PointerIntPair) { +# CHECK-NEXT: Pointer = [[PTR_S2]] +# CHECK-NEXT: Int = Case3 +# CHECK-NEXT: } + +# CHECK: (lldb) p enum_pair.Pointer +# CHECK-NEXT: (S *) [[PTR_S2]] + +# CHECK: (lldb) p enum_pair.Int +# CHECK-NEXT: (E) Case3 diff --git a/llvm/utils/lldbDataFormatters.py b/llvm/utils/lldbDataFormatters.py index a3e4ae15930d9..36a4a63474b36 100644 --- a/llvm/utils/lldbDataFormatters.py +++ b/llvm/utils/lldbDataFormatters.py @@ -57,21 +57,11 @@ def __lldb_init_module(debugger, internal_dict): f"-F {__name__}.ConstStringSummaryProvider " "lldb_private::ConstString" ) - - # The synthetic providers for PointerIntPair and PointerUnion are disabled - # because of a few issues. One example is template arguments that are - # non-pointer types that instead specialize PointerLikeTypeTraits. - # debugger.HandleCommand( - # "type synthetic add -w llvm " - # f"-l {__name__}.PointerIntPairSynthProvider " - # '-x "^llvm::PointerIntPair<.+>$"' - # ) - # debugger.HandleCommand( - # "type synthetic add -w llvm " - # f"-l {__name__}.PointerUnionSynthProvider " - # '-x "^llvm::PointerUnion<.+>$"' - # ) - + debugger.HandleCommand( + "type synthetic add -w llvm " + f"-l {__name__}.PointerIntPairSynthProvider " + '-x "^llvm::PointerIntPair<.+>$"' + ) debugger.HandleCommand( "type summary add -w llvm " f"-e -F {__name__}.DenseMapSummary " @@ -217,13 +207,6 @@ def ConstStringSummaryProvider(valobj, internal_dict): return "" -def get_expression_path(val): - stream = lldb.SBStream() - if not val.GetExpressionPath(stream): - return None - return stream.GetData() - - class PointerIntPairSynthProvider: def __init__(self, valobj, internal_dict): self.valobj = valobj @@ -239,81 +222,101 @@ def get_child_index(self, name): return 1 return None + def _get_raw_value(self): + data: SBData = self.value.GetData() + error = lldb.SBError() + raw_bytes = data.ReadRawData(error, 0, self.ptr_size) + if error.Fail(): + return None + + return raw_bytes + + def _get_pointer(self, pointer_bit_mask: int, pointer_ty: SBType): + raw_bytes = self._get_raw_value() + if raw_bytes is None: + return + + unmasked_pointer = int.from_bytes(raw_bytes, self.byteorder) + pointer_value = unmasked_pointer & pointer_bit_mask + + data = lldb.SBData() + data.SetDataFromUInt64Array([pointer_value]) + return self.valobj.CreateValueFromData("Pointer", data, pointer_ty) + + def _get_int(self, int_shift: int, int_mask: int, int_ty: SBType): + raw_bytes = self._get_raw_value() + if raw_bytes is None: + return + + unmasked_pointer = int.from_bytes(raw_bytes, self.byteorder) + int_value = (unmasked_pointer >> int_shift) & int_mask + + data = lldb.SBData() + data.SetDataFromUInt64Array([int_value]) + return self.valobj.CreateValueFromData("Int", data, int_ty) + def get_child_at_index(self, index): - expr_path = get_expression_path(self.valobj) if index == 0: - return self.valobj.CreateValueFromExpression( - "Pointer", f"({self.pointer_ty.name}){expr_path}.getPointer()" - ) + return self.pointer_valobj if index == 1: - return self.valobj.CreateValueFromExpression( - "Int", f"({self.int_ty.name}){expr_path}.getInt()" - ) + return self.int_valobj return None def update(self): - self.pointer_ty = self.valobj.GetType().GetTemplateArgumentType(0) - self.int_ty = self.valobj.GetType().GetTemplateArgumentType(2) - - -def parse_template_parameters(typename): - """ - LLDB doesn't support template parameter packs, so let's parse them manually. - """ - result = [] - start = typename.find("<") - end = typename.rfind(">") - if start < 1 or end < 2 or end - start < 2: - return result - - nesting_level = 0 - current_parameter_start = start + 1 + self.byteorder = ( + "big" + if self.valobj.target.GetByteOrder() == lldb.eByteOrderBig + else "little" + ) + self.ptr_size = self.valobj.target.GetAddressByteSize() + self.value: SBValue = self.valobj.GetChildMemberWithName("Value") + if not self.value: + return - for i in range(start + 1, end + 1): - c = typename[i] - if c == "<": - nesting_level += 1 - elif c == ">": - nesting_level -= 1 - elif c == "," and nesting_level == 0: - result.append(typename[current_parameter_start:i].strip()) - current_parameter_start = i + 1 + valobj_type = self.valobj.GetType() - result.append(typename[current_parameter_start:i].strip()) + pointer_ty: SBType = valobj_type.GetTemplateArgumentType(0) + if not pointer_ty: + return - return result + int_ty: SBType = valobj_type.GetTemplateArgumentType(2) + if not int_ty: + return + pointer_info = valobj_type.GetTemplateArgumentType(4) + if not pointer_info: + return -class PointerUnionSynthProvider: - def __init__(self, valobj, internal_dict): - self.valobj = valobj - self.update() + mask_and_shift_constants = pointer_info.FindDirectNestedType( + "MaskAndShiftConstants" + ).GetEnumMembers() - def num_children(self): - return 1 + # FIXME: SBAPI should provide a way to retrieve an enum member + # by name. + pointer_bit_mask: SBTypeEnumMember = ( + mask_and_shift_constants.GetTypeEnumMemberAtIndex(0) + ) + if pointer_bit_mask.name != "PointerBitMask": + return - def get_child_index(self, name): - if name == "Ptr": - return 0 - return None + int_shift: SBTypeEnumMember = mask_and_shift_constants.GetTypeEnumMemberAtIndex( + 1 + ) + if int_shift.name != "IntShift": + return - def get_child_at_index(self, index): - if index != 0: - return None - ptr_type_name = self.template_args[self.active_type_tag] - return self.valobj.CreateValueFromExpression( - "Ptr", f"({ptr_type_name}){self.val_expr_path}.getPointer()" + int_mask: SBTypeEnumMember = mask_and_shift_constants.GetTypeEnumMemberAtIndex( + 2 ) + if int_mask.name != "IntMask": + return - def update(self): - self.pointer_int_pair = self.valobj.GetChildMemberWithName("Val") - self.val_expr_path = get_expression_path( - self.valobj.GetChildMemberWithName("Val") + self.pointer_valobj = self._get_pointer( + pointer_bit_mask.GetValueAsUnsigned(), pointer_ty + ) + self.int_valobj = self._get_int( + int_shift.GetValueAsUnsigned(), int_mask.GetValueAsUnsigned(), int_ty ) - self.active_type_tag = self.valobj.CreateValueFromExpression( - "", f"(int){self.val_expr_path}.getInt()" - ).GetValueAsSigned() - self.template_args = parse_template_parameters(self.valobj.GetType().name) def DenseMapSummary(valobj: lldb.SBValue, _) -> str: