Skip to content
7 changes: 7 additions & 0 deletions cross-project-tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,20 @@ 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})

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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "llvm/ADT/PointerIntPair.h"

int main() {
float a = 5;
llvm::PointerIntPair<float *, 1, bool> float_pair(&a, true);
llvm::PointerIntPair<void *, 1, bool> void_pair(&a, false);
llvm::PointerIntPair<llvm::PointerIntPair<void *, 1, bool>, 1, bool> nested(
void_pair, true);

struct S {
int i;
};
S s;

enum class E : unsigned {
Case1,
Case2,
Case3,
Case4,
};
llvm::PointerIntPair<S *, 2, E> enum_pair(&s, E::Case2);

S s2;

__builtin_debugtrap();

enum_pair.setPointerAndInt(&s2, E::Case3);

__builtin_debugtrap();
}
Original file line number Diff line number Diff line change
@@ -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 *, 1, bool>) float_pair = {
# CHECK-NEXT: (float *) Pointer = [[PTR_A]]
# CHECK-NEXT: (bool) Int = true
# CHECK-NEXT: }

# CHECK: (lldb) v -T nested
# CHECK-NEXT: (llvm::PointerIntPair<llvm::PointerIntPair<void *, 1, bool>, 1, bool>) nested = {
# CHECK-NEXT: (llvm::PointerIntPair<void *, 1, bool>) 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<S *, 2, E>) 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<S *, 2, E>) {
# 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
163 changes: 83 additions & 80 deletions llvm/utils/lldbDataFormatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down
Loading