debuginfo: slices are DW_TAG_array_type's

This commit is contained in:
shua
2026-02-26 23:39:46 +01:00
parent 740679e1f5
commit d715ef4be1
5 changed files with 68 additions and 19 deletions
@@ -152,7 +152,20 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
cx.size_and_align_of(Ty::new_mut_ptr(cx.tcx, pointee_type))
);
let pointee_type_di_node = type_di_node(cx, pointee_type);
let pointee_type_di_node = match pointee_type.kind() {
// `&[T]` will look like `{ data_ptr: *const T, length: usize }`
ty::Slice(element_type) => type_di_node(cx, *element_type),
// `&str` will look like `{ data_ptr: *const u8, length: usize }`
ty::Str => type_di_node(cx, cx.tcx.types.u8),
// `&dyn K` will look like `{ pointer: _, vtable: _}`
// any Adt `Foo` containing an unsized type (eg `&[_]` or `&dyn _`)
// will look like `{ data_ptr: *const Foo, length: usize }`
// and thin pointers `&Foo` will just look like `*const Foo`.
//
// in all those cases, we just use the pointee_type
_ => type_di_node(cx, pointee_type),
};
return_if_di_node_created_in_meantime!(cx, unique_type_id);
@@ -389,26 +402,11 @@ fn build_dyn_type_di_node<'ll, 'tcx>(
}
/// Create debuginfo for `[T]` and `str`. These are unsized.
///
/// NOTE: We currently emit just emit the debuginfo for the element type here
/// (i.e. `T` for slices and `u8` for `str`), so that we end up with
/// `*const T` for the `data_ptr` field of the corresponding wide-pointer
/// debuginfo of `&[T]`.
///
/// It would be preferable and more accurate if we emitted a DIArray of T
/// without an upper bound instead. That is, LLVM already supports emitting
/// debuginfo of arrays of unknown size. But GDB currently seems to end up
/// in an infinite loop when confronted with such a type.
///
/// As a side effect of the current encoding every instance of a type like
/// `struct Foo { unsized_field: [u8] }` will look like
/// `struct Foo { unsized_field: u8 }` in debuginfo. If the length of the
/// slice is zero, then accessing `unsized_field` in the debugger would
/// result in an out-of-bounds access.
fn build_slice_type_di_node<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
slice_type: Ty<'tcx>,
unique_type_id: UniqueTypeId<'tcx>,
span: Span,
) -> DINodeCreationResult<'ll> {
let element_type = match slice_type.kind() {
ty::Slice(element_type) => *element_type,
@@ -423,7 +421,20 @@ fn build_slice_type_di_node<'ll, 'tcx>(
let element_type_di_node = type_di_node(cx, element_type);
return_if_di_node_created_in_meantime!(cx, unique_type_id);
DINodeCreationResult { di_node: element_type_di_node, already_stored_in_typemap: false }
let (size, align) = cx.spanned_size_and_align_of(slice_type, span);
let subrange = unsafe { llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, -1) };
let subscripts = &[subrange];
let di_node = unsafe {
llvm::LLVMDIBuilderCreateArrayType(
DIB(cx),
size.bits(),
align.bits() as u32,
element_type_di_node,
subscripts.as_ptr(),
subscripts.len() as c_uint,
)
};
DINodeCreationResult { di_node, already_stored_in_typemap: false }
}
/// Get the debuginfo node for the given type.
@@ -454,7 +465,7 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>(
}
ty::Tuple(elements) if elements.is_empty() => build_basic_type_di_node(cx, t),
ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t, span),
ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id),
ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id, span),
ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id),
ty::Foreign(..) => build_foreign_type_di_node(cx, t, unique_type_id),
ty::RawPtr(pointee_type, _) | ty::Ref(_, pointee_type, _) => {
+1
View File
@@ -103,6 +103,7 @@ if gdb_version[0] < 7 or (gdb_version[0] == 7 and gdb_version[1] < 12):
printer.add(RustType.StdString, StdStringProvider)
printer.add(RustType.StdOsString, StdOsStringProvider)
printer.add(RustType.StdStr, StdStrProvider)
printer.add(RustType.StdBoxStr, StdBoxStrProvider)
printer.add(RustType.StdSlice, StdSliceProvider)
printer.add(RustType.StdVec, StdVecProvider)
printer.add(RustType.StdVecDeque, StdVecDequeProvider)
+20
View File
@@ -142,6 +142,20 @@ class StdSliceProvider(printer_base):
return "array"
class StdBoxStrProvider(printer_base):
def __init__(self, valobj):
self._valobj = valobj
self._length = int(valobj["length"])
self._data_ptr = valobj["data_ptr"]
def to_string(self):
return self._data_ptr.lazy_string(encoding="utf-8", length=self._length)
@staticmethod
def display_hint():
return "string"
class StdVecProvider(printer_base):
def __init__(self, valobj):
self._valobj = valobj
@@ -203,6 +217,12 @@ class StdRcProvider(printer_base):
self._is_atomic = is_atomic
self._ptr = unwrap_unique_or_non_null(valobj["ptr"])
self._value = self._ptr["data" if is_atomic else "value"]
# FIXME(shua): the debuginfo template type should be 'str' not 'u8'
if self._ptr.type.target().name == "alloc::rc::RcInner<str>":
length = self._valobj["ptr"]["pointer"]["length"]
u8_ptr_ty = gdb.Type.pointer(gdb.lookup_type("u8"))
ptr = self._value.address.reinterpret_cast(u8_ptr_ty)
self._value = ptr.lazy_string(encoding="utf-8", length=length)
self._strong = unwrap_scalar_wrappers(self._ptr["strong"])
self._weak = unwrap_scalar_wrappers(self._ptr["weak"]) - 1
+3
View File
@@ -37,12 +37,14 @@ class RustType(Enum):
StdNonZeroNumber = 29
StdPath = 30
StdPathBuf = 31
StdBoxStr = 32
STD_STRING_REGEX = re.compile(r"^(alloc::([a-z_]+::)+)String$")
STD_STR_REGEX = re.compile(r"^&(mut )?str$")
STD_SLICE_REGEX = re.compile(r"^&(mut )?\[.+\]$")
STD_OS_STRING_REGEX = re.compile(r"^(std::ffi::([a-z_]+::)+)OsString$")
STD_BOX_STR_REGEX = re.compile(r"^(alloc::([a-z_]+::)+)Box<str,.+>$")
STD_VEC_REGEX = re.compile(r"^(alloc::([a-z_]+::)+)Vec<.+>$")
STD_VEC_DEQUE_REGEX = re.compile(r"^(alloc::([a-z_]+::)+)VecDeque<.+>$")
STD_BTREE_SET_REGEX = re.compile(r"^(alloc::([a-z_]+::)+)BTreeSet<.+>$")
@@ -67,6 +69,7 @@ STD_TYPE_TO_REGEX = {
RustType.StdString: STD_STRING_REGEX,
RustType.StdOsString: STD_OS_STRING_REGEX,
RustType.StdStr: STD_STR_REGEX,
RustType.StdBoxStr: STD_BOX_STR_REGEX,
RustType.StdSlice: STD_SLICE_REGEX,
RustType.StdVec: STD_VEC_REGEX,
RustType.StdVecDeque: STD_VEC_DEQUE_REGEX,
+14
View File
@@ -23,6 +23,12 @@
//@ gdb-command:print str_in_rc
//@ gdb-check:$5 = alloc::rc::Rc<&str, alloc::alloc::Global> {ptr: core::ptr::non_null::NonNull<alloc::rc::RcInner<&str>> {pointer: 0x[...]}, phantom: core::marker::PhantomData<alloc::rc::RcInner<&str>>, alloc: alloc::alloc::Global}
//@ gdb-command:print box_str
//@ gdb-check:$6 = alloc::boxed::Box<str, alloc::alloc::Global> [87, 111, 114, 108, 100]
//@ gdb-command:print rc_str
//@ gdb-check:$7 = alloc::rc::Rc<str, alloc::alloc::Global> {ptr: core::ptr::non_null::NonNull<alloc::rc::RcInner<str>> {pointer: alloc::rc::RcInner<str> {strong: core::cell::Cell<usize> {value: core::cell::UnsafeCell<usize> {value: 1}}, weak: core::cell::Cell<usize> {value: core::cell::UnsafeCell<usize> {value: 1}}, value: 0x[...]}}, phantom: core::marker::PhantomData<alloc::rc::RcInner<str>>, alloc: alloc::alloc::Global}
// === LLDB TESTS ==================================================================================
//@ lldb-command:run
//@ lldb-command:v plain_string
@@ -40,6 +46,12 @@
//@ lldb-command:v str_in_rc
//@ lldb-check:(alloc::rc::Rc<&str, alloc::alloc::Global>) str_in_rc = strong=1, weak=0 { value = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } }
//@ lldb-command:v box_str
//@ lldb-check:(alloc::boxed::Box<unsigned char[], alloc::alloc::Global>) box_str = { __0 = { pointer = { pointer = { data_ptr = 0x[...] "World" length = 5 } } _marker = } __1 = }
//@ lldb-command:v rc_str
//@ lldb-check:(alloc::rc::Rc<unsigned char[], alloc::alloc::Global>) rc_str = strong=1, weak=0 { value = "World" }
#![allow(unused_variables)]
pub struct Foo<'a> {
@@ -53,6 +65,8 @@ fn main() {
let str_in_tuple = ("Hello", "World");
let str_in_rc = std::rc::Rc::new("Hello");
let box_str: Box<str> = "World".into();
let rc_str: std::rc::Rc<str> = "World".into();
zzz(); // #break
}