Introduce composite debuginfo.
This commit is contained in:
parent
6d651a295e
commit
b550eabfa6
9 changed files with 199 additions and 16 deletions
|
@ -4,8 +4,9 @@ use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods};
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
|
use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
|
||||||
use rustc_span::{SourceFile, Span, Symbol};
|
use rustc_span::{SourceFile, Span, Symbol};
|
||||||
use rustc_target::abi::Size;
|
|
||||||
use rustc_target::abi::call::FnAbi;
|
use rustc_target::abi::call::FnAbi;
|
||||||
|
use rustc_target::abi::Size;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::builder::Builder;
|
use crate::builder::Builder;
|
||||||
use crate::context::CodegenCx;
|
use crate::context::CodegenCx;
|
||||||
|
@ -13,7 +14,15 @@ use crate::context::CodegenCx;
|
||||||
impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
|
impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
|
||||||
// FIXME(eddyb) find a common convention for all of the debuginfo-related
|
// FIXME(eddyb) find a common convention for all of the debuginfo-related
|
||||||
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
|
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
|
||||||
fn dbg_var_addr(&mut self, _dbg_var: Self::DIVariable, _scope_metadata: Self::DIScope, _variable_alloca: Self::Value, _direct_offset: Size, _indirect_offsets: &[Size]) {
|
fn dbg_var_addr(
|
||||||
|
&mut self,
|
||||||
|
_dbg_var: Self::DIVariable,
|
||||||
|
_scope_metadata: Self::DIScope,
|
||||||
|
_variable_alloca: Self::Value,
|
||||||
|
_direct_offset: Size,
|
||||||
|
_indirect_offsets: &[Size],
|
||||||
|
_fragment: Option<Range<Size>>,
|
||||||
|
) {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,16 +40,31 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||||
fn create_vtable_debuginfo(&self, _ty: Ty<'tcx>, _trait_ref: Option<PolyExistentialTraitRef<'tcx>>, _vtable: Self::Value) {
|
fn create_vtable_debuginfo(
|
||||||
|
&self,
|
||||||
|
_ty: Ty<'tcx>,
|
||||||
|
_trait_ref: Option<PolyExistentialTraitRef<'tcx>>,
|
||||||
|
_vtable: Self::Value,
|
||||||
|
) {
|
||||||
// TODO(antoyo)
|
// TODO(antoyo)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_function_debug_context(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _llfn: RValue<'gcc>, _mir: &mir::Body<'tcx>) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>> {
|
fn create_function_debug_context(
|
||||||
|
&self,
|
||||||
|
_instance: Instance<'tcx>,
|
||||||
|
_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||||
|
_llfn: RValue<'gcc>,
|
||||||
|
_mir: &mir::Body<'tcx>,
|
||||||
|
) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>> {
|
||||||
// TODO(antoyo)
|
// TODO(antoyo)
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extend_scope_to_file(&self, _scope_metadata: Self::DIScope, _file: &SourceFile) -> Self::DIScope {
|
fn extend_scope_to_file(
|
||||||
|
&self,
|
||||||
|
_scope_metadata: Self::DIScope,
|
||||||
|
_file: &SourceFile,
|
||||||
|
) -> Self::DIScope {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,15 +72,32 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
||||||
// TODO(antoyo)
|
// TODO(antoyo)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_dbg_var(&self, _variable_name: Symbol, _variable_type: Ty<'tcx>, _scope_metadata: Self::DIScope, _variable_kind: VariableKind, _span: Span) -> Self::DIVariable {
|
fn create_dbg_var(
|
||||||
|
&self,
|
||||||
|
_variable_name: Symbol,
|
||||||
|
_variable_type: Ty<'tcx>,
|
||||||
|
_scope_metadata: Self::DIScope,
|
||||||
|
_variable_kind: VariableKind,
|
||||||
|
_span: Span,
|
||||||
|
) -> Self::DIVariable {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dbg_scope_fn(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _maybe_definition_llfn: Option<RValue<'gcc>>) -> Self::DIScope {
|
fn dbg_scope_fn(
|
||||||
|
&self,
|
||||||
|
_instance: Instance<'tcx>,
|
||||||
|
_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||||
|
_maybe_definition_llfn: Option<RValue<'gcc>>,
|
||||||
|
) -> Self::DIScope {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dbg_loc(&self, _scope: Self::DIScope, _inlined_at: Option<Self::DILocation>, _span: Span) -> Self::DILocation {
|
fn dbg_loc(
|
||||||
|
&self,
|
||||||
|
_scope: Self::DIScope,
|
||||||
|
_inlined_at: Option<Self::DILocation>,
|
||||||
|
_span: Span,
|
||||||
|
) -> Self::DILocation {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ use smallvec::SmallVec;
|
||||||
use std::cell::OnceCell;
|
use std::cell::OnceCell;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
mod create_scope_map;
|
mod create_scope_map;
|
||||||
pub mod gdb;
|
pub mod gdb;
|
||||||
|
@ -163,12 +164,14 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
|
||||||
variable_alloca: Self::Value,
|
variable_alloca: Self::Value,
|
||||||
direct_offset: Size,
|
direct_offset: Size,
|
||||||
indirect_offsets: &[Size],
|
indirect_offsets: &[Size],
|
||||||
|
fragment: Option<Range<Size>>,
|
||||||
) {
|
) {
|
||||||
// Convert the direct and indirect offsets to address ops.
|
// Convert the direct and indirect offsets and fragment byte range to address ops.
|
||||||
// FIXME(eddyb) use `const`s instead of getting the values via FFI,
|
// FIXME(eddyb) use `const`s instead of getting the values via FFI,
|
||||||
// the values should match the ones in the DWARF standard anyway.
|
// the values should match the ones in the DWARF standard anyway.
|
||||||
let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
|
let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
|
||||||
let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
|
let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
|
||||||
|
let op_llvm_fragment = || unsafe { llvm::LLVMRustDIBuilderCreateOpLLVMFragment() };
|
||||||
let mut addr_ops = SmallVec::<[u64; 8]>::new();
|
let mut addr_ops = SmallVec::<[u64; 8]>::new();
|
||||||
|
|
||||||
if direct_offset.bytes() > 0 {
|
if direct_offset.bytes() > 0 {
|
||||||
|
@ -182,6 +185,13 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
|
||||||
addr_ops.push(offset.bytes() as u64);
|
addr_ops.push(offset.bytes() as u64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let Some(fragment) = fragment {
|
||||||
|
// `DW_OP_LLVM_fragment` takes as arguments the fragment's
|
||||||
|
// offset and size, both of them in bits.
|
||||||
|
addr_ops.push(op_llvm_fragment());
|
||||||
|
addr_ops.push(fragment.start.bits() as u64);
|
||||||
|
addr_ops.push((fragment.end - fragment.start).bits() as u64);
|
||||||
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`.
|
// FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`.
|
||||||
|
|
|
@ -2210,6 +2210,7 @@ extern "C" {
|
||||||
) -> &'a DILocation;
|
) -> &'a DILocation;
|
||||||
pub fn LLVMRustDIBuilderCreateOpDeref() -> u64;
|
pub fn LLVMRustDIBuilderCreateOpDeref() -> u64;
|
||||||
pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64;
|
pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64;
|
||||||
|
pub fn LLVMRustDIBuilderCreateOpLLVMFragment() -> u64;
|
||||||
|
|
||||||
#[allow(improper_ctypes)]
|
#[allow(improper_ctypes)]
|
||||||
pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
|
pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
|
||||||
|
|
|
@ -14,6 +14,8 @@ use super::operand::{OperandRef, OperandValue};
|
||||||
use super::place::PlaceRef;
|
use super::place::PlaceRef;
|
||||||
use super::{FunctionCx, LocalRef};
|
use super::{FunctionCx, LocalRef};
|
||||||
|
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
pub struct FunctionDebugContext<S, L> {
|
pub struct FunctionDebugContext<S, L> {
|
||||||
pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
|
pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
|
||||||
}
|
}
|
||||||
|
@ -25,7 +27,7 @@ pub enum VariableKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like `mir::VarDebugInfo`, but within a `mir::Local`.
|
/// Like `mir::VarDebugInfo`, but within a `mir::Local`.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Clone)]
|
||||||
pub struct PerLocalVarDebugInfo<'tcx, D> {
|
pub struct PerLocalVarDebugInfo<'tcx, D> {
|
||||||
pub name: Symbol,
|
pub name: Symbol,
|
||||||
pub source_info: mir::SourceInfo,
|
pub source_info: mir::SourceInfo,
|
||||||
|
@ -33,6 +35,10 @@ pub struct PerLocalVarDebugInfo<'tcx, D> {
|
||||||
/// `DIVariable` returned by `create_dbg_var`.
|
/// `DIVariable` returned by `create_dbg_var`.
|
||||||
pub dbg_var: Option<D>,
|
pub dbg_var: Option<D>,
|
||||||
|
|
||||||
|
/// Byte range in the `dbg_var` covered by this fragment,
|
||||||
|
/// if this is a fragment of a composite `VarDebugInfo`.
|
||||||
|
pub fragment: Option<Range<Size>>,
|
||||||
|
|
||||||
/// `.place.projection` from `mir::VarDebugInfo`.
|
/// `.place.projection` from `mir::VarDebugInfo`.
|
||||||
pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>,
|
pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>,
|
||||||
}
|
}
|
||||||
|
@ -145,7 +151,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
Some(per_local) => &per_local[local],
|
Some(per_local) => &per_local[local],
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
let whole_local_var = vars.iter().find(|var| var.projection.is_empty()).copied();
|
let whole_local_var = vars.iter().find(|var| var.projection.is_empty()).cloned();
|
||||||
let has_proj = || vars.iter().any(|var| !var.projection.is_empty());
|
let has_proj = || vars.iter().any(|var| !var.projection.is_empty());
|
||||||
|
|
||||||
let fallback_var = if self.mir.local_kind(local) == mir::LocalKind::Arg {
|
let fallback_var = if self.mir.local_kind(local) == mir::LocalKind::Arg {
|
||||||
|
@ -187,6 +193,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
name,
|
name,
|
||||||
source_info: decl.source_info,
|
source_info: decl.source_info,
|
||||||
dbg_var,
|
dbg_var,
|
||||||
|
fragment: None,
|
||||||
projection: ty::List::empty(),
|
projection: ty::List::empty(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -199,7 +206,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
let name = if bx.sess().fewer_names() {
|
let name = if bx.sess().fewer_names() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(match whole_local_var.or(fallback_var) {
|
Some(match whole_local_var.or(fallback_var.clone()) {
|
||||||
Some(var) if var.name != kw::Empty => var.name.to_string(),
|
Some(var) if var.name != kw::Empty => var.name.to_string(),
|
||||||
_ => format!("{:?}", local),
|
_ => format!("{:?}", local),
|
||||||
})
|
})
|
||||||
|
@ -249,7 +256,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
LocalRef::UnsizedPlace(_) => return,
|
LocalRef::UnsizedPlace(_) => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let vars = vars.iter().copied().chain(fallback_var);
|
let vars = vars.iter().cloned().chain(fallback_var);
|
||||||
|
|
||||||
for var in vars {
|
for var in vars {
|
||||||
let Some(dbg_var) = var.dbg_var else { continue };
|
let Some(dbg_var) = var.dbg_var else { continue };
|
||||||
|
@ -312,9 +319,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
bx.store(place.llval, alloca.llval, alloca.align);
|
bx.store(place.llval, alloca.llval, alloca.align);
|
||||||
|
|
||||||
// Point the debug info to `*alloca` for the current variable
|
// Point the debug info to `*alloca` for the current variable
|
||||||
bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO]);
|
bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO], None);
|
||||||
} else {
|
} else {
|
||||||
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets);
|
bx.dbg_var_addr(
|
||||||
|
dbg_var,
|
||||||
|
dbg_loc,
|
||||||
|
base.llval,
|
||||||
|
direct_offset,
|
||||||
|
&indirect_offsets,
|
||||||
|
None,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -382,6 +396,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
let ty = self.monomorphize(c.ty());
|
let ty = self.monomorphize(c.ty());
|
||||||
(ty, VariableKind::LocalVariable)
|
(ty, VariableKind::LocalVariable)
|
||||||
}
|
}
|
||||||
|
mir::VarDebugInfoContents::Composite { ty, fragments: _ } => {
|
||||||
|
let ty = self.monomorphize(ty);
|
||||||
|
(ty, VariableKind::LocalVariable)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
|
self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
|
||||||
|
@ -393,6 +411,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
name: var.name,
|
name: var.name,
|
||||||
source_info: var.source_info,
|
source_info: var.source_info,
|
||||||
dbg_var,
|
dbg_var,
|
||||||
|
fragment: None,
|
||||||
projection: place.projection,
|
projection: place.projection,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -407,10 +426,48 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
bx,
|
bx,
|
||||||
);
|
);
|
||||||
|
|
||||||
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[]);
|
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mir::VarDebugInfoContents::Composite { ty, ref fragments } => {
|
||||||
|
let var_ty = self.monomorphize(ty);
|
||||||
|
let var_layout = self.cx.layout_of(var_ty);
|
||||||
|
for fragment in fragments {
|
||||||
|
let mut fragment_start = Size::ZERO;
|
||||||
|
let mut fragment_layout = var_layout;
|
||||||
|
|
||||||
|
for elem in &fragment.projection {
|
||||||
|
match *elem {
|
||||||
|
mir::ProjectionElem::Field(field, _) => {
|
||||||
|
let i = field.index();
|
||||||
|
fragment_start += fragment_layout.fields.offset(i);
|
||||||
|
fragment_layout = fragment_layout.field(self.cx, i);
|
||||||
|
}
|
||||||
|
_ => span_bug!(
|
||||||
|
var.source_info.span,
|
||||||
|
"unsupported fragment projection `{:?}`",
|
||||||
|
elem,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let place = fragment.contents;
|
||||||
|
per_local[place.local].push(PerLocalVarDebugInfo {
|
||||||
|
name: var.name,
|
||||||
|
source_info: var.source_info,
|
||||||
|
dbg_var,
|
||||||
|
fragment: if fragment_layout.size == var_layout.size {
|
||||||
|
// Fragment covers entire variable, so as far as
|
||||||
|
// DWARF is concerned, it's not really a fragment.
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(fragment_start..fragment_start + fragment_layout.size)
|
||||||
|
},
|
||||||
|
projection: place.projection,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(per_local)
|
Some(per_local)
|
||||||
|
|
|
@ -6,6 +6,8 @@ use rustc_span::{SourceFile, Span, Symbol};
|
||||||
use rustc_target::abi::call::FnAbi;
|
use rustc_target::abi::call::FnAbi;
|
||||||
use rustc_target::abi::Size;
|
use rustc_target::abi::Size;
|
||||||
|
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
pub trait DebugInfoMethods<'tcx>: BackendTypes {
|
pub trait DebugInfoMethods<'tcx>: BackendTypes {
|
||||||
fn create_vtable_debuginfo(
|
fn create_vtable_debuginfo(
|
||||||
&self,
|
&self,
|
||||||
|
@ -72,6 +74,9 @@ pub trait DebugInfoBuilderMethods: BackendTypes {
|
||||||
direct_offset: Size,
|
direct_offset: Size,
|
||||||
// NB: each offset implies a deref (i.e. they're steps in a pointer chain).
|
// NB: each offset implies a deref (i.e. they're steps in a pointer chain).
|
||||||
indirect_offsets: &[Size],
|
indirect_offsets: &[Size],
|
||||||
|
// Byte range in the `dbg_var` covered by this fragment,
|
||||||
|
// if this is a fragment of a composite `DIVariable`.
|
||||||
|
fragment: Option<Range<Size>>,
|
||||||
);
|
);
|
||||||
fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation);
|
fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation);
|
||||||
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self);
|
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self);
|
||||||
|
|
|
@ -1111,6 +1111,10 @@ extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() {
|
||||||
return dwarf::DW_OP_plus_uconst;
|
return dwarf::DW_OP_plus_uconst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" int64_t LLVMRustDIBuilderCreateOpLLVMFragment() {
|
||||||
|
return dwarf::DW_OP_LLVM_fragment;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void LLVMRustWriteTypeToString(LLVMTypeRef Ty, RustStringRef Str) {
|
extern "C" void LLVMRustWriteTypeToString(LLVMTypeRef Ty, RustStringRef Str) {
|
||||||
RawRustStringOstream OS(Str);
|
RawRustStringOstream OS(Str);
|
||||||
unwrap<llvm::Type>(Ty)->print(OS);
|
unwrap<llvm::Type>(Ty)->print(OS);
|
||||||
|
|
|
@ -1071,6 +1071,18 @@ pub enum VarDebugInfoContents<'tcx> {
|
||||||
/// based on a `Local`, not a `Static`, and contains no indexing.
|
/// based on a `Local`, not a `Static`, and contains no indexing.
|
||||||
Place(Place<'tcx>),
|
Place(Place<'tcx>),
|
||||||
Const(Constant<'tcx>),
|
Const(Constant<'tcx>),
|
||||||
|
/// The user variable's data is split across several fragments,
|
||||||
|
/// each described by a `VarDebugInfoFragment`.
|
||||||
|
/// See DWARF 5's "2.6.1.2 Composite Location Descriptions"
|
||||||
|
/// and LLVM's `DW_OP_LLVM_fragment` for more details on
|
||||||
|
/// the underlying debuginfo feature this relies on.
|
||||||
|
Composite {
|
||||||
|
/// Type of the original user variable.
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
/// All the parts of the original user variable, which ended
|
||||||
|
/// up in disjoint places, due to optimizations.
|
||||||
|
fragments: Vec<VarDebugInfoFragment<'tcx>>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
|
impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
|
||||||
|
@ -1078,10 +1090,51 @@ impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
|
||||||
match self {
|
match self {
|
||||||
VarDebugInfoContents::Const(c) => write!(fmt, "{}", c),
|
VarDebugInfoContents::Const(c) => write!(fmt, "{}", c),
|
||||||
VarDebugInfoContents::Place(p) => write!(fmt, "{:?}", p),
|
VarDebugInfoContents::Place(p) => write!(fmt, "{:?}", p),
|
||||||
|
VarDebugInfoContents::Composite { ty, fragments } => {
|
||||||
|
write!(fmt, "{:?}{{ ", ty)?;
|
||||||
|
for f in fragments.iter() {
|
||||||
|
write!(fmt, "{:?}, ", f)?;
|
||||||
|
}
|
||||||
|
write!(fmt, "}}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
|
pub struct VarDebugInfoFragment<'tcx> {
|
||||||
|
/// Where in the composite user variable this fragment is,
|
||||||
|
/// represented as a "projection" into the composite variable.
|
||||||
|
/// At lower levels, this corresponds to a byte/bit range.
|
||||||
|
// NOTE(eddyb) there's an unenforced invariant that this contains
|
||||||
|
// only `Field`s, and not into `enum` variants or `union`s.
|
||||||
|
// FIXME(eddyb) support this for `enum`s by either using DWARF's
|
||||||
|
// more advanced control-flow features (unsupported by LLVM?)
|
||||||
|
// to match on the discriminant, or by using custom type debuginfo
|
||||||
|
// with non-overlapping variants for the composite variable.
|
||||||
|
pub projection: Vec<PlaceElem<'tcx>>,
|
||||||
|
|
||||||
|
/// Where the data for this fragment can be found.
|
||||||
|
// NOTE(eddyb) There's an unenforced invariant that this `Place` is
|
||||||
|
// contains no indexing (with a non-constant index).
|
||||||
|
pub contents: Place<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for VarDebugInfoFragment<'_> {
|
||||||
|
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
for elem in self.projection.iter() {
|
||||||
|
match elem {
|
||||||
|
ProjectionElem::Field(field, _) => {
|
||||||
|
write!(fmt, ".{:?}", field.index())?;
|
||||||
|
}
|
||||||
|
_ => bug!("unsupported fragment projection `{:?}`", elem),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(fmt, " => {:?}", self.contents)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Debug information pertaining to a user variable.
|
/// Debug information pertaining to a user variable.
|
||||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||||
pub struct VarDebugInfo<'tcx> {
|
pub struct VarDebugInfo<'tcx> {
|
||||||
|
|
|
@ -847,6 +847,17 @@ macro_rules! make_mir_visitor {
|
||||||
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
|
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
|
||||||
location
|
location
|
||||||
),
|
),
|
||||||
|
VarDebugInfoContents::Composite { ty, fragments } => {
|
||||||
|
// FIXME(eddyb) use a better `TyContext` here.
|
||||||
|
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
|
||||||
|
for VarDebugInfoFragment { projection: _, contents } in fragments {
|
||||||
|
self.visit_place(
|
||||||
|
contents,
|
||||||
|
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
|
||||||
|
location,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#![allow(rustc::potential_query_instability)]
|
#![allow(rustc::potential_query_instability)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
|
#![feature(drain_filter)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
#![feature(map_try_insert)]
|
#![feature(map_try_insert)]
|
||||||
#![feature(min_specialization)]
|
#![feature(min_specialization)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue