diff options
Diffstat (limited to 'compiler/rustc_codegen_gcc/src/debuginfo.rs')
| -rw-r--r-- | compiler/rustc_codegen_gcc/src/debuginfo.rs | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs new file mode 100644 index 00000000000..55e01687400 --- /dev/null +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -0,0 +1,319 @@ +use std::ops::Range; +use std::sync::Arc; + +use gccjit::{Location, RValue}; +use rustc_abi::Size; +use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind}; +use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoCodegenMethods}; +use rustc_index::bit_set::DenseBitSet; +use rustc_index::{Idx, IndexVec}; +use rustc_middle::mir::{self, Body, SourceScope}; +use rustc_middle::ty::{ExistentialTraitRef, Instance, Ty}; +use rustc_session::config::DebugInfo; +use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol}; +use rustc_target::callconv::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; + +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.). + fn dbg_var_addr( + &mut self, + _dbg_var: Self::DIVariable, + _dbg_loc: Self::DILocation, + _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); + } + + fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) { + // TODO(antoyo): insert reference to gdb debug scripts section global. + } + + /// 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); + } + + fn clear_dbg_loc(&mut self) { + self.location = None; + } + + fn get_dbg_loc(&self) -> Option<Self::DILocation> { + self.location + } +} + +/// Generate the `debug_context` in an MIR Body. +/// # 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 = DenseBitSet::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 = DenseBitSet::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`. +/// +/// # 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<DenseBitSet<SourceScope>>, + debug_context: &mut FunctionDebugContext<'tcx, (), Location<'gcc>>, + instantiated: &mut DenseBitSet<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; + } + } + + 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: Arc<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 } + } + } +} + +impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { + fn create_vtable_debuginfo( + &self, + _ty: Ty<'tcx>, + _trait_ref: Option<ExistentialTraitRef<'tcx>>, + _vtable: Self::Value, + ) { + // 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<'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) + } + + fn extend_scope_to_file( + &self, + _scope_metadata: Self::DIScope, + _file: &SourceFile, + ) -> Self::DIScope { + // TODO(antoyo): implement. + } + + fn debuginfo_finalize(&self) { + self.context.set_debug_info(true) + } + + fn create_dbg_var( + &self, + _variable_name: Symbol, + _variable_type: Ty<'tcx>, + _scope_metadata: Self::DIScope, + _variable_kind: VariableKind, + _span: Span, + ) -> Self::DIVariable { + } + + 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. + } + + fn dbg_loc( + &self, + _scope: Self::DIScope, + _inlined_at: Option<Self::DILocation>, + span: Span, + ) -> 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 + } +} |
