Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 30 additions & 19 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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,
Expand All @@ -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.
Expand Down Expand Up @@ -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, _) => {
Expand Down
1 change: 1 addition & 0 deletions src/etc/gdb_lookup.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def __call__(self, valobj):
printer.add(RustType.STD_OS_STRING, StdOsStringProvider)
printer.add(RustType.STD_STR, StdStrProvider)
printer.add(RustType.STD_SLICE, StdSliceProvider)
printer.add(RustType.STD_BOX_STR, StdBoxStrProvider)
printer.add(RustType.STD_VEC, StdVecProvider)
printer.add(RustType.STD_VEC_DEQUE, StdVecDequeProvider)
printer.add(RustType.STD_BTREE_SET, StdBTreeSetProvider)
Expand Down
20 changes: 20 additions & 0 deletions src/etc/gdb_providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,20 @@ def display_hint():
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
Expand Down Expand Up @@ -197,6 +211,12 @@ def __init__(self, valobj, is_atomic=False):
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 = self._ptr["strong"]["v" if is_atomic else "value"]["value"]
self._weak = self._ptr["weak"]["v" if is_atomic else "value"]["value"] - 1

Expand Down
3 changes: 3 additions & 0 deletions src/etc/rust_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class RustType(object):
STD_OS_STRING = "StdOsString"
STD_STR = "StdStr"
STD_SLICE = "StdSlice"
STD_BOX_STR = "StdBoxStr"
STD_VEC = "StdVec"
STD_VEC_DEQUE = "StdVecDeque"
STD_BTREE_SET = "StdBTreeSet"
Expand All @@ -41,6 +42,7 @@ class RustType(object):
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<.+>$")
Expand Down Expand Up @@ -68,6 +70,7 @@ class RustType(object):
RustType.STD_OS_STRING: STD_OS_STRING_REGEX,
RustType.STD_STR: STD_STR_REGEX,
RustType.STD_SLICE: STD_SLICE_REGEX,
RustType.STD_BOX_STR: STD_BOX_STR_REGEX,
RustType.STD_VEC: STD_VEC_REGEX,
RustType.STD_VEC_DEQUE: STD_VEC_DEQUE_REGEX,
RustType.STD_HASH_MAP: STD_HASH_MAP_REGEX,
Expand Down
14 changes: 14 additions & 0 deletions tests/debuginfo/strings-and-strs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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> {
Expand All @@ -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
}

Expand Down
Loading