2022-03-03 10:15:25 +00:00
|
|
|
use self::type_map::DINodeCreationResult;
|
|
|
|
use self::type_map::Stub;
|
|
|
|
use self::type_map::UniqueTypeId;
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2018-02-19 11:41:10 +00:00
|
|
|
use super::namespace::mangled_name_of_instance;
|
2021-10-06 12:26:50 +00:00
|
|
|
use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_name};
|
2019-12-24 22:38:22 +00:00
|
|
|
use super::utils::{
|
2020-02-25 00:00:00 +00:00
|
|
|
create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, DIB,
|
2019-12-24 22:38:22 +00:00
|
|
|
};
|
2022-03-03 10:15:25 +00:00
|
|
|
use super::CodegenUnitDebugContext;
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2019-05-17 01:20:14 +00:00
|
|
|
use crate::abi;
|
|
|
|
use crate::common::CodegenCx;
|
2022-03-03 10:15:25 +00:00
|
|
|
use crate::debuginfo::metadata::type_map::build_type_with_children;
|
2022-01-13 17:13:54 +00:00
|
|
|
use crate::debuginfo::utils::fat_pointer_kind;
|
|
|
|
use crate::debuginfo::utils::FatPtrKind;
|
2019-02-17 18:58:58 +00:00
|
|
|
use crate::llvm;
|
2019-12-24 22:38:22 +00:00
|
|
|
use crate::llvm::debuginfo::{
|
2022-03-03 10:15:25 +00:00
|
|
|
DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind,
|
2019-12-24 22:38:22 +00:00
|
|
|
};
|
2019-05-17 01:20:14 +00:00
|
|
|
use crate::value::Value;
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2021-02-13 11:17:15 +00:00
|
|
|
use cstr::cstr;
|
2021-12-28 21:57:18 +00:00
|
|
|
use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo;
|
2022-01-25 13:34:34 +00:00
|
|
|
use rustc_codegen_ssa::debuginfo::type_names::VTableNameKind;
|
2019-12-24 22:38:22 +00:00
|
|
|
use rustc_codegen_ssa::traits::*;
|
|
|
|
use rustc_fs_util::path_to_c_string;
|
2020-01-05 01:37:57 +00:00
|
|
|
use rustc_hir::def::CtorKind;
|
2020-02-10 01:03:24 +00:00
|
|
|
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
2019-12-24 22:38:22 +00:00
|
|
|
use rustc_index::vec::{Idx, IndexVec};
|
2022-01-10 14:59:52 +00:00
|
|
|
use rustc_middle::bug;
|
2021-06-24 20:37:03 +00:00
|
|
|
use rustc_middle::mir::{self, GeneratorLayout};
|
2022-03-03 10:15:25 +00:00
|
|
|
use rustc_middle::ty::layout::LayoutOf;
|
|
|
|
use rustc_middle::ty::layout::TyAndLayout;
|
2020-06-20 01:37:52 +00:00
|
|
|
use rustc_middle::ty::subst::GenericArgKind;
|
2022-03-03 10:15:25 +00:00
|
|
|
use rustc_middle::ty::{self, AdtKind, Instance, ParamEnv, Ty, TyCtxt, COMMON_VTABLE_ENTRIES};
|
2020-03-11 11:49:08 +00:00
|
|
|
use rustc_session::config::{self, DebugInfo};
|
2021-08-08 15:24:30 +00:00
|
|
|
use rustc_span::symbol::Symbol;
|
2021-08-26 10:46:01 +00:00
|
|
|
use rustc_span::FileNameDisplayPreference;
|
2022-01-10 14:59:52 +00:00
|
|
|
use rustc_span::{self, SourceFile, SourceFileHash};
|
2022-03-03 10:15:25 +00:00
|
|
|
use rustc_target::abi::{Align, Size};
|
|
|
|
use smallvec::smallvec;
|
2020-08-05 11:35:53 +00:00
|
|
|
use tracing::debug;
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2019-12-24 22:38:22 +00:00
|
|
|
use libc::{c_longlong, c_uint};
|
2022-03-03 10:15:25 +00:00
|
|
|
use std::borrow::Cow;
|
2019-05-06 01:47:03 +00:00
|
|
|
use std::collections::hash_map::Entry;
|
2018-07-04 13:36:49 +00:00
|
|
|
use std::fmt::{self, Write};
|
|
|
|
use std::hash::{Hash, Hasher};
|
2018-07-26 15:11:10 +00:00
|
|
|
use std::iter;
|
2017-12-14 07:09:19 +00:00
|
|
|
use std::path::{Path, PathBuf};
|
2019-12-24 22:38:22 +00:00
|
|
|
use std::ptr;
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2018-07-04 13:36:49 +00:00
|
|
|
impl PartialEq for llvm::Metadata {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
2019-01-12 15:13:33 +00:00
|
|
|
ptr::eq(self, other)
|
2018-07-04 13:36:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Eq for llvm::Metadata {}
|
|
|
|
|
|
|
|
impl Hash for llvm::Metadata {
|
|
|
|
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
|
|
|
(self as *const Self).hash(hasher);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for llvm::Metadata {
|
2019-02-25 07:40:18 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2018-07-04 13:36:49 +00:00
|
|
|
(self as *const Self).fmt(f)
|
|
|
|
}
|
|
|
|
}
|
2016-10-21 21:56:36 +00:00
|
|
|
|
2016-03-18 21:30:15 +00:00
|
|
|
// From DWARF 5.
|
2019-05-17 01:20:14 +00:00
|
|
|
// See http://www.dwarfstd.org/ShowIssue.php?issue=140129.1.
|
2016-03-18 21:30:15 +00:00
|
|
|
const DW_LANG_RUST: c_uint = 0x1c;
|
2015-04-24 04:48:10 +00:00
|
|
|
#[allow(non_upper_case_globals)]
|
|
|
|
const DW_ATE_boolean: c_uint = 0x02;
|
|
|
|
#[allow(non_upper_case_globals)]
|
|
|
|
const DW_ATE_float: c_uint = 0x04;
|
|
|
|
#[allow(non_upper_case_globals)]
|
|
|
|
const DW_ATE_signed: c_uint = 0x05;
|
|
|
|
#[allow(non_upper_case_globals)]
|
|
|
|
const DW_ATE_unsigned: c_uint = 0x07;
|
|
|
|
#[allow(non_upper_case_globals)]
|
2021-10-14 17:26:42 +00:00
|
|
|
const DW_ATE_UTF: c_uint = 0x10;
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
pub(super) const UNKNOWN_LINE_NUMBER: c_uint = 0;
|
|
|
|
pub(super) const UNKNOWN_COLUMN_NUMBER: c_uint = 0;
|
2022-02-04 12:19:55 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
const NO_SCOPE_METADATA: Option<&DIScope> = None;
|
|
|
|
/// A function that returns an empty list of generic parameter debuginfo nodes.
|
|
|
|
const NO_GENERICS: for<'ll> fn(&CodegenCx<'ll, '_>) -> SmallVec<&'ll DIType> = |_| SmallVec::new();
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
// SmallVec is used quite a bit in this module, so create a shorthand.
|
|
|
|
// The actual number of elements is not so important.
|
|
|
|
pub type SmallVec<T> = smallvec::SmallVec<[T; 16]>;
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
mod enums;
|
|
|
|
mod type_map;
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
pub(crate) use type_map::TypeMap;
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Returns from the enclosing function if the type debuginfo node with the given
|
2019-05-17 01:20:14 +00:00
|
|
|
/// unique ID can be found in the type map.
|
2022-03-03 10:15:25 +00:00
|
|
|
macro_rules! return_if_di_node_created_in_meantime {
|
2019-12-24 22:38:22 +00:00
|
|
|
($cx: expr, $unique_type_id: expr) => {
|
2022-03-03 10:15:25 +00:00
|
|
|
if let Some(di_node) = debug_context($cx).type_map.di_node_for_unique_id($unique_type_id) {
|
|
|
|
return DINodeCreationResult::new(di_node, true);
|
2015-10-21 16:20:46 +00:00
|
|
|
}
|
2019-12-24 22:38:22 +00:00
|
|
|
};
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Extract size and alignment from a TyAndLayout.
|
|
|
|
fn size_and_align_of<'tcx>(ty_and_layout: TyAndLayout<'tcx>) -> (Size, Align) {
|
|
|
|
(ty_and_layout.size, ty_and_layout.align.abi)
|
|
|
|
}
|
|
|
|
|
2022-01-13 17:13:54 +00:00
|
|
|
/// Creates debuginfo for a fixed size array (e.g. `[u64; 123]`).
|
2022-03-03 10:15:25 +00:00
|
|
|
/// For slices (that is, "arrays" of unknown size) use [build_slice_type_di_node].
|
|
|
|
fn build_fixed_size_array_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-01-13 17:13:54 +00:00
|
|
|
array_type: Ty<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
2022-01-13 17:13:54 +00:00
|
|
|
let ty::Array(element_type, len) = array_type.kind() else {
|
2022-03-03 10:15:25 +00:00
|
|
|
bug!("build_fixed_size_array_di_node() called with non-ty::Array type `{:?}`", array_type)
|
2022-01-13 17:13:54 +00:00
|
|
|
};
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let element_type_di_node = type_di_node(cx, *element_type);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
return_if_di_node_created_in_meantime!(cx, unique_type_id);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-01-13 17:13:54 +00:00
|
|
|
let (size, align) = cx.size_and_align_of(array_type);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-01-13 17:13:54 +00:00
|
|
|
let upper_bound = len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong;
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2019-12-24 22:38:22 +00:00
|
|
|
let subrange =
|
|
|
|
unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) };
|
2015-04-24 04:48:10 +00:00
|
|
|
|
|
|
|
let subscripts = create_DIArray(DIB(cx), &[subrange]);
|
2022-03-03 10:15:25 +00:00
|
|
|
let di_node = unsafe {
|
2016-08-01 23:35:09 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreateArrayType(
|
2015-04-24 04:48:10 +00:00
|
|
|
DIB(cx),
|
2017-06-01 18:50:53 +00:00
|
|
|
size.bits(),
|
2018-09-08 22:16:45 +00:00
|
|
|
align.bits() as u32,
|
2022-03-03 10:15:25 +00:00
|
|
|
element_type_di_node,
|
2019-12-24 22:38:22 +00:00
|
|
|
subscripts,
|
|
|
|
)
|
2015-04-24 04:48:10 +00:00
|
|
|
};
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
DINodeCreationResult::new(di_node, false)
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-01-13 17:13:54 +00:00
|
|
|
/// Creates debuginfo for built-in pointer-like things:
|
|
|
|
///
|
|
|
|
/// - ty::Ref
|
|
|
|
/// - ty::RawPtr
|
|
|
|
/// - ty::Adt in the case it's Box
|
|
|
|
///
|
|
|
|
/// At some point we might want to remove the special handling of Box
|
|
|
|
/// and treat it the same as other smart pointers (like Rc, Arc, ...).
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_pointer_or_reference_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
2022-01-13 17:13:54 +00:00
|
|
|
ptr_type: Ty<'tcx>,
|
|
|
|
pointee_type: Ty<'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
|
|
|
let pointee_type_di_node = type_di_node(cx, pointee_type);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
return_if_di_node_created_in_meantime!(cx, unique_type_id);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-01-13 17:13:54 +00:00
|
|
|
let (thin_pointer_size, thin_pointer_align) =
|
|
|
|
cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.types.unit));
|
|
|
|
let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
match fat_pointer_kind(cx, pointee_type) {
|
2022-01-13 17:13:54 +00:00
|
|
|
None => {
|
|
|
|
// This is a thin pointer. Create a regular pointer type and give it the correct name.
|
|
|
|
debug_assert_eq!(
|
|
|
|
(thin_pointer_size, thin_pointer_align),
|
2022-02-23 16:11:50 +00:00
|
|
|
cx.size_and_align_of(ptr_type),
|
|
|
|
"ptr_type={}, pointee_type={}",
|
|
|
|
ptr_type,
|
|
|
|
pointee_type,
|
2022-01-13 17:13:54 +00:00
|
|
|
);
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let di_node = unsafe {
|
2022-01-13 17:13:54 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreatePointerType(
|
|
|
|
DIB(cx),
|
2022-03-03 10:15:25 +00:00
|
|
|
pointee_type_di_node,
|
2022-01-13 17:13:54 +00:00
|
|
|
thin_pointer_size.bits(),
|
|
|
|
thin_pointer_align.bits() as u32,
|
|
|
|
0, // Ignore DWARF address space.
|
|
|
|
ptr_type_debuginfo_name.as_ptr().cast(),
|
|
|
|
ptr_type_debuginfo_name.len(),
|
|
|
|
)
|
2022-03-03 10:15:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
DINodeCreationResult { di_node, already_stored_in_typemap: false }
|
2022-01-13 17:13:54 +00:00
|
|
|
}
|
|
|
|
Some(fat_pointer_kind) => {
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::build_type_with_children(
|
|
|
|
cx,
|
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::Struct,
|
|
|
|
unique_type_id,
|
|
|
|
&ptr_type_debuginfo_name,
|
|
|
|
cx.size_and_align_of(ptr_type),
|
|
|
|
NO_SCOPE_METADATA,
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
),
|
|
|
|
|cx, owner| {
|
|
|
|
let layout = cx.layout_of(ptr_type);
|
|
|
|
let addr_field = layout.field(cx, abi::FAT_PTR_ADDR);
|
|
|
|
let extra_field = layout.field(cx, abi::FAT_PTR_EXTRA);
|
|
|
|
|
|
|
|
let (addr_field_name, extra_field_name) = match fat_pointer_kind {
|
|
|
|
FatPtrKind::Dyn => ("pointer", "vtable"),
|
|
|
|
FatPtrKind::Slice => ("data_ptr", "length"),
|
|
|
|
};
|
2022-01-13 17:13:54 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
debug_assert_eq!(abi::FAT_PTR_ADDR, 0);
|
|
|
|
debug_assert_eq!(abi::FAT_PTR_EXTRA, 1);
|
2022-01-13 17:13:54 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
// The data pointer type is a regular, thin pointer, regardless of whether this
|
|
|
|
// is a slice or a trait object.
|
|
|
|
let data_ptr_type_di_node = unsafe {
|
|
|
|
llvm::LLVMRustDIBuilderCreatePointerType(
|
|
|
|
DIB(cx),
|
|
|
|
pointee_type_di_node,
|
|
|
|
addr_field.size.bits(),
|
|
|
|
addr_field.align.abi.bits() as u32,
|
|
|
|
0, // Ignore DWARF address space.
|
|
|
|
std::ptr::null(),
|
|
|
|
0,
|
|
|
|
)
|
|
|
|
};
|
2022-01-13 17:13:54 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
smallvec![
|
|
|
|
build_field_di_node(
|
|
|
|
cx,
|
|
|
|
owner,
|
|
|
|
addr_field_name,
|
|
|
|
(addr_field.size, addr_field.align.abi),
|
|
|
|
layout.fields.offset(abi::FAT_PTR_ADDR),
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
data_ptr_type_di_node,
|
|
|
|
),
|
|
|
|
build_field_di_node(
|
|
|
|
cx,
|
|
|
|
owner,
|
|
|
|
extra_field_name,
|
|
|
|
(extra_field.size, extra_field.align.abi),
|
|
|
|
layout.fields.offset(abi::FAT_PTR_EXTRA),
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
type_di_node(cx, extra_field.ty),
|
|
|
|
),
|
|
|
|
]
|
2022-01-13 17:13:54 +00:00
|
|
|
},
|
2022-03-03 10:15:25 +00:00
|
|
|
NO_GENERICS,
|
2022-01-13 17:13:54 +00:00
|
|
|
)
|
|
|
|
}
|
2022-03-03 10:15:25 +00:00
|
|
|
}
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_subroutine_type_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
2022-02-04 12:19:55 +00:00
|
|
|
// It's possible to create a self-referential
|
|
|
|
// type in Rust by using 'impl trait':
|
|
|
|
//
|
|
|
|
// fn foo() -> impl Copy { foo }
|
|
|
|
//
|
|
|
|
// Unfortunately LLVM's API does not allow us to create recursive subroutine types.
|
|
|
|
// In order to work around that restriction we place a marker type in the type map,
|
|
|
|
// before creating the actual type. If the actual type is recursive, it will hit the
|
|
|
|
// marker type. So we end up with a type that looks like
|
|
|
|
//
|
|
|
|
// fn foo() -> <recursive_type>
|
|
|
|
//
|
|
|
|
// Once that is created, we replace the marker in the typemap with the actual type.
|
|
|
|
debug_context(cx)
|
|
|
|
.type_map
|
2022-03-03 10:15:25 +00:00
|
|
|
.unique_id_to_di_node
|
2022-02-04 12:19:55 +00:00
|
|
|
.borrow_mut()
|
2022-03-03 10:15:25 +00:00
|
|
|
.insert(unique_type_id, recursion_marker_type_di_node(cx));
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let fn_ty = unique_type_id.expect_ty();
|
2022-02-04 12:19:55 +00:00
|
|
|
let signature = cx
|
|
|
|
.tcx
|
|
|
|
.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), fn_ty.fn_sig(cx.tcx));
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let signature_di_nodes: SmallVec<_> = iter::once(
|
2018-07-26 15:11:10 +00:00
|
|
|
// return type
|
2020-08-02 22:49:11 +00:00
|
|
|
match signature.output().kind() {
|
2022-02-04 12:19:55 +00:00
|
|
|
ty::Tuple(tys) if tys.is_empty() => {
|
|
|
|
// this is a "void" function
|
|
|
|
None
|
|
|
|
}
|
2022-03-03 10:15:25 +00:00
|
|
|
_ => Some(type_di_node(cx, signature.output())),
|
2019-12-24 22:38:22 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
.chain(
|
2018-07-26 15:11:10 +00:00
|
|
|
// regular arguments
|
2022-03-03 10:15:25 +00:00
|
|
|
signature.inputs().iter().map(|&argument_type| Some(type_di_node(cx, argument_type))),
|
2019-12-24 22:38:22 +00:00
|
|
|
)
|
|
|
|
.collect();
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
debug_context(cx).type_map.unique_id_to_di_node.borrow_mut().remove(&unique_type_id);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let fn_di_node = unsafe {
|
2022-02-04 12:19:55 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreateSubroutineType(
|
|
|
|
DIB(cx),
|
2022-03-03 10:15:25 +00:00
|
|
|
create_DIArray(DIB(cx), &signature_di_nodes[..]),
|
2022-02-04 12:19:55 +00:00
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
// This is actually a function pointer, so wrap it in pointer DI.
|
|
|
|
let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false);
|
2022-03-03 10:15:25 +00:00
|
|
|
let di_node = unsafe {
|
2022-02-04 12:19:55 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreatePointerType(
|
|
|
|
DIB(cx),
|
2022-03-03 10:15:25 +00:00
|
|
|
fn_di_node,
|
2022-02-04 12:19:55 +00:00
|
|
|
cx.tcx.data_layout.pointer_size.bits(),
|
|
|
|
cx.tcx.data_layout.pointer_align.abi.bits() as u32,
|
|
|
|
0, // Ignore DWARF address space.
|
|
|
|
name.as_ptr().cast(),
|
|
|
|
name.len(),
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
DINodeCreationResult::new(di_node, false)
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-01-21 09:35:18 +00:00
|
|
|
/// Create debuginfo for `dyn SomeTrait` types. Currently these are empty structs
|
|
|
|
/// we with the correct type name (e.g. "dyn SomeTrait<Foo, Item=u32> + Sync").
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_dyn_type_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
2022-01-13 17:13:54 +00:00
|
|
|
dyn_type: Ty<'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
2022-01-13 17:13:54 +00:00
|
|
|
if let ty::Dynamic(..) = dyn_type.kind() {
|
|
|
|
let type_name = compute_debuginfo_type_name(cx.tcx, dyn_type, true);
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::build_type_with_children(
|
|
|
|
cx,
|
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::Struct,
|
|
|
|
unique_type_id,
|
|
|
|
&type_name,
|
|
|
|
cx.size_and_align_of(dyn_type),
|
|
|
|
NO_SCOPE_METADATA,
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
),
|
|
|
|
|_, _| smallvec![],
|
|
|
|
NO_GENERICS,
|
|
|
|
)
|
2022-01-13 17:13:54 +00:00
|
|
|
} else {
|
2022-03-14 16:11:58 +00:00
|
|
|
bug!(
|
|
|
|
"Only ty::Dynamic is valid for build_dyn_type_di_node(). Found {:?} instead.",
|
|
|
|
dyn_type
|
|
|
|
)
|
2022-01-13 17:13:54 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-01-21 09:35:18 +00:00
|
|
|
/// Create debuginfo for `[T]` and `str`. These are unsized.
|
|
|
|
///
|
2022-01-27 15:55:48 +00:00
|
|
|
/// 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 fat-pointer
|
|
|
|
/// debuginfo of `&[T]`.
|
2022-01-21 09:35:18 +00:00
|
|
|
///
|
2022-01-27 15:55:48 +00:00
|
|
|
/// 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.
|
2022-01-21 09:35:18 +00:00
|
|
|
///
|
2022-01-27 15:55:48 +00:00
|
|
|
/// 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.
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_slice_type_di_node<'ll, 'tcx>(
|
2022-01-13 17:13:54 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
slice_type: Ty<'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
2022-01-13 17:13:54 +00:00
|
|
|
let element_type = match slice_type.kind() {
|
Overhaul `TyS` and `Ty`.
Specifically, change `Ty` from this:
```
pub type Ty<'tcx> = &'tcx TyS<'tcx>;
```
to this
```
pub struct Ty<'tcx>(Interned<'tcx, TyS<'tcx>>);
```
There are two benefits to this.
- It's now a first class type, so we can define methods on it. This
means we can move a lot of methods away from `TyS`, leaving `TyS` as a
barely-used type, which is appropriate given that it's not meant to
be used directly.
- The uniqueness requirement is now explicit, via the `Interned` type.
E.g. the pointer-based `Eq` and `Hash` comes from `Interned`, rather
than via `TyS`, which wasn't obvious at all.
Much of this commit is boring churn. The interesting changes are in
these files:
- compiler/rustc_middle/src/arena.rs
- compiler/rustc_middle/src/mir/visit.rs
- compiler/rustc_middle/src/ty/context.rs
- compiler/rustc_middle/src/ty/mod.rs
Specifically:
- Most mentions of `TyS` are removed. It's very much a dumb struct now;
`Ty` has all the smarts.
- `TyS` now has `crate` visibility instead of `pub`.
- `TyS::make_for_test` is removed in favour of the static `BOOL_TY`,
which just works better with the new structure.
- The `Eq`/`Ord`/`Hash` impls are removed from `TyS`. `Interned`s impls
of `Eq`/`Hash` now suffice. `Ord` is now partly on `Interned`
(pointer-based, for the `Equal` case) and partly on `TyS`
(contents-based, for the other cases).
- There are many tedious sigil adjustments, i.e. adding or removing `*`
or `&`. They seem to be unavoidable.
2022-01-25 03:13:38 +00:00
|
|
|
ty::Slice(element_type) => *element_type,
|
2022-01-13 17:13:54 +00:00
|
|
|
ty::Str => cx.tcx.types.u8,
|
|
|
|
_ => {
|
|
|
|
bug!(
|
2022-03-14 16:11:58 +00:00
|
|
|
"Only ty::Slice is valid for build_slice_type_di_node(). Found {:?} instead.",
|
2022-01-13 17:13:54 +00:00
|
|
|
slice_type
|
|
|
|
)
|
|
|
|
}
|
Improve debug symbol names to avoid ambiguity and work better with MSVC's debugger
There are several cases where names of types and functions in the debug info are either ambiguous, or not helpful, such as including ambiguous placeholders (e.g., `{{impl}}`, `{{closure}}` or `dyn _'`) or dropping qualifications (e.g., for dynamic types).
Instead, each debug symbol name should be unique and useful:
* Include disambiguators for anonymous `DefPathDataName` (closures and generators), and unify their formatting when used as a path-qualifier vs item being qualified.
* Qualify the principal trait for dynamic types.
* If there is no principal trait for a dynamic type, emit all other traits instead.
* Respect the `qualified` argument when emitting ref and pointer types.
* For implementations, emit the disambiguator.
* Print const generics when emitting generic parameters or arguments.
Additionally, when targeting MSVC, its debugger treats many command arguments as C++ expressions, even when the argument is defined to be a symbol name. As such names in the debug info need to be more C++-like to be parsed correctly:
* Avoid characters with special meaning (`#`, `[`, `"`, `+`).
* Never start a name with `<` or `{` as this is treated as an operator.
* `>>` is always treated as a right-shift, even when parsing generic arguments (so add a space to avoid this).
* Emit function declarations using C/C++ style syntax (e.g., leading return type).
* Emit arrays as a synthetic `array$<type, size>` type.
* Include a `$` in all synthetic types as this is a legal character for C++, but not Rust (thus we avoid collisions with user types).
2021-06-24 17:36:28 +00:00
|
|
|
};
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-14 16:11:58 +00:00
|
|
|
let element_type_di_node = type_di_node(cx, element_type);
|
2022-03-03 10:15:25 +00:00
|
|
|
return_if_di_node_created_in_meantime!(cx, unique_type_id);
|
2022-03-14 16:11:58 +00:00
|
|
|
DINodeCreationResult { di_node: element_type_di_node, already_stored_in_typemap: false }
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Get the debuginfo node for the given type.
|
|
|
|
///
|
|
|
|
/// This function will look up the debuginfo node in the TypeMap. If it can't find it, it
|
|
|
|
/// will create the node by dispatching to the corresponding `build_*_di_node()` function.
|
|
|
|
pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
|
2022-02-04 12:19:55 +00:00
|
|
|
let unique_type_id = UniqueTypeId::for_ty(cx.tcx, t);
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
if let Some(existing_di_node) = debug_context(cx).type_map.di_node_for_unique_id(unique_type_id)
|
|
|
|
{
|
|
|
|
return existing_di_node;
|
2022-02-04 12:19:55 +00:00
|
|
|
}
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
debug!("type_di_node: {:?}", t);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let DINodeCreationResult { di_node, already_stored_in_typemap } = match *t.kind() {
|
2019-12-24 22:38:22 +00:00
|
|
|
ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
|
2022-03-03 10:15:25 +00:00
|
|
|
DINodeCreationResult::new(build_basic_type_di_node(cx, t), false)
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
2021-09-30 17:38:50 +00:00
|
|
|
ty::Tuple(elements) if elements.is_empty() => {
|
2022-03-03 10:15:25 +00:00
|
|
|
DINodeCreationResult::new(build_basic_type_di_node(cx, t), false)
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
2022-03-03 10:15:25 +00:00
|
|
|
ty::Array(..) => build_fixed_size_array_di_node(cx, unique_type_id, t),
|
|
|
|
ty::Slice(_) | ty::Str => build_slice_type_di_node(cx, t, unique_type_id),
|
|
|
|
ty::Dynamic(..) => build_dyn_type_di_node(cx, t, unique_type_id),
|
|
|
|
ty::Foreign(..) => build_foreign_type_di_node(cx, t, unique_type_id),
|
2022-01-13 17:13:54 +00:00
|
|
|
ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => {
|
2022-03-03 10:15:25 +00:00
|
|
|
build_pointer_or_reference_di_node(cx, t, pointee_type, unique_type_id)
|
2022-01-13 17:13:54 +00:00
|
|
|
}
|
2022-03-08 07:06:59 +00:00
|
|
|
// Box<T, A> may have a non-ZST allocator A. In that case, we
|
|
|
|
// cannot treat Box<T, A> as just an owned alias of `*mut T`.
|
|
|
|
ty::Adt(def, substs) if def.is_box() && cx.layout_of(substs.type_at(1)).is_zst() => {
|
2022-03-03 10:15:25 +00:00
|
|
|
build_pointer_or_reference_di_node(cx, t, t.boxed_ty(), unique_type_id)
|
2016-12-26 13:34:03 +00:00
|
|
|
}
|
2022-03-03 10:15:25 +00:00
|
|
|
ty::FnDef(..) | ty::FnPtr(_) => build_subroutine_type_di_node(cx, unique_type_id),
|
|
|
|
ty::Closure(..) => build_closure_env_di_node(cx, unique_type_id),
|
|
|
|
ty::Generator(..) => enums::build_generator_di_node(cx, unique_type_id),
|
2018-08-22 00:35:02 +00:00
|
|
|
ty::Adt(def, ..) => match def.adt_kind() {
|
2022-03-03 10:15:25 +00:00
|
|
|
AdtKind::Struct => build_struct_type_di_node(cx, unique_type_id),
|
|
|
|
AdtKind::Union => build_union_type_di_node(cx, unique_type_id),
|
|
|
|
AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id),
|
2016-09-05 22:26:02 +00:00
|
|
|
},
|
2022-03-03 10:15:25 +00:00
|
|
|
ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
|
2020-06-22 12:36:53 +00:00
|
|
|
// Type parameters from polymorphized functions.
|
2022-03-03 10:15:25 +00:00
|
|
|
ty::Param(_) => build_param_type_di_node(cx, t),
|
2022-03-14 16:11:58 +00:00
|
|
|
_ => bug!("debuginfo: unexpected type in type_di_node(): {:?}", t),
|
2015-04-24 04:48:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
{
|
|
|
|
if already_stored_in_typemap {
|
2022-02-04 12:19:55 +00:00
|
|
|
// Make sure that we really do have a `TypeMap` entry for the unique type ID.
|
2022-03-03 10:15:25 +00:00
|
|
|
let di_node_for_uid =
|
|
|
|
match debug_context(cx).type_map.di_node_for_unique_id(unique_type_id) {
|
|
|
|
Some(di_node) => di_node,
|
2022-02-04 12:19:55 +00:00
|
|
|
None => {
|
2022-01-10 14:59:52 +00:00
|
|
|
bug!(
|
2022-03-14 16:11:58 +00:00
|
|
|
"expected type debuginfo node for unique \
|
2022-02-04 12:19:55 +00:00
|
|
|
type ID '{:?}' to already be in \
|
|
|
|
the `debuginfo::TypeMap` but it \
|
2022-02-24 16:19:18 +00:00
|
|
|
was not.",
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id,
|
2019-12-24 22:38:22 +00:00
|
|
|
);
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
2022-02-04 12:19:55 +00:00
|
|
|
};
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
debug_assert_eq!(di_node_for_uid as *const _, di_node as *const _);
|
2015-04-24 04:48:10 +00:00
|
|
|
} else {
|
2022-03-03 10:15:25 +00:00
|
|
|
debug_context(cx).type_map.insert(unique_type_id, di_node);
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
di_node
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
// FIXME(mw): Cache this via a regular UniqueTypeId instead of an extra field in the debug context.
|
|
|
|
fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll DIType {
|
2022-02-04 12:19:55 +00:00
|
|
|
*debug_context(cx).recursion_marker_type.get_or_init(move || {
|
|
|
|
unsafe {
|
|
|
|
// The choice of type here is pretty arbitrary -
|
|
|
|
// anything reading the debuginfo for a recursive
|
|
|
|
// type is going to see *something* weird - the only
|
|
|
|
// question is what exactly it will see.
|
|
|
|
//
|
|
|
|
// FIXME: the name `<recur_type>` does not fit the naming scheme
|
|
|
|
// of other types.
|
2022-02-24 16:19:18 +00:00
|
|
|
//
|
|
|
|
// FIXME: it might make sense to use an actual pointer type here
|
|
|
|
// so that debuggers can show the address.
|
2022-02-04 12:19:55 +00:00
|
|
|
let name = "<recur_type>";
|
|
|
|
llvm::LLVMRustDIBuilderCreateBasicType(
|
|
|
|
DIB(cx),
|
|
|
|
name.as_ptr().cast(),
|
|
|
|
name.len(),
|
|
|
|
cx.tcx.data_layout.pointer_size.bits(),
|
|
|
|
DW_ATE_unsigned,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-03-31 05:17:15 +00:00
|
|
|
fn hex_encode(data: &[u8]) -> String {
|
|
|
|
let mut hex_string = String::with_capacity(data.len() * 2);
|
|
|
|
for byte in data.iter() {
|
|
|
|
write!(&mut hex_string, "{:02x}", byte).unwrap();
|
|
|
|
}
|
|
|
|
hex_string
|
|
|
|
}
|
|
|
|
|
2021-12-14 18:49:49 +00:00
|
|
|
pub fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> &'ll DIFile {
|
2021-04-19 22:27:02 +00:00
|
|
|
debug!("file_metadata: file_name: {:?}", source_file.name);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2020-04-05 08:43:44 +00:00
|
|
|
let hash = Some(&source_file.src_hash);
|
2021-04-19 22:27:02 +00:00
|
|
|
let file_name = Some(source_file.name.prefer_remapped().to_string());
|
2020-02-10 01:03:24 +00:00
|
|
|
let directory = if source_file.is_real_file() && !source_file.is_imported() {
|
2021-08-26 10:46:01 +00:00
|
|
|
Some(
|
|
|
|
cx.sess()
|
|
|
|
.opts
|
|
|
|
.working_dir
|
|
|
|
.to_string_lossy(FileNameDisplayPreference::Remapped)
|
|
|
|
.to_string(),
|
|
|
|
)
|
2017-04-24 17:01:19 +00:00
|
|
|
} else {
|
|
|
|
// If the path comes from an upstream crate we assume it has been made
|
|
|
|
// independent of the compiler's working directory one way or another.
|
2019-05-06 01:47:03 +00:00
|
|
|
None
|
|
|
|
};
|
2020-03-31 05:17:15 +00:00
|
|
|
file_metadata_raw(cx, file_name, directory, hash)
|
Workaround ODR violations in enum debuginfo
When using a generic enum type that was defined in an external crate,
our debuginfo currently claims that the concrete type (e.g. Option<i32>)
was defined in the current crate, where it was first used.
This means that if there are multiple crates that all use, for example,
Option<i32> values, they'll have conflicting debuginfo, each crate
claiming to have defined that type. This doesn't cause problems in
regular builds, but with LTO enabled, LLVM complains because it tries to
merge the debuginfo for those types and sees the ODR violations.
Since I couldn't find a way to get the file info for the external crate
that actually defined the enum, I'm working around the issue by using
"<unknown>" as the file for enum types. We'll want to re-visit and fix
this later, but this at least this fixes the ICE. And with the file
being unknown instead of wrong, the debuginfo isn't really worse than
before either.
Fixes #26447
2015-07-29 11:53:59 +00:00
|
|
|
}
|
|
|
|
|
2021-12-14 18:49:49 +00:00
|
|
|
pub fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
|
2020-03-31 05:17:15 +00:00
|
|
|
file_metadata_raw(cx, None, None, None)
|
Workaround ODR violations in enum debuginfo
When using a generic enum type that was defined in an external crate,
our debuginfo currently claims that the concrete type (e.g. Option<i32>)
was defined in the current crate, where it was first used.
This means that if there are multiple crates that all use, for example,
Option<i32> values, they'll have conflicting debuginfo, each crate
claiming to have defined that type. This doesn't cause problems in
regular builds, but with LTO enabled, LLVM complains because it tries to
merge the debuginfo for those types and sees the ODR violations.
Since I couldn't find a way to get the file info for the external crate
that actually defined the enum, I'm working around the issue by using
"<unknown>" as the file for enum types. We'll want to re-visit and fix
this later, but this at least this fixes the ICE. And with the file
being unknown instead of wrong, the debuginfo isn't really worse than
before either.
Fixes #26447
2015-07-29 11:53:59 +00:00
|
|
|
}
|
|
|
|
|
2021-12-14 18:49:49 +00:00
|
|
|
fn file_metadata_raw<'ll>(
|
2019-12-24 22:38:22 +00:00
|
|
|
cx: &CodegenCx<'ll, '_>,
|
|
|
|
file_name: Option<String>,
|
|
|
|
directory: Option<String>,
|
2020-03-31 05:17:15 +00:00
|
|
|
hash: Option<&SourceFileHash>,
|
2019-12-24 22:38:22 +00:00
|
|
|
) -> &'ll DIFile {
|
2019-05-06 01:47:03 +00:00
|
|
|
let key = (file_name, directory);
|
|
|
|
|
|
|
|
match debug_context(cx).created_files.borrow_mut().entry(key) {
|
2020-03-20 14:03:11 +00:00
|
|
|
Entry::Occupied(o) => o.get(),
|
2019-05-06 01:47:03 +00:00
|
|
|
Entry::Vacant(v) => {
|
|
|
|
let (file_name, directory) = v.key();
|
|
|
|
debug!("file_metadata: file_name: {:?}, directory: {:?}", file_name, directory);
|
|
|
|
|
2020-03-06 00:00:00 +00:00
|
|
|
let file_name = file_name.as_deref().unwrap_or("<unknown>");
|
|
|
|
let directory = directory.as_deref().unwrap_or("");
|
2019-05-06 01:47:03 +00:00
|
|
|
|
2020-03-31 05:17:15 +00:00
|
|
|
let (hash_kind, hash_value) = match hash {
|
|
|
|
Some(hash) => {
|
|
|
|
let kind = match hash.kind {
|
|
|
|
rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5,
|
|
|
|
rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1,
|
2020-10-13 15:41:06 +00:00
|
|
|
rustc_span::SourceFileHashAlgorithm::Sha256 => llvm::ChecksumKind::SHA256,
|
2020-03-31 05:17:15 +00:00
|
|
|
};
|
|
|
|
(kind, hex_encode(hash.hash_bytes()))
|
|
|
|
}
|
|
|
|
None => (llvm::ChecksumKind::None, String::new()),
|
|
|
|
};
|
|
|
|
|
2019-05-06 01:47:03 +00:00
|
|
|
let file_metadata = unsafe {
|
2020-03-06 00:00:00 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreateFile(
|
|
|
|
DIB(cx),
|
|
|
|
file_name.as_ptr().cast(),
|
|
|
|
file_name.len(),
|
|
|
|
directory.as_ptr().cast(),
|
|
|
|
directory.len(),
|
2020-03-31 05:17:15 +00:00
|
|
|
hash_kind,
|
|
|
|
hash_value.as_ptr().cast(),
|
|
|
|
hash_value.len(),
|
2020-03-06 00:00:00 +00:00
|
|
|
)
|
2019-05-06 01:47:03 +00:00
|
|
|
};
|
2017-04-24 17:01:19 +00:00
|
|
|
|
2019-05-06 01:47:03 +00:00
|
|
|
v.insert(file_metadata);
|
|
|
|
file_metadata
|
|
|
|
}
|
Workaround ODR violations in enum debuginfo
When using a generic enum type that was defined in an external crate,
our debuginfo currently claims that the concrete type (e.g. Option<i32>)
was defined in the current crate, where it was first used.
This means that if there are multiple crates that all use, for example,
Option<i32> values, they'll have conflicting debuginfo, each crate
claiming to have defined that type. This doesn't cause problems in
regular builds, but with LTO enabled, LLVM complains because it tries to
merge the debuginfo for those types and sees the ODR violations.
Since I couldn't find a way to get the file info for the external crate
that actually defined the enum, I'm working around the issue by using
"<unknown>" as the file for enum types. We'll want to re-visit and fix
this later, but this at least this fixes the ICE. And with the file
being unknown instead of wrong, the debuginfo isn't really worse than
before either.
Fixes #26447
2015-07-29 11:53:59 +00:00
|
|
|
}
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2020-06-25 06:28:00 +00:00
|
|
|
trait MsvcBasicName {
|
|
|
|
fn msvc_basic_name(self) -> &'static str;
|
|
|
|
}
|
|
|
|
|
2020-12-12 14:32:30 +00:00
|
|
|
impl MsvcBasicName for ty::IntTy {
|
2020-06-25 06:28:00 +00:00
|
|
|
fn msvc_basic_name(self) -> &'static str {
|
|
|
|
match self {
|
2020-12-12 14:32:30 +00:00
|
|
|
ty::IntTy::Isize => "ptrdiff_t",
|
|
|
|
ty::IntTy::I8 => "__int8",
|
|
|
|
ty::IntTy::I16 => "__int16",
|
|
|
|
ty::IntTy::I32 => "__int32",
|
|
|
|
ty::IntTy::I64 => "__int64",
|
|
|
|
ty::IntTy::I128 => "__int128",
|
2020-06-25 06:28:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-12 14:32:30 +00:00
|
|
|
impl MsvcBasicName for ty::UintTy {
|
2020-06-25 06:28:00 +00:00
|
|
|
fn msvc_basic_name(self) -> &'static str {
|
|
|
|
match self {
|
2020-12-12 14:32:30 +00:00
|
|
|
ty::UintTy::Usize => "size_t",
|
|
|
|
ty::UintTy::U8 => "unsigned __int8",
|
|
|
|
ty::UintTy::U16 => "unsigned __int16",
|
|
|
|
ty::UintTy::U32 => "unsigned __int32",
|
|
|
|
ty::UintTy::U64 => "unsigned __int64",
|
|
|
|
ty::UintTy::U128 => "unsigned __int128",
|
2020-06-25 06:28:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-12 14:32:30 +00:00
|
|
|
impl MsvcBasicName for ty::FloatTy {
|
2020-06-25 06:28:00 +00:00
|
|
|
fn msvc_basic_name(self) -> &'static str {
|
|
|
|
match self {
|
2020-12-12 14:32:30 +00:00
|
|
|
ty::FloatTy::F32 => "float",
|
|
|
|
ty::FloatTy::F64 => "double",
|
2020-06-25 06:28:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_basic_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
|
|
|
|
debug!("build_basic_type_di_node: {:?}", t);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2020-06-25 06:28:00 +00:00
|
|
|
// When targeting MSVC, emit MSVC style type names for compatibility with
|
|
|
|
// .natvis visualizers (and perhaps other existing native debuggers?)
|
2021-12-28 21:57:18 +00:00
|
|
|
let cpp_like_debuginfo = cpp_like_debuginfo(cx.tcx);
|
2020-06-25 06:28:00 +00:00
|
|
|
|
2020-08-02 22:49:11 +00:00
|
|
|
let (name, encoding) = match t.kind() {
|
2018-08-22 00:35:02 +00:00
|
|
|
ty::Never => ("!", DW_ATE_unsigned),
|
2021-09-30 17:38:50 +00:00
|
|
|
ty::Tuple(elements) if elements.is_empty() => ("()", DW_ATE_unsigned),
|
2018-08-22 00:35:55 +00:00
|
|
|
ty::Bool => ("bool", DW_ATE_boolean),
|
2021-10-14 17:26:42 +00:00
|
|
|
ty::Char => ("char", DW_ATE_UTF),
|
2021-12-28 21:57:18 +00:00
|
|
|
ty::Int(int_ty) if cpp_like_debuginfo => (int_ty.msvc_basic_name(), DW_ATE_signed),
|
|
|
|
ty::Uint(uint_ty) if cpp_like_debuginfo => (uint_ty.msvc_basic_name(), DW_ATE_unsigned),
|
|
|
|
ty::Float(float_ty) if cpp_like_debuginfo => (float_ty.msvc_basic_name(), DW_ATE_float),
|
2019-12-24 22:38:22 +00:00
|
|
|
ty::Int(int_ty) => (int_ty.name_str(), DW_ATE_signed),
|
|
|
|
ty::Uint(uint_ty) => (uint_ty.name_str(), DW_ATE_unsigned),
|
|
|
|
ty::Float(float_ty) => (float_ty.name_str(), DW_ATE_float),
|
2022-03-03 10:15:25 +00:00
|
|
|
_ => bug!("debuginfo::build_basic_type_di_node - `t` is invalid type"),
|
2015-04-24 04:48:10 +00:00
|
|
|
};
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let ty_di_node = unsafe {
|
2016-08-01 23:35:09 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreateBasicType(
|
2015-04-24 04:48:10 +00:00
|
|
|
DIB(cx),
|
2020-03-06 00:00:00 +00:00
|
|
|
name.as_ptr().cast(),
|
|
|
|
name.len(),
|
2020-05-21 17:53:41 +00:00
|
|
|
cx.size_of(t).bits(),
|
2019-12-24 22:38:22 +00:00
|
|
|
encoding,
|
|
|
|
)
|
2015-04-24 04:48:10 +00:00
|
|
|
};
|
|
|
|
|
2021-12-28 21:57:18 +00:00
|
|
|
if !cpp_like_debuginfo {
|
2022-03-03 10:15:25 +00:00
|
|
|
return ty_di_node;
|
2020-06-25 06:28:00 +00:00
|
|
|
}
|
|
|
|
|
2020-08-02 22:49:11 +00:00
|
|
|
let typedef_name = match t.kind() {
|
2020-06-25 06:28:00 +00:00
|
|
|
ty::Int(int_ty) => int_ty.name_str(),
|
|
|
|
ty::Uint(uint_ty) => uint_ty.name_str(),
|
|
|
|
ty::Float(float_ty) => float_ty.name_str(),
|
2022-03-03 10:15:25 +00:00
|
|
|
_ => return ty_di_node,
|
2020-06-25 06:28:00 +00:00
|
|
|
};
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let typedef_di_node = unsafe {
|
2020-06-25 06:28:00 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreateTypedef(
|
|
|
|
DIB(cx),
|
2022-03-03 10:15:25 +00:00
|
|
|
ty_di_node,
|
2020-06-25 06:28:00 +00:00
|
|
|
typedef_name.as_ptr().cast(),
|
|
|
|
typedef_name.len(),
|
|
|
|
unknown_file_metadata(cx),
|
|
|
|
0,
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
typedef_di_node
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_foreign_type_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
t: Ty<'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
|
|
|
debug!("build_foreign_type_di_node: {:?}", t);
|
|
|
|
|
|
|
|
let &ty::Foreign(def_id) = unique_type_id.expect_ty().kind() else {
|
|
|
|
bug!("build_foreign_type_di_node() called with unexpected type: {:?}", unique_type_id.expect_ty());
|
|
|
|
};
|
2017-09-03 18:53:58 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
build_type_with_children(
|
2022-01-25 13:26:50 +00:00
|
|
|
cx,
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::Struct,
|
|
|
|
unique_type_id,
|
|
|
|
&compute_debuginfo_type_name(cx.tcx, t, false),
|
|
|
|
cx.size_and_align_of(t),
|
|
|
|
Some(get_namespace_for_item(cx, def_id)),
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
),
|
|
|
|
|_, _| smallvec![],
|
|
|
|
NO_GENERICS,
|
2022-01-25 13:26:50 +00:00
|
|
|
)
|
2017-09-03 18:53:58 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_param_type_di_node<'ll, 'tcx>(
|
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
t: Ty<'tcx>,
|
|
|
|
) -> DINodeCreationResult<'ll> {
|
|
|
|
debug!("build_param_type_di_node: {:?}", t);
|
2020-06-22 12:36:53 +00:00
|
|
|
let name = format!("{:?}", t);
|
2022-03-03 10:15:25 +00:00
|
|
|
DINodeCreationResult {
|
|
|
|
di_node: unsafe {
|
|
|
|
llvm::LLVMRustDIBuilderCreateBasicType(
|
|
|
|
DIB(cx),
|
|
|
|
name.as_ptr().cast(),
|
|
|
|
name.len(),
|
|
|
|
Size::ZERO.bits(),
|
|
|
|
DW_ATE_unsigned,
|
|
|
|
)
|
|
|
|
},
|
|
|
|
already_stored_in_typemap: false,
|
2020-08-07 22:39:38 +00:00
|
|
|
}
|
2020-06-22 12:36:53 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
pub fn build_compile_unit_di_node<'ll, 'tcx>(
|
2021-12-14 18:49:49 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2019-06-11 21:11:55 +00:00
|
|
|
codegen_unit_name: &str,
|
2022-03-03 10:15:25 +00:00
|
|
|
debug_context: &CodegenUnitDebugContext<'ll, 'tcx>,
|
2019-06-11 21:11:55 +00:00
|
|
|
) -> &'ll DIDescriptor {
|
2018-01-05 04:14:44 +00:00
|
|
|
let mut name_in_debuginfo = match tcx.sess.local_crate_source_file {
|
2017-05-19 08:55:25 +00:00
|
|
|
Some(ref path) => path.clone(),
|
2021-12-15 03:39:23 +00:00
|
|
|
None => PathBuf::from(tcx.crate_name(LOCAL_CRATE).as_str()),
|
2015-04-24 04:48:10 +00:00
|
|
|
};
|
|
|
|
|
2021-12-17 04:39:41 +00:00
|
|
|
// To avoid breaking split DWARF, we need to ensure that each codegen unit
|
|
|
|
// has a unique `DW_AT_name`. This is because there's a remote chance that
|
|
|
|
// different codegen units for the same module will have entirely
|
|
|
|
// identical DWARF entries for the purpose of the DWO ID, which would
|
|
|
|
// violate Appendix F ("Split Dwarf Object Files") of the DWARF 5
|
|
|
|
// specification. LLVM uses the algorithm specified in section 7.32 "Type
|
|
|
|
// Signature Computation" to compute the DWO ID, which does not include
|
|
|
|
// any fields that would distinguish compilation units. So we must embed
|
|
|
|
// the codegen unit name into the `DW_AT_name`. (Issue #88521.)
|
|
|
|
//
|
|
|
|
// Additionally, the OSX linker has an idiosyncrasy where it will ignore
|
|
|
|
// some debuginfo if multiple object files with the same `DW_AT_name` are
|
|
|
|
// linked together.
|
|
|
|
//
|
|
|
|
// As a workaround for these two issues, we generate unique names for each
|
|
|
|
// object file. Those do not correspond to an actual source file but that
|
|
|
|
// is harmless.
|
|
|
|
name_in_debuginfo.push("@");
|
|
|
|
name_in_debuginfo.push(codegen_unit_name);
|
2017-05-19 08:55:25 +00:00
|
|
|
|
2022-03-14 16:11:58 +00:00
|
|
|
debug!("build_compile_unit_di_node: {:?}", name_in_debuginfo);
|
2019-12-24 22:38:22 +00:00
|
|
|
let rustc_producer =
|
|
|
|
format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"),);
|
2017-03-08 18:08:09 +00:00
|
|
|
// FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice.
|
2019-07-19 14:08:37 +00:00
|
|
|
let producer = format!("clang LLVM ({})", rustc_producer);
|
2015-04-24 04:48:10 +00:00
|
|
|
|
2018-08-07 14:04:34 +00:00
|
|
|
let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
|
2021-08-26 10:46:01 +00:00
|
|
|
let work_dir = tcx.sess.opts.working_dir.to_string_lossy(FileNameDisplayPreference::Remapped);
|
2015-04-24 04:48:10 +00:00
|
|
|
let flags = "\0";
|
2021-05-11 12:39:04 +00:00
|
|
|
let output_filenames = tcx.output_filenames(());
|
2020-11-30 16:39:08 +00:00
|
|
|
let split_name = if tcx.sess.target_can_use_split_dwarf() {
|
2021-05-11 12:39:04 +00:00
|
|
|
output_filenames
|
sess/cg: re-introduce split dwarf kind
In #79570, `-Z split-dwarf-kind={none,single,split}` was replaced by `-C
split-debuginfo={off,packed,unpacked}`. `-C split-debuginfo`'s packed
and unpacked aren't exact parallels to single and split, respectively.
On Unix, `-C split-debuginfo=packed` will put debuginfo into object
files and package debuginfo into a DWARF package file (`.dwp`) and
`-C split-debuginfo=unpacked` will put debuginfo into dwarf object files
and won't package it.
In the initial implementation of Split DWARF, split mode wrote sections
which did not require relocation into a DWARF object (`.dwo`) file which
was ignored by the linker and then packaged those DWARF objects into
DWARF packages (`.dwp`). In single mode, sections which did not require
relocation were written into object files but ignored by the linker and
were not packaged. However, both split and single modes could be
packaged or not, the primary difference in behaviour was where the
debuginfo sections that did not require link-time relocation were
written (in a DWARF object or the object file).
This commit re-introduces a `-Z split-dwarf-kind` flag, which can be
used to pick between split and single modes when `-C split-debuginfo` is
used to enable Split DWARF (either packed or unpacked).
Signed-off-by: David Wood <david.wood@huawei.com>
2021-10-08 16:10:17 +00:00
|
|
|
.split_dwarf_path(
|
|
|
|
tcx.sess.split_debuginfo(),
|
|
|
|
tcx.sess.opts.debugging_opts.split_dwarf_kind,
|
|
|
|
Some(codegen_unit_name),
|
|
|
|
)
|
2021-12-06 23:59:59 +00:00
|
|
|
// We get a path relative to the working directory from split_dwarf_path
|
|
|
|
.map(|f| tcx.sess.source_map().path_mapping().map_prefix(f).0)
|
2020-11-30 16:39:08 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
.unwrap_or_default();
|
2020-09-23 16:33:54 +00:00
|
|
|
let split_name = split_name.to_str().unwrap();
|
2019-05-21 11:41:44 +00:00
|
|
|
|
|
|
|
// FIXME(#60020):
|
|
|
|
//
|
|
|
|
// This should actually be
|
|
|
|
//
|
2019-05-17 01:20:14 +00:00
|
|
|
// let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo);
|
2019-05-21 11:41:44 +00:00
|
|
|
//
|
2019-05-17 01:20:14 +00:00
|
|
|
// That is, we should set LLVM's emission kind to `LineTablesOnly` if
|
2019-05-21 11:41:44 +00:00
|
|
|
// we are compiling with "limited" debuginfo. However, some of the
|
|
|
|
// existing tools relied on slightly more debuginfo being generated than
|
|
|
|
// would be the case with `LineTablesOnly`, and we did not want to break
|
|
|
|
// these tools in a "drive-by fix", without a good idea or plan about
|
|
|
|
// what limited debuginfo should exactly look like. So for now we keep
|
|
|
|
// the emission kind as `FullDebug`.
|
|
|
|
//
|
|
|
|
// See https://github.com/rust-lang/rust/issues/60020 for details.
|
|
|
|
let kind = DebugEmissionKind::FullDebug;
|
|
|
|
assert!(tcx.sess.opts.debuginfo != DebugInfo::None);
|
2017-02-11 21:01:25 +00:00
|
|
|
|
|
|
|
unsafe {
|
2021-02-14 15:12:14 +00:00
|
|
|
let compile_unit_file = llvm::LLVMRustDIBuilderCreateFile(
|
2019-12-24 22:38:22 +00:00
|
|
|
debug_context.builder,
|
2020-03-06 00:00:00 +00:00
|
|
|
name_in_debuginfo.as_ptr().cast(),
|
|
|
|
name_in_debuginfo.len(),
|
2021-02-14 15:12:14 +00:00
|
|
|
work_dir.as_ptr().cast(),
|
|
|
|
work_dir.len(),
|
2020-03-31 05:17:15 +00:00
|
|
|
llvm::ChecksumKind::None,
|
|
|
|
ptr::null(),
|
|
|
|
0,
|
2019-12-24 22:38:22 +00:00
|
|
|
);
|
2017-02-11 21:01:25 +00:00
|
|
|
|
2017-02-13 09:57:50 +00:00
|
|
|
let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit(
|
2016-07-12 22:40:38 +00:00
|
|
|
debug_context.builder,
|
2015-04-24 04:48:10 +00:00
|
|
|
DW_LANG_RUST,
|
2021-02-14 15:12:14 +00:00
|
|
|
compile_unit_file,
|
2020-03-06 00:00:00 +00:00
|
|
|
producer.as_ptr().cast(),
|
|
|
|
producer.len(),
|
2018-01-05 04:14:44 +00:00
|
|
|
tcx.sess.opts.optimize != config::OptLevel::No,
|
2019-10-05 07:48:14 +00:00
|
|
|
flags.as_ptr().cast(),
|
2015-04-24 04:48:10 +00:00
|
|
|
0,
|
2021-02-14 15:12:14 +00:00
|
|
|
// NB: this doesn't actually have any perceptible effect, it seems. LLVM will instead
|
|
|
|
// put the path supplied to `MCSplitDwarfFile` into the debug info of the final
|
|
|
|
// output(s).
|
2019-10-05 07:48:14 +00:00
|
|
|
split_name.as_ptr().cast(),
|
2020-03-06 00:00:00 +00:00
|
|
|
split_name.len(),
|
2019-12-24 22:38:22 +00:00
|
|
|
kind,
|
2020-09-23 15:25:20 +00:00
|
|
|
0,
|
2020-09-23 16:33:54 +00:00
|
|
|
tcx.sess.opts.debugging_opts.split_dwarf_inlining,
|
2019-12-24 22:38:22 +00:00
|
|
|
);
|
2017-02-13 09:57:50 +00:00
|
|
|
|
2018-01-05 04:14:44 +00:00
|
|
|
if tcx.sess.opts.debugging_opts.profile {
|
2019-12-24 22:38:22 +00:00
|
|
|
let cu_desc_metadata =
|
|
|
|
llvm::LLVMRustMetadataAsValue(debug_context.llcontext, unit_metadata);
|
2021-05-11 12:39:04 +00:00
|
|
|
let default_gcda_path = &output_filenames.with_extension("gcda");
|
2020-05-26 17:41:40 +00:00
|
|
|
let gcda_path =
|
|
|
|
tcx.sess.opts.debugging_opts.profile_emit.as_ref().unwrap_or(default_gcda_path);
|
2017-06-04 16:50:25 +00:00
|
|
|
|
|
|
|
let gcov_cu_info = [
|
2021-05-11 12:39:04 +00:00
|
|
|
path_to_mdstring(debug_context.llcontext, &output_filenames.with_extension("gcno")),
|
2021-09-30 17:38:50 +00:00
|
|
|
path_to_mdstring(debug_context.llcontext, gcda_path),
|
2017-06-04 16:50:25 +00:00
|
|
|
cu_desc_metadata,
|
|
|
|
];
|
2019-12-24 22:38:22 +00:00
|
|
|
let gcov_metadata = llvm::LLVMMDNodeInContext(
|
|
|
|
debug_context.llcontext,
|
|
|
|
gcov_cu_info.as_ptr(),
|
|
|
|
gcov_cu_info.len() as c_uint,
|
|
|
|
);
|
2017-06-04 16:50:25 +00:00
|
|
|
|
2021-02-13 11:17:15 +00:00
|
|
|
let llvm_gcov_ident = cstr!("llvm.gcov");
|
2019-12-24 22:38:22 +00:00
|
|
|
llvm::LLVMAddNamedMetadataOperand(
|
|
|
|
debug_context.llmod,
|
|
|
|
llvm_gcov_ident.as_ptr(),
|
|
|
|
gcov_metadata,
|
|
|
|
);
|
2017-06-04 16:50:25 +00:00
|
|
|
}
|
2017-02-13 09:57:50 +00:00
|
|
|
|
2020-12-30 18:52:21 +00:00
|
|
|
// Insert `llvm.ident` metadata on the wasm targets since that will
|
2019-07-19 14:08:37 +00:00
|
|
|
// get hooked up to the "producer" sections `processed-by` information.
|
2020-12-30 18:52:21 +00:00
|
|
|
if tcx.sess.target.is_like_wasm {
|
2019-07-19 14:08:37 +00:00
|
|
|
let name_metadata = llvm::LLVMMDStringInContext(
|
|
|
|
debug_context.llcontext,
|
2019-10-05 07:48:14 +00:00
|
|
|
rustc_producer.as_ptr().cast(),
|
2019-07-19 14:08:37 +00:00
|
|
|
rustc_producer.as_bytes().len() as c_uint,
|
|
|
|
);
|
|
|
|
llvm::LLVMAddNamedMetadataOperand(
|
|
|
|
debug_context.llmod,
|
2021-02-13 11:17:15 +00:00
|
|
|
cstr!("llvm.ident").as_ptr(),
|
2019-07-19 14:08:37 +00:00
|
|
|
llvm::LLVMMDNodeInContext(debug_context.llcontext, &name_metadata, 1),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-02-13 09:57:50 +00:00
|
|
|
return unit_metadata;
|
2015-04-24 04:48:10 +00:00
|
|
|
};
|
|
|
|
|
2021-12-14 18:49:49 +00:00
|
|
|
fn path_to_mdstring<'ll>(llcx: &'ll llvm::Context, path: &Path) -> &'ll Value {
|
2018-11-29 13:09:28 +00:00
|
|
|
let path_str = path_to_c_string(path);
|
2017-02-13 09:57:50 +00:00
|
|
|
unsafe {
|
2019-12-24 22:38:22 +00:00
|
|
|
llvm::LLVMMDStringInContext(
|
|
|
|
llcx,
|
|
|
|
path_str.as_ptr(),
|
|
|
|
path_str.as_bytes().len() as c_uint,
|
|
|
|
)
|
2017-02-13 09:57:50 +00:00
|
|
|
}
|
|
|
|
}
|
2015-04-24 04:48:10 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Creates a `DW_TAG_member` entry inside the DIE represented by the given `type_di_node`.
|
|
|
|
fn build_field_di_node<'ll, 'tcx>(
|
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
owner: &'ll DIScope,
|
|
|
|
name: &str,
|
|
|
|
size_and_align: (Size, Align),
|
2017-06-01 18:50:53 +00:00
|
|
|
offset: Size,
|
2016-11-18 22:15:14 +00:00
|
|
|
flags: DIFlags,
|
2022-03-03 10:15:25 +00:00
|
|
|
type_di_node: &'ll DIType,
|
|
|
|
) -> &'ll DIType {
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMRustDIBuilderCreateMemberType(
|
|
|
|
DIB(cx),
|
|
|
|
owner,
|
|
|
|
name.as_ptr().cast(),
|
|
|
|
name.len(),
|
|
|
|
unknown_file_metadata(cx),
|
|
|
|
UNKNOWN_LINE_NUMBER,
|
|
|
|
size_and_align.0.bits(),
|
|
|
|
size_and_align.1.bits() as u32,
|
|
|
|
offset.bits(),
|
|
|
|
flags,
|
|
|
|
type_di_node,
|
|
|
|
)
|
2015-04-29 06:14:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Creates the debuginfo node for a Rust struct type. Maybe be a regular struct or a tuple-struct.
|
|
|
|
fn build_struct_type_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
|
|
|
let struct_type = unique_type_id.expect_ty();
|
|
|
|
let ty::Adt(adt_def, _) = struct_type.kind() else {
|
|
|
|
bug!("build_struct_type_di_node() called with non-struct-type: {:?}", struct_type);
|
2015-08-02 19:52:50 +00:00
|
|
|
};
|
2022-03-03 10:15:25 +00:00
|
|
|
debug_assert!(adt_def.is_struct());
|
|
|
|
let containing_scope = get_namespace_for_item(cx, adt_def.did());
|
|
|
|
let struct_type_and_layout = cx.layout_of(struct_type);
|
|
|
|
let variant_def = adt_def.non_enum_variant();
|
2015-08-02 19:52:50 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::build_type_with_children(
|
2020-06-18 02:39:23 +00:00
|
|
|
cx,
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::Struct,
|
|
|
|
unique_type_id,
|
|
|
|
&compute_debuginfo_type_name(cx.tcx, struct_type, false),
|
|
|
|
size_and_align_of(struct_type_and_layout),
|
|
|
|
Some(containing_scope),
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
),
|
|
|
|
// Fields:
|
|
|
|
|cx, owner| {
|
|
|
|
variant_def
|
|
|
|
.fields
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, f)| {
|
|
|
|
let field_name = if variant_def.ctor_kind == CtorKind::Fn {
|
|
|
|
// This is a tuple struct
|
|
|
|
tuple_field_name(i)
|
|
|
|
} else {
|
|
|
|
// This is struct with named fields
|
|
|
|
Cow::Borrowed(f.name.as_str())
|
|
|
|
};
|
|
|
|
let field_layout = struct_type_and_layout.field(cx, i);
|
|
|
|
build_field_di_node(
|
|
|
|
cx,
|
|
|
|
owner,
|
|
|
|
&field_name[..],
|
|
|
|
(field_layout.size, field_layout.align.abi),
|
|
|
|
struct_type_and_layout.fields.offset(i),
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
type_di_node(cx, field_layout.ty),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
},
|
|
|
|
|cx| build_generic_type_param_di_nodes(cx, struct_type),
|
2015-04-29 06:14:37 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
//=-----------------------------------------------------------------------------
|
|
|
|
// Tuples
|
|
|
|
//=-----------------------------------------------------------------------------
|
|
|
|
|
2021-05-15 11:01:13 +00:00
|
|
|
/// Returns names of captured upvars for closures and generators.
|
|
|
|
///
|
|
|
|
/// Here are some examples:
|
|
|
|
/// - `name__field1__field2` when the upvar is captured by value.
|
|
|
|
/// - `_ref__name__field` when the upvar is captured by reference.
|
2022-03-03 10:15:25 +00:00
|
|
|
///
|
|
|
|
/// For generators this only contains upvars that are shared by all states.
|
|
|
|
fn closure_saved_names_of_captured_variables(tcx: TyCtxt<'_>, def_id: DefId) -> SmallVec<String> {
|
2021-05-15 11:01:13 +00:00
|
|
|
let body = tcx.optimized_mir(def_id);
|
|
|
|
|
|
|
|
body.var_debug_info
|
|
|
|
.iter()
|
|
|
|
.filter_map(|var| {
|
|
|
|
let is_ref = match var.value {
|
|
|
|
mir::VarDebugInfoContents::Place(place) if place.local == mir::Local::new(1) => {
|
|
|
|
// The projection is either `[.., Field, Deref]` or `[.., Field]`. It
|
|
|
|
// implies whether the variable is captured by value or by reference.
|
|
|
|
matches!(place.projection.last().unwrap(), mir::ProjectionElem::Deref)
|
|
|
|
}
|
|
|
|
_ => return None,
|
|
|
|
};
|
|
|
|
let prefix = if is_ref { "_ref__" } else { "" };
|
2021-12-15 03:39:23 +00:00
|
|
|
Some(prefix.to_owned() + var.name.as_str())
|
2021-05-15 11:01:13 +00:00
|
|
|
})
|
2022-03-03 10:15:25 +00:00
|
|
|
.collect()
|
2021-05-15 11:01:13 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Builds the DW_TAG_member debuginfo nodes for the upvars of a closure or generator.
|
|
|
|
/// For a generator, this will handle upvars shared by all states.
|
|
|
|
fn build_upvar_field_di_nodes<'ll, 'tcx>(
|
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
closure_or_generator_ty: Ty<'tcx>,
|
2022-03-14 16:11:58 +00:00
|
|
|
closure_or_generator_di_node: &'ll DIType,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> SmallVec<&'ll DIType> {
|
|
|
|
let (&def_id, up_var_tys) = match closure_or_generator_ty.kind() {
|
|
|
|
ty::Generator(def_id, substs, _) => {
|
|
|
|
let upvar_tys: SmallVec<_> = substs.as_generator().prefix_tys().collect();
|
|
|
|
(def_id, upvar_tys)
|
|
|
|
}
|
|
|
|
ty::Closure(def_id, substs) => {
|
|
|
|
let upvar_tys: SmallVec<_> = substs.as_closure().upvar_tys().collect();
|
|
|
|
(def_id, upvar_tys)
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
bug!(
|
2022-03-14 16:11:58 +00:00
|
|
|
"build_upvar_field_di_nodes() called with non-closure-or-generator-type: {:?}",
|
2022-03-03 10:15:25 +00:00
|
|
|
closure_or_generator_ty
|
|
|
|
)
|
|
|
|
}
|
|
|
|
};
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2022-03-03 11:45:35 +00:00
|
|
|
debug_assert!(
|
|
|
|
up_var_tys
|
|
|
|
.iter()
|
|
|
|
.all(|&t| t == cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t))
|
|
|
|
);
|
2022-03-03 10:15:25 +00:00
|
|
|
|
|
|
|
let capture_names = closure_saved_names_of_captured_variables(cx.tcx, def_id);
|
|
|
|
let layout = cx.layout_of(closure_or_generator_ty);
|
|
|
|
|
|
|
|
up_var_tys
|
|
|
|
.into_iter()
|
|
|
|
.zip(capture_names.iter())
|
|
|
|
.enumerate()
|
|
|
|
.map(|(index, (up_var_ty, capture_name))| {
|
|
|
|
build_field_di_node(
|
|
|
|
cx,
|
2022-03-14 16:11:58 +00:00
|
|
|
closure_or_generator_di_node,
|
2022-03-03 10:15:25 +00:00
|
|
|
capture_name,
|
|
|
|
cx.size_and_align_of(up_var_ty),
|
|
|
|
layout.fields.offset(index),
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
type_di_node(cx, up_var_ty),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect()
|
2015-04-29 06:14:37 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Builds the DW_TAG_structure_type debuginfo node for a Rust tuple type.
|
|
|
|
fn build_tuple_type_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
|
|
|
let tuple_type = unique_type_id.expect_ty();
|
|
|
|
let &ty::Tuple(component_types) = tuple_type.kind() else {
|
|
|
|
bug!("build_tuple_type_di_node() called with non-tuple-type: {:?}", tuple_type)
|
|
|
|
};
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let tuple_type_and_layout = cx.layout_of(tuple_type);
|
|
|
|
let type_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false);
|
|
|
|
|
|
|
|
type_map::build_type_with_children(
|
2015-04-29 06:14:37 +00:00
|
|
|
cx,
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::Struct,
|
|
|
|
unique_type_id,
|
|
|
|
&type_name,
|
|
|
|
size_and_align_of(tuple_type_and_layout),
|
|
|
|
NO_SCOPE_METADATA,
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
),
|
|
|
|
// Fields:
|
2022-03-14 16:11:58 +00:00
|
|
|
|cx, tuple_di_node| {
|
2022-03-03 10:15:25 +00:00
|
|
|
component_types
|
|
|
|
.into_iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(index, component_type)| {
|
|
|
|
build_field_di_node(
|
|
|
|
cx,
|
2022-03-14 16:11:58 +00:00
|
|
|
tuple_di_node,
|
2022-03-03 10:15:25 +00:00
|
|
|
&tuple_field_name(index),
|
|
|
|
cx.size_and_align_of(component_type),
|
|
|
|
tuple_type_and_layout.fields.offset(index),
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
type_di_node(cx, component_type),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
},
|
|
|
|
NO_GENERICS,
|
2015-04-29 06:14:37 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-03-14 16:11:58 +00:00
|
|
|
/// Builds the debuginfo node for a closure environment.
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_closure_env_di_node<'ll, 'tcx>(
|
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
|
|
|
) -> DINodeCreationResult<'ll> {
|
|
|
|
let closure_env_type = unique_type_id.expect_ty();
|
|
|
|
let &ty::Closure(def_id, _substs) = closure_env_type.kind() else {
|
2022-03-14 16:11:58 +00:00
|
|
|
bug!("build_closure_env_di_node() called with non-closure-type: {:?}", closure_env_type)
|
2022-03-03 10:15:25 +00:00
|
|
|
};
|
|
|
|
let containing_scope = get_namespace_for_item(cx, def_id);
|
|
|
|
let type_name = compute_debuginfo_type_name(cx.tcx, closure_env_type, false);
|
2016-08-22 18:11:22 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::build_type_with_children(
|
|
|
|
cx,
|
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::Struct,
|
|
|
|
unique_type_id,
|
|
|
|
&type_name,
|
|
|
|
cx.size_and_align_of(closure_env_type),
|
|
|
|
Some(containing_scope),
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
),
|
|
|
|
// Fields:
|
|
|
|
|cx, owner| build_upvar_field_di_nodes(cx, closure_env_type, owner),
|
2022-03-03 13:43:17 +00:00
|
|
|
NO_GENERICS,
|
2022-03-03 10:15:25 +00:00
|
|
|
)
|
2016-08-22 18:11:22 +00:00
|
|
|
}
|
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Build the debuginfo node for a Rust `union` type.
|
|
|
|
fn build_union_type_di_node<'ll, 'tcx>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
2022-02-04 12:19:55 +00:00
|
|
|
unique_type_id: UniqueTypeId<'tcx>,
|
2022-03-03 10:15:25 +00:00
|
|
|
) -> DINodeCreationResult<'ll> {
|
|
|
|
let union_type = unique_type_id.expect_ty();
|
|
|
|
let (union_def_id, variant_def) = match union_type.kind() {
|
2022-03-04 20:28:41 +00:00
|
|
|
ty::Adt(def, _) => (def.did(), def.non_enum_variant()),
|
2022-03-03 10:15:25 +00:00
|
|
|
_ => bug!("build_union_type_di_node on a non-ADT"),
|
2016-08-22 18:11:22 +00:00
|
|
|
};
|
2017-07-07 12:23:38 +00:00
|
|
|
let containing_scope = get_namespace_for_item(cx, union_def_id);
|
2022-03-03 10:15:25 +00:00
|
|
|
let union_ty_and_layout = cx.layout_of(union_type);
|
|
|
|
let type_name = compute_debuginfo_type_name(cx.tcx, union_type, false);
|
2016-08-22 18:11:22 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::build_type_with_children(
|
2016-08-22 18:11:22 +00:00
|
|
|
cx,
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::Union,
|
|
|
|
unique_type_id,
|
|
|
|
&type_name,
|
|
|
|
size_and_align_of(union_ty_and_layout),
|
|
|
|
Some(containing_scope),
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
),
|
|
|
|
// Fields:
|
|
|
|
|cx, owner| {
|
|
|
|
variant_def
|
|
|
|
.fields
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(i, f)| {
|
|
|
|
let field_layout = union_ty_and_layout.field(cx, i);
|
|
|
|
build_field_di_node(
|
|
|
|
cx,
|
|
|
|
owner,
|
|
|
|
f.name.as_str(),
|
|
|
|
size_and_align_of(field_layout),
|
|
|
|
Size::ZERO,
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
type_di_node(cx, field_layout.ty),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
},
|
|
|
|
// Generics:
|
|
|
|
|cx| build_generic_type_param_di_nodes(cx, union_type),
|
2016-08-22 18:11:22 +00:00
|
|
|
)
|
|
|
|
}
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2018-05-16 15:58:54 +00:00
|
|
|
// FIXME(eddyb) maybe precompute this? Right now it's computed once
|
|
|
|
// per generator monomorphization, but it doesn't depend on substs.
|
2021-12-14 18:49:49 +00:00
|
|
|
fn generator_layout_and_saved_local_names<'tcx>(
|
2018-05-16 15:58:54 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
def_id: DefId,
|
2020-04-19 11:00:18 +00:00
|
|
|
) -> (&'tcx GeneratorLayout<'tcx>, IndexVec<mir::GeneratorSavedLocal, Option<Symbol>>) {
|
2018-05-16 15:58:54 +00:00
|
|
|
let body = tcx.optimized_mir(def_id);
|
2021-01-17 12:27:05 +00:00
|
|
|
let generator_layout = body.generator_layout().unwrap();
|
2019-12-24 22:38:22 +00:00
|
|
|
let mut generator_saved_local_names = IndexVec::from_elem(None, &generator_layout.field_tys);
|
2018-05-16 15:58:54 +00:00
|
|
|
|
2019-12-11 19:50:03 +00:00
|
|
|
let state_arg = mir::Local::new(1);
|
2018-05-16 15:58:54 +00:00
|
|
|
for var in &body.var_debug_info {
|
2022-01-18 19:26:13 +00:00
|
|
|
let mir::VarDebugInfoContents::Place(place) = &var.value else { continue };
|
2020-05-30 19:02:32 +00:00
|
|
|
if place.local != state_arg {
|
2018-05-16 15:58:54 +00:00
|
|
|
continue;
|
|
|
|
}
|
2020-05-30 19:02:32 +00:00
|
|
|
match place.projection[..] {
|
2018-05-16 15:58:54 +00:00
|
|
|
[
|
|
|
|
// Deref of the `Pin<&mut Self>` state argument.
|
|
|
|
mir::ProjectionElem::Field(..),
|
|
|
|
mir::ProjectionElem::Deref,
|
|
|
|
// Field of a variant of the state.
|
|
|
|
mir::ProjectionElem::Downcast(_, variant),
|
|
|
|
mir::ProjectionElem::Field(field, _),
|
|
|
|
] => {
|
2021-11-30 18:08:41 +00:00
|
|
|
let name = &mut generator_saved_local_names
|
|
|
|
[generator_layout.variant_fields[variant][field]];
|
2018-05-16 15:58:54 +00:00
|
|
|
if name.is_none() {
|
|
|
|
name.replace(var.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(generator_layout, generator_saved_local_names)
|
|
|
|
}
|
|
|
|
|
2019-05-17 01:20:14 +00:00
|
|
|
/// Computes the type parameters for a type, if any, for the given metadata.
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_generic_type_param_di_nodes<'ll, 'tcx>(
|
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
) -> SmallVec<&'ll DIType> {
|
2020-08-02 22:49:11 +00:00
|
|
|
if let ty::Adt(def, substs) = *ty.kind() {
|
2020-02-29 00:56:37 +00:00
|
|
|
if substs.types().next().is_some() {
|
2022-03-04 20:28:41 +00:00
|
|
|
let generics = cx.tcx.generics_of(def.did());
|
2018-10-12 13:34:14 +00:00
|
|
|
let names = get_parameter_names(cx, generics);
|
2022-03-03 10:15:25 +00:00
|
|
|
let template_params: SmallVec<_> = iter::zip(substs, names)
|
2019-12-24 22:38:22 +00:00
|
|
|
.filter_map(|(kind, name)| {
|
|
|
|
if let GenericArgKind::Type(ty) = kind.unpack() {
|
|
|
|
let actual_type =
|
|
|
|
cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
|
2022-03-14 16:11:58 +00:00
|
|
|
let actual_type_di_node = type_di_node(cx, actual_type);
|
2021-12-15 03:39:23 +00:00
|
|
|
let name = name.as_str();
|
2019-12-24 22:38:22 +00:00
|
|
|
Some(unsafe {
|
2022-03-03 10:15:25 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
|
2019-12-24 22:38:22 +00:00
|
|
|
DIB(cx),
|
|
|
|
None,
|
2020-03-06 00:00:00 +00:00
|
|
|
name.as_ptr().cast(),
|
|
|
|
name.len(),
|
2022-03-14 16:11:58 +00:00
|
|
|
actual_type_di_node,
|
2022-03-03 10:15:25 +00:00
|
|
|
)
|
2019-12-24 22:38:22 +00:00
|
|
|
})
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
2018-10-12 13:34:14 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
return template_params;
|
2018-10-12 13:34:14 +00:00
|
|
|
}
|
|
|
|
}
|
2022-03-03 10:15:25 +00:00
|
|
|
|
|
|
|
return smallvec![];
|
2018-10-12 13:34:14 +00:00
|
|
|
|
2019-12-24 22:38:22 +00:00
|
|
|
fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
|
|
|
|
let mut names = generics
|
|
|
|
.parent
|
2021-02-25 01:13:42 +00:00
|
|
|
.map_or_else(Vec::new, |def_id| get_parameter_names(cx, cx.tcx.generics_of(def_id)));
|
2018-10-12 13:34:14 +00:00
|
|
|
names.extend(generics.params.iter().map(|param| param.name));
|
|
|
|
names
|
2015-04-29 06:14:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates debug information for the given global variable.
|
|
|
|
///
|
2022-03-03 10:15:25 +00:00
|
|
|
/// Adds the created debuginfo nodes directly to the crate's IR.
|
|
|
|
pub fn build_global_var_di_node<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, global: &'ll Value) {
|
2018-01-05 04:58:34 +00:00
|
|
|
if cx.dbg_cx.is_none() {
|
2015-04-29 06:14:37 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-02-11 22:20:02 +00:00
|
|
|
// Only create type information if full debuginfo is enabled
|
|
|
|
if cx.sess().opts.debuginfo != DebugInfo::Full {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-05 04:58:34 +00:00
|
|
|
let tcx = cx.tcx;
|
2018-04-12 12:52:09 +00:00
|
|
|
|
2019-05-17 01:20:14 +00:00
|
|
|
// We may want to remove the namespace scope if we're in an extern block (see
|
|
|
|
// https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952).
|
2018-02-19 11:41:10 +00:00
|
|
|
let var_scope = get_namespace_for_item(cx, def_id);
|
2018-04-12 12:52:09 +00:00
|
|
|
let span = tcx.def_span(def_id);
|
2015-04-29 06:14:37 +00:00
|
|
|
|
2018-06-24 22:00:21 +00:00
|
|
|
let (file_metadata, line_number) = if !span.is_dummy() {
|
2020-02-25 00:00:00 +00:00
|
|
|
let loc = cx.lookup_debug_loc(span.lo());
|
2020-02-10 01:03:24 +00:00
|
|
|
(file_metadata(cx, &loc.file), loc.line)
|
2015-04-29 06:14:37 +00:00
|
|
|
} else {
|
2021-02-19 20:50:15 +00:00
|
|
|
(unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)
|
2015-04-29 06:14:37 +00:00
|
|
|
};
|
|
|
|
|
2018-02-19 11:41:10 +00:00
|
|
|
let is_local_to_unit = is_node_local_to_unit(cx, def_id);
|
2020-06-22 12:57:03 +00:00
|
|
|
let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, ty::ParamEnv::reveal_all());
|
2022-03-03 10:15:25 +00:00
|
|
|
let type_di_node = type_di_node(cx, variable_type);
|
2021-12-14 21:32:21 +00:00
|
|
|
let var_name = tcx.item_name(def_id);
|
|
|
|
let var_name = var_name.as_str();
|
2020-07-10 05:45:05 +00:00
|
|
|
let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name;
|
2020-03-06 00:00:00 +00:00
|
|
|
// When empty, linkage_name field is omitted,
|
|
|
|
// which is what we want for no_mangle statics
|
2020-05-26 00:00:00 +00:00
|
|
|
let linkage_name = if var_name == linkage_name { "" } else { linkage_name };
|
2016-11-18 16:11:18 +00:00
|
|
|
|
2017-03-02 03:35:25 +00:00
|
|
|
let global_align = cx.align_of(variable_type);
|
2016-11-18 16:11:18 +00:00
|
|
|
|
2015-04-29 06:14:37 +00:00
|
|
|
unsafe {
|
2019-12-24 22:38:22 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreateStaticVariable(
|
|
|
|
DIB(cx),
|
|
|
|
Some(var_scope),
|
2020-03-06 00:00:00 +00:00
|
|
|
var_name.as_ptr().cast(),
|
|
|
|
var_name.len(),
|
|
|
|
linkage_name.as_ptr().cast(),
|
|
|
|
linkage_name.len(),
|
2019-12-24 22:38:22 +00:00
|
|
|
file_metadata,
|
2021-02-19 20:50:15 +00:00
|
|
|
line_number,
|
2022-03-03 10:15:25 +00:00
|
|
|
type_di_node,
|
2019-12-24 22:38:22 +00:00
|
|
|
is_local_to_unit,
|
|
|
|
global,
|
|
|
|
None,
|
|
|
|
global_align.bytes() as u32,
|
2016-11-18 16:11:18 +00:00
|
|
|
);
|
2015-04-29 06:14:37 +00:00
|
|
|
}
|
|
|
|
}
|
2016-08-25 02:34:31 +00:00
|
|
|
|
2021-10-06 12:26:50 +00:00
|
|
|
/// Generates LLVM debuginfo for a vtable.
|
2022-01-25 13:34:34 +00:00
|
|
|
///
|
|
|
|
/// The vtable type looks like a struct with a field for each function pointer and super-trait
|
|
|
|
/// pointer it contains (plus the `size` and `align` fields).
|
|
|
|
///
|
|
|
|
/// Except for `size`, `align`, and `drop_in_place`, the field names don't try to mirror
|
|
|
|
/// the name of the method they implement. This can be implemented in the future once there
|
|
|
|
/// is a proper disambiguation scheme for dealing with methods from different traits that have
|
|
|
|
/// the same name.
|
2022-03-03 10:15:25 +00:00
|
|
|
fn build_vtable_type_di_node<'ll, 'tcx>(
|
2021-10-06 12:26:50 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
|
|
|
) -> &'ll DIType {
|
|
|
|
let tcx = cx.tcx;
|
|
|
|
|
|
|
|
let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
|
|
|
|
let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
|
|
|
|
let trait_ref = tcx.erase_regions(trait_ref);
|
|
|
|
|
|
|
|
tcx.vtable_entries(trait_ref)
|
|
|
|
} else {
|
|
|
|
COMMON_VTABLE_ENTRIES
|
|
|
|
};
|
|
|
|
|
2022-01-25 13:34:34 +00:00
|
|
|
// All function pointers are described as opaque pointers. This could be improved in the future
|
|
|
|
// by describing them as actual function pointers.
|
|
|
|
let void_pointer_ty = tcx.mk_imm_ptr(tcx.types.unit);
|
2022-03-03 10:15:25 +00:00
|
|
|
let void_pointer_type_di_node = type_di_node(cx, void_pointer_ty);
|
|
|
|
let usize_di_node = type_di_node(cx, tcx.types.usize);
|
2022-01-25 13:34:34 +00:00
|
|
|
let (pointer_size, pointer_align) = cx.size_and_align_of(void_pointer_ty);
|
|
|
|
// If `usize` is not pointer-sized and -aligned then the size and alignment computations
|
|
|
|
// for the vtable as a whole would be wrong. Let's make sure this holds even on weird
|
|
|
|
// platforms.
|
|
|
|
assert_eq!(cx.size_and_align_of(tcx.types.usize), (pointer_size, pointer_align));
|
|
|
|
|
|
|
|
let vtable_type_name =
|
|
|
|
compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::Type);
|
2022-02-04 12:19:55 +00:00
|
|
|
let unique_type_id = UniqueTypeId::for_vtable_ty(tcx, ty, poly_trait_ref);
|
2022-01-25 13:34:34 +00:00
|
|
|
let size = pointer_size * vtable_entries.len() as u64;
|
|
|
|
|
|
|
|
// This gets mapped to a DW_AT_containing_type attribute which allows GDB to correlate
|
|
|
|
// the vtable to the type it is for.
|
2022-03-03 10:15:25 +00:00
|
|
|
let vtable_holder = type_di_node(cx, ty);
|
2022-01-25 13:34:34 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
build_type_with_children(
|
2022-01-25 13:34:34 +00:00
|
|
|
cx,
|
2022-03-03 10:15:25 +00:00
|
|
|
type_map::stub(
|
|
|
|
cx,
|
|
|
|
Stub::VtableTy { vtable_holder },
|
|
|
|
unique_type_id,
|
|
|
|
&vtable_type_name,
|
|
|
|
(size, pointer_align),
|
|
|
|
NO_SCOPE_METADATA,
|
|
|
|
DIFlags::FlagArtificial,
|
|
|
|
),
|
|
|
|
|cx, vtable_type_di_node| {
|
|
|
|
vtable_entries
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.filter_map(|(index, vtable_entry)| {
|
|
|
|
let (field_name, field_type_di_node) = match vtable_entry {
|
|
|
|
ty::VtblEntry::MetadataDropInPlace => {
|
|
|
|
("drop_in_place".to_string(), void_pointer_type_di_node)
|
|
|
|
}
|
|
|
|
ty::VtblEntry::Method(_) => {
|
|
|
|
// Note: This code does not try to give a proper name to each method
|
|
|
|
// because their might be multiple methods with the same name
|
|
|
|
// (coming from different traits).
|
|
|
|
(format!("__method{}", index), void_pointer_type_di_node)
|
|
|
|
}
|
|
|
|
ty::VtblEntry::TraitVPtr(_) => {
|
|
|
|
(format!("__super_trait_ptr{}", index), void_pointer_type_di_node)
|
|
|
|
}
|
|
|
|
ty::VtblEntry::MetadataAlign => ("align".to_string(), usize_di_node),
|
|
|
|
ty::VtblEntry::MetadataSize => ("size".to_string(), usize_di_node),
|
|
|
|
ty::VtblEntry::Vacant => return None,
|
|
|
|
};
|
2022-01-25 13:34:34 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
let field_offset = pointer_size * index as u64;
|
2021-10-06 12:26:50 +00:00
|
|
|
|
2022-03-03 10:15:25 +00:00
|
|
|
Some(build_field_di_node(
|
|
|
|
cx,
|
|
|
|
vtable_type_di_node,
|
|
|
|
&field_name,
|
|
|
|
(pointer_size, pointer_align),
|
|
|
|
field_offset,
|
|
|
|
DIFlags::FlagZero,
|
|
|
|
field_type_di_node,
|
|
|
|
))
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
},
|
|
|
|
NO_GENERICS,
|
|
|
|
)
|
|
|
|
.di_node
|
2021-10-06 12:26:50 +00:00
|
|
|
}
|
|
|
|
|
2018-09-20 13:47:22 +00:00
|
|
|
/// Creates debug information for the given vtable, which is for the
|
|
|
|
/// given type.
|
|
|
|
///
|
|
|
|
/// Adds the created metadata nodes directly to the crate's IR.
|
2022-03-03 10:15:25 +00:00
|
|
|
pub fn create_vtable_di_node<'ll, 'tcx>(
|
2021-10-06 12:26:50 +00:00
|
|
|
cx: &CodegenCx<'ll, 'tcx>,
|
|
|
|
ty: Ty<'tcx>,
|
|
|
|
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
|
|
|
|
vtable: &'ll Value,
|
|
|
|
) {
|
2018-09-20 13:47:22 +00:00
|
|
|
if cx.dbg_cx.is_none() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-02-11 22:20:02 +00:00
|
|
|
// Only create type information if full debuginfo is enabled
|
|
|
|
if cx.sess().opts.debuginfo != DebugInfo::Full {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-01-25 13:34:34 +00:00
|
|
|
let vtable_name =
|
|
|
|
compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable);
|
2022-03-03 10:15:25 +00:00
|
|
|
let vtable_type_di_node = build_vtable_type_di_node(cx, ty, poly_trait_ref);
|
2022-01-25 13:34:34 +00:00
|
|
|
let linkage_name = "";
|
2018-09-20 13:47:22 +00:00
|
|
|
|
|
|
|
unsafe {
|
2019-12-24 22:38:22 +00:00
|
|
|
llvm::LLVMRustDIBuilderCreateStaticVariable(
|
|
|
|
DIB(cx),
|
|
|
|
NO_SCOPE_METADATA,
|
2021-10-06 12:26:50 +00:00
|
|
|
vtable_name.as_ptr().cast(),
|
|
|
|
vtable_name.len(),
|
2020-03-06 00:00:00 +00:00
|
|
|
linkage_name.as_ptr().cast(),
|
|
|
|
linkage_name.len(),
|
2019-12-24 22:38:22 +00:00
|
|
|
unknown_file_metadata(cx),
|
|
|
|
UNKNOWN_LINE_NUMBER,
|
2022-03-03 10:15:25 +00:00
|
|
|
vtable_type_di_node,
|
2019-12-24 22:38:22 +00:00
|
|
|
true,
|
|
|
|
vtable,
|
|
|
|
None,
|
|
|
|
0,
|
|
|
|
);
|
2018-09-20 13:47:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-17 01:20:14 +00:00
|
|
|
/// Creates an "extension" of an existing `DIScope` into another file.
|
2021-12-14 18:49:49 +00:00
|
|
|
pub fn extend_scope_to_file<'ll>(
|
2018-07-04 13:36:49 +00:00
|
|
|
cx: &CodegenCx<'ll, '_>,
|
|
|
|
scope_metadata: &'ll DIScope,
|
2020-02-10 01:03:24 +00:00
|
|
|
file: &SourceFile,
|
2018-07-04 13:36:49 +00:00
|
|
|
) -> &'ll DILexicalBlock {
|
2020-02-10 01:03:24 +00:00
|
|
|
let file_metadata = file_metadata(cx, file);
|
2019-12-24 22:38:22 +00:00
|
|
|
unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlockFile(DIB(cx), scope_metadata, file_metadata) }
|
2016-08-26 16:23:42 +00:00
|
|
|
}
|
2022-03-03 10:15:25 +00:00
|
|
|
|
|
|
|
pub fn tuple_field_name(field_index: usize) -> Cow<'static, str> {
|
|
|
|
const TUPLE_FIELD_NAMES: [&'static str; 16] = [
|
|
|
|
"__0", "__1", "__2", "__3", "__4", "__5", "__6", "__7", "__8", "__9", "__10", "__11",
|
|
|
|
"__12", "__13", "__14", "__15",
|
|
|
|
];
|
|
|
|
TUPLE_FIELD_NAMES
|
|
|
|
.get(field_index)
|
|
|
|
.map(|s| Cow::from(*s))
|
|
|
|
.unwrap_or_else(|| Cow::from(format!("__{}", field_index)))
|
|
|
|
}
|