Skip to content

feat(debuginfo): Add support for debuginfo, without scope support #455

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion libgccjit.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
d24c8dae3
cf9554126
2 changes: 0 additions & 2 deletions src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,12 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock
if env::var("CG_GCCJIT_DUMP_GIMPLE").as_deref() == Ok("1") {
context.set_dump_initial_gimple(true);
}
context.set_debug_info(true);
if env::var("CG_GCCJIT_DUMP_EVERYTHING").as_deref() == Ok("1") {
context.set_dump_everything(true);
}
if env::var("CG_GCCJIT_KEEP_INTERMEDIATES").as_deref() == Ok("1") {
context.set_keep_intermediates(true);
}

if env::var("CG_GCCJIT_VERBOSE").as_deref() == Ok("1") {
context.add_driver_option("-v");
}
Expand Down
407 changes: 207 additions & 200 deletions src/builder.rs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/context.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::cell::{Cell, RefCell};

use gccjit::{Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, RValue, Type};
use gccjit::{Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, Location, RValue, Type};
use rustc_codegen_ssa::base::wants_msvc_seh;
use rustc_codegen_ssa::traits::{
BackendTypes,
Expand Down Expand Up @@ -345,7 +345,7 @@ impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
type Funclet = (); // TODO(antoyo)

type DIScope = (); // TODO(antoyo)
type DILocation = (); // TODO(antoyo)
type DILocation = Location<'gcc>;
type DIVariable = (); // TODO(antoyo)
}

Expand Down
252 changes: 231 additions & 21 deletions src/debuginfo.rs
Original file line number Diff line number Diff line change
@@ -1,41 +1,201 @@
use gccjit::RValue;
use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind};
use gccjit::{Location, RValue};
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods};
use rustc_middle::mir;
use rustc_index::bit_set::BitSet;
use rustc_index::IndexVec;
use rustc_middle::mir::{Body, self, SourceScope};
use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
use rustc_span::{SourceFile, Span, Symbol};
use rustc_session::config::DebugInfo;
use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol};
use rustc_target::abi::call::FnAbi;
use rustc_target::abi::Size;
use rustc_data_structures::sync::Lrc;
use crate::rustc_index::Idx;
use std::ops::Range;

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,
_scope_metadata: Self::DIScope,
_variable_alloca: Self::Value,
dbg_loc: Self::DILocation,
variable_alloca: Self::Value,
_direct_offset: Size,
_indirect_offsets: &[Size],
_fragment: Option<Range<Size>>,
) {
unimplemented!();
// 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) {
unimplemented!();
}

fn set_dbg_loc(&mut self, _dbg_loc: Self::DILocation) {
unimplemented!();
fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation) {
self.loc = Some(dbg_loc);
}
}

/// Generate the `debug_context` in an MIR Body.
/// # Souce 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`.
///
/// # Souce 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(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.
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 }
}
}
}

Expand All @@ -51,25 +211,44 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {

fn create_function_debug_context(
&self,
_instance: Instance<'tcx>,
_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
_llfn: RValue<'gcc>,
_mir: &mir::Body<'tcx>,
instance: Instance<'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
llfn: RValue<'gcc>,
mir: &mir::Body<'tcx>,
) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>> {
// TODO(antoyo)
None
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 {
unimplemented!();
// TODO(antoyo): implement.
}

fn debuginfo_finalize(&self) {
// TODO(antoyo)
self.context.set_debug_info(true)
}

fn create_dbg_var(
Expand All @@ -80,7 +259,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
_variable_kind: VariableKind,
_span: Span,
) -> Self::DIVariable {
unimplemented!();
()
}

fn dbg_scope_fn(
Expand All @@ -89,15 +268,46 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
_maybe_definition_llfn: Option<RValue<'gcc>>,
) -> Self::DIScope {
unimplemented!();
// TODO(antoyo): implement.
}

fn dbg_loc(
&self,
_scope: Self::DIScope,
_inlined_at: Option<Self::DILocation>,
_span: Span,
span: Span,
) -> Self::DILocation {
unimplemented!();
let pos = span.lo();
let DebugLoc{file, line, col} = self.lookup_debug_loc(pos);
let loc = match &file.name {
rustc_span::FileName::Real(name) => match name {
rustc_span::RealFileName::LocalPath(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 {
local_path,
virtual_name:_,
} => 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
}
}
Loading