rust/compiler/rustc_codegen_gcc/src/debuginfo.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

316 lines
11 KiB
Rust
Raw Normal View History

2022-10-01 21:10:36 +00:00
use std::ops::Range;
use gccjit::{Location, RValue};
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoCodegenMethods};
use rustc_data_structures::sync::Lrc;
use rustc_index::bit_set::BitSet;
use rustc_index::{Idx, IndexVec};
use rustc_middle::mir::{self, Body, SourceScope};
use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
use rustc_session::config::DebugInfo;
use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol};
2022-10-01 21:10:36 +00:00
use rustc_target::abi::Size;
2020-05-10 14:54:30 +00:00
use rustc_target::abi::call::FnAbi;
use crate::builder::Builder;
use crate::context::CodegenCx;
pub(super) const UNKNOWN_LINE_NUMBER: u32 = 0;
pub(super) const UNKNOWN_COLUMN_NUMBER: u32 = 0;
2020-05-10 14:54:30 +00:00
impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
// FIXME(eddyb) find a common convention for all of the debuginfo-related
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
2022-10-01 21:10:36 +00:00
fn dbg_var_addr(
&mut self,
_dbg_var: Self::DIVariable,
_dbg_loc: Self::DILocation,
2022-10-01 21:10:36 +00:00
_variable_alloca: Self::Value,
_direct_offset: Size,
_indirect_offsets: &[Size],
_fragment: Option<Range<Size>>,
) {
// FIXME(tempdragon): Not sure if this is correct, probably wrong but still keep it here.
#[cfg(feature = "master")]
_variable_alloca.set_location(_dbg_loc);
2020-05-10 14:54:30 +00:00
}
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
2021-08-15 12:28:46 +00:00
// TODO(antoyo): insert reference to gdb debug scripts section global.
2020-05-10 14:54:30 +00:00
}
/// FIXME(tempdragon): Currently, this function is not yet implemented. It seems that the
/// debug name and the mangled name should both be included in the LValues.
/// Besides, a function to get the rvalue type(m_is_lvalue) should also be included.
fn set_var_name(&mut self, _value: RValue<'gcc>, _name: &str) {}
fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation) {
self.location = Some(dbg_loc);
}
Don't leave debug locations for constants sitting on the builder indefinitely. Because constants are currently emitted *before* the prologue, leaving the debug location on the IRBuilder spills onto other instructions in the prologue and messes up both line numbers as well as the point LLVM chooses to be the prologue end. Example LLVM IR (irrelevant IR elided): Before: define internal { i64, i64 } @_ZN3tmp3Foo18var_return_opt_try17he02116165b0fc08cE(ptr align 8 %self) !dbg !347 { start: %self.dbg.spill = alloca [8 x i8], align 8 %_0 = alloca [16 x i8], align 8 %residual.dbg.spill = alloca [0 x i8], align 1 #dbg_declare(ptr %residual.dbg.spill, !353, !DIExpression(), !357) store ptr %self, ptr %self.dbg.spill, align 8, !dbg !357 #dbg_declare(ptr %self.dbg.spill, !350, !DIExpression(), !358) After: define internal { i64, i64 } @_ZN3tmp3Foo18var_return_opt_try17h00b17d08874ddd90E(ptr align 8 %self) !dbg !347 { start: %self.dbg.spill = alloca [8 x i8], align 8 %_0 = alloca [16 x i8], align 8 %residual.dbg.spill = alloca [0 x i8], align 1 #dbg_declare(ptr %residual.dbg.spill, !353, !DIExpression(), !357) store ptr %self, ptr %self.dbg.spill, align 8 #dbg_declare(ptr %self.dbg.spill, !350, !DIExpression(), !358) Note in particular how !357 from %residual.dbg.spill's dbg_declare no longer falls through onto the store to %self.dbg.spill. This fixes argument values at entry when the constant is a ZST (e.g. <Option as Try>::Residual). This fixes #130003 (but note that it does *not* fix issues with argument values and non-ZST constants, which emit their own stores that have debug info on them, like #128945).
2024-09-06 19:39:11 +00:00
fn clear_dbg_loc(&mut self) {
self.location = None;
}
}
/// Generate the `debug_context` in an MIR Body.
2024-09-02 05:54:55 +00:00
/// # Source of Origin
/// Copied from `create_scope_map.rs` of rustc_codegen_llvm
fn compute_mir_scopes<'gcc, 'tcx>(
cx: &CodegenCx<'gcc, 'tcx>,
instance: Instance<'tcx>,
mir: &Body<'tcx>,
debug_context: &mut FunctionDebugContext<'tcx, (), Location<'gcc>>,
) {
// Find all scopes with variables defined in them.
let variables = if cx.sess().opts.debuginfo == DebugInfo::Full {
let mut vars = BitSet::new_empty(mir.source_scopes.len());
// FIXME(eddyb) take into account that arguments always have debuginfo,
// irrespective of their name (assuming full debuginfo is enabled).
// NOTE(eddyb) actually, on second thought, those are always in the
// function scope, which always exists.
for var_debug_info in &mir.var_debug_info {
vars.insert(var_debug_info.source_info.scope);
}
Some(vars)
} else {
// Nothing to emit, of course.
None
};
let mut instantiated = BitSet::new_empty(mir.source_scopes.len());
// Instantiate all scopes.
for idx in 0..mir.source_scopes.len() {
let scope = SourceScope::new(idx);
make_mir_scope(cx, instance, mir, &variables, debug_context, &mut instantiated, scope);
}
assert!(instantiated.count() == mir.source_scopes.len());
}
/// Update the `debug_context`, adding new scope to it,
/// if it's not added as is denoted in `instantiated`.
///
2024-09-02 05:54:55 +00:00
/// # Source of Origin
/// Copied from `create_scope_map.rs` of rustc_codegen_llvm
/// FIXME(tempdragon/?): Add Scope Support Here.
fn make_mir_scope<'gcc, 'tcx>(
cx: &CodegenCx<'gcc, 'tcx>,
_instance: Instance<'tcx>,
mir: &Body<'tcx>,
variables: &Option<BitSet<SourceScope>>,
debug_context: &mut FunctionDebugContext<'tcx, (), Location<'gcc>>,
instantiated: &mut BitSet<SourceScope>,
scope: SourceScope,
) {
if instantiated.contains(scope) {
return;
}
let scope_data = &mir.source_scopes[scope];
let parent_scope = if let Some(parent) = scope_data.parent_scope {
make_mir_scope(cx, _instance, mir, variables, debug_context, instantiated, parent);
debug_context.scopes[parent]
} else {
// The root is the function itself.
let file = cx.sess().source_map().lookup_source_file(mir.span.lo());
debug_context.scopes[scope] = DebugScope {
file_start_pos: file.start_pos,
file_end_pos: file.end_position(),
..debug_context.scopes[scope]
};
instantiated.insert(scope);
return;
};
if let Some(ref vars) = *variables {
if !vars.contains(scope) && scope_data.inlined.is_none() {
// Do not create a DIScope if there are no variables defined in this
// MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
debug_context.scopes[scope] = parent_scope;
instantiated.insert(scope);
return;
}
2020-05-10 14:54:30 +00:00
}
let loc = cx.lookup_debug_loc(scope_data.span.lo());
// FIXME(tempdragon): Add the scope related code here if the scope is supported.
let dbg_scope = ();
let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
// FIXME(eddyb) this doesn't account for the macro-related
// `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does.
// TODO(tempdragon): Add scope support and then revert to cg_llvm version of this closure
// NOTE: These variables passed () here.
// Changed to comply to clippy.
/* let callsite_scope = */
parent_scope.adjust_dbg_scope_for_span(cx, callsite_span);
cx.dbg_loc(/* callsite_scope */ (), parent_scope.inlined_at, callsite_span)
});
let p_inlined_at = parent_scope.inlined_at;
// TODO(tempdragon): dbg_scope: Add support for scope extension here.
inlined_at.or(p_inlined_at);
debug_context.scopes[scope] = DebugScope {
dbg_scope,
inlined_at,
file_start_pos: loc.file.start_pos,
file_end_pos: loc.file.end_position(),
};
instantiated.insert(scope);
}
/// A source code location used to generate debug information.
// FIXME(eddyb) rename this to better indicate it's a duplicate of
// `rustc_span::Loc` rather than `DILocation`, perhaps by making
// `lookup_char_pos` return the right information instead.
pub struct DebugLoc {
/// Information about the original source file.
pub file: Lrc<SourceFile>,
/// The (1-based) line number.
pub line: u32,
/// The (1-based) column number.
pub col: u32,
}
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
/// Looks up debug source information about a `BytePos`.
// FIXME(eddyb) rename this to better indicate it's a duplicate of
// `lookup_char_pos` rather than `dbg_loc`, perhaps by making
// `lookup_char_pos` return the right information instead.
// Source of Origin: cg_llvm
pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
Ok(SourceFileAndLine { sf: file, line }) => {
let line_pos = file.lines()[line];
// Use 1-based indexing.
let line = (line + 1) as u32;
let col = (file.relative_position(pos) - line_pos).to_u32() + 1;
(file, line, col)
}
Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER),
};
// For MSVC, omit the column number.
// Otherwise, emit it. This mimics clang behaviour.
// See discussion in https://github.com/rust-lang/rust/issues/42921
if self.sess().target.is_like_msvc {
DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER }
} else {
DebugLoc { file, line, col }
}
2020-05-10 14:54:30 +00:00
}
}
impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
2022-10-01 21:10:36 +00:00
fn create_vtable_debuginfo(
&self,
_ty: Ty<'tcx>,
_trait_ref: Option<PolyExistentialTraitRef<'tcx>>,
_vtable: Self::Value,
) {
2021-08-15 12:28:46 +00:00
// TODO(antoyo)
2020-05-10 14:54:30 +00:00
}
2022-10-01 21:10:36 +00:00
fn create_function_debug_context(
&self,
instance: Instance<'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
llfn: RValue<'gcc>,
mir: &mir::Body<'tcx>,
) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>> {
if self.sess().opts.debuginfo == DebugInfo::None {
return None;
}
// Initialize fn debug context (including scopes).
let empty_scope = DebugScope {
dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
inlined_at: None,
file_start_pos: BytePos(0),
file_end_pos: BytePos(0),
};
let mut fn_debug_context = FunctionDebugContext {
scopes: IndexVec::from_elem(empty_scope, mir.source_scopes.as_slice()),
inlined_function_scopes: Default::default(),
};
// Fill in all the scopes, with the information from the MIR body.
compute_mir_scopes(self, instance, mir, &mut fn_debug_context);
Some(fn_debug_context)
2020-05-10 14:54:30 +00:00
}
2022-10-01 21:10:36 +00:00
fn extend_scope_to_file(
&self,
_scope_metadata: Self::DIScope,
_file: &SourceFile,
) -> Self::DIScope {
// TODO(antoyo): implement.
2020-05-10 14:54:30 +00:00
}
fn debuginfo_finalize(&self) {
self.context.set_debug_info(true)
2020-05-10 14:54:30 +00:00
}
2022-10-01 21:10:36 +00:00
fn create_dbg_var(
&self,
_variable_name: Symbol,
_variable_type: Ty<'tcx>,
_scope_metadata: Self::DIScope,
_variable_kind: VariableKind,
_span: Span,
) -> Self::DIVariable {
2020-05-10 14:54:30 +00:00
}
2022-10-01 21:10:36 +00:00
fn dbg_scope_fn(
&self,
_instance: Instance<'tcx>,
_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
_maybe_definition_llfn: Option<RValue<'gcc>>,
) -> Self::DIScope {
// TODO(antoyo): implement.
2020-05-10 14:54:30 +00:00
}
2022-10-01 21:10:36 +00:00
fn dbg_loc(
&self,
_scope: Self::DIScope,
_inlined_at: Option<Self::DILocation>,
span: Span,
2022-10-01 21:10:36 +00:00
) -> Self::DILocation {
let pos = span.lo();
let DebugLoc { file, line, col } = self.lookup_debug_loc(pos);
let loc = match file.name {
rustc_span::FileName::Real(ref name) => match *name {
rustc_span::RealFileName::LocalPath(ref name) => {
if let Some(name) = name.to_str() {
self.context.new_location(name, line as i32, col as i32)
} else {
Location::null()
}
}
rustc_span::RealFileName::Remapped {
ref local_path,
virtual_name: ref _unused,
} => {
if let Some(name) = local_path.as_ref() {
if let Some(name) = name.to_str() {
self.context.new_location(name, line as i32, col as i32)
} else {
Location::null()
}
} else {
Location::null()
}
}
},
_ => Location::null(),
};
loc
2020-05-10 14:54:30 +00:00
}
}