Skip to content

Commit 6ec5010

Browse files
authored
Merge pull request #455 from tempdragon/master
feat(debuginfo): Add support for debuginfo, without scope support
2 parents 64fc213 + 7c3565e commit 6ec5010

File tree

9 files changed

+605
-389
lines changed

9 files changed

+605
-389
lines changed

Cargo.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

libgccjit.version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
d24c8dae3
1+
cf9554126

src/base.rs

-2
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,12 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Lock
152152
if env::var("CG_GCCJIT_DUMP_GIMPLE").as_deref() == Ok("1") {
153153
context.set_dump_initial_gimple(true);
154154
}
155-
context.set_debug_info(true);
156155
if env::var("CG_GCCJIT_DUMP_EVERYTHING").as_deref() == Ok("1") {
157156
context.set_dump_everything(true);
158157
}
159158
if env::var("CG_GCCJIT_KEEP_INTERMEDIATES").as_deref() == Ok("1") {
160159
context.set_keep_intermediates(true);
161160
}
162-
163161
if env::var("CG_GCCJIT_VERBOSE").as_deref() == Ok("1") {
164162
context.add_driver_option("-v");
165163
}

src/builder.rs

+207-200
Large diffs are not rendered by default.

src/context.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::cell::{Cell, RefCell};
22

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

347347
type DIScope = (); // TODO(antoyo)
348-
type DILocation = (); // TODO(antoyo)
348+
type DILocation = Location<'gcc>;
349349
type DIVariable = (); // TODO(antoyo)
350350
}
351351

src/debuginfo.rs

+231-21
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,201 @@
1-
use gccjit::RValue;
2-
use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind};
1+
use gccjit::{Location, RValue};
2+
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
33
use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods};
4-
use rustc_middle::mir;
4+
use rustc_index::bit_set::BitSet;
5+
use rustc_index::IndexVec;
6+
use rustc_middle::mir::{Body, self, SourceScope};
57
use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
6-
use rustc_span::{SourceFile, Span, Symbol};
8+
use rustc_session::config::DebugInfo;
9+
use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span, Symbol};
710
use rustc_target::abi::call::FnAbi;
811
use rustc_target::abi::Size;
12+
use rustc_data_structures::sync::Lrc;
13+
use crate::rustc_index::Idx;
914
use std::ops::Range;
1015

1116
use crate::builder::Builder;
1217
use crate::context::CodegenCx;
1318

19+
pub(super) const UNKNOWN_LINE_NUMBER: u32 = 0;
20+
pub(super) const UNKNOWN_COLUMN_NUMBER: u32 = 0;
21+
1422
impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
1523
// FIXME(eddyb) find a common convention for all of the debuginfo-related
1624
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
1725
fn dbg_var_addr(
1826
&mut self,
1927
_dbg_var: Self::DIVariable,
20-
_scope_metadata: Self::DIScope,
21-
_variable_alloca: Self::Value,
28+
dbg_loc: Self::DILocation,
29+
variable_alloca: Self::Value,
2230
_direct_offset: Size,
2331
_indirect_offsets: &[Size],
2432
_fragment: Option<Range<Size>>,
2533
) {
26-
unimplemented!();
34+
// FIXME(tempdragon): Not sure if this is correct, probably wrong but still keep it here.
35+
#[cfg(feature = "master")]
36+
variable_alloca.set_location(dbg_loc);
2737
}
2838

2939
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
3040
// TODO(antoyo): insert reference to gdb debug scripts section global.
3141
}
3242

43+
/// FIXME(tempdragon): Currently, this function is not yet implemented. It seems that the
44+
/// debug name and the mangled name should both be included in the LValues.
45+
/// Besides, a function to get the rvalue type(m_is_lvalue) should also be included.
3346
fn set_var_name(&mut self, _value: RValue<'gcc>, _name: &str) {
34-
unimplemented!();
3547
}
3648

37-
fn set_dbg_loc(&mut self, _dbg_loc: Self::DILocation) {
38-
unimplemented!();
49+
fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation) {
50+
self.loc = Some(dbg_loc);
51+
}
52+
}
53+
54+
/// Generate the `debug_context` in an MIR Body.
55+
/// # Souce of Origin
56+
/// Copied from `create_scope_map.rs` of rustc_codegen_llvm
57+
fn compute_mir_scopes<'gcc, 'tcx>(
58+
cx: &CodegenCx<'gcc, 'tcx>,
59+
instance: Instance<'tcx>,
60+
mir: &Body<'tcx>,
61+
debug_context: &mut FunctionDebugContext<'tcx, (), Location<'gcc>>,
62+
) {
63+
// Find all scopes with variables defined in them.
64+
let variables = if cx.sess().opts.debuginfo == DebugInfo::Full {
65+
let mut vars = BitSet::new_empty(mir.source_scopes.len());
66+
// FIXME(eddyb) take into account that arguments always have debuginfo,
67+
// irrespective of their name (assuming full debuginfo is enabled).
68+
// NOTE(eddyb) actually, on second thought, those are always in the
69+
// function scope, which always exists.
70+
for var_debug_info in &mir.var_debug_info {
71+
vars.insert(var_debug_info.source_info.scope);
72+
}
73+
Some(vars)
74+
} else {
75+
// Nothing to emit, of course.
76+
None
77+
};
78+
let mut instantiated = BitSet::new_empty(mir.source_scopes.len());
79+
// Instantiate all scopes.
80+
for idx in 0..mir.source_scopes.len() {
81+
let scope = SourceScope::new(idx);
82+
make_mir_scope(cx, instance, mir, &variables, debug_context, &mut instantiated, scope);
83+
}
84+
assert!(instantiated.count() == mir.source_scopes.len());
85+
}
86+
87+
/// Update the `debug_context`, adding new scope to it,
88+
/// if it's not added as is denoted in `instantiated`.
89+
///
90+
/// # Souce of Origin
91+
/// Copied from `create_scope_map.rs` of rustc_codegen_llvm
92+
/// FIXME(tempdragon/?): Add Scope Support Here.
93+
fn make_mir_scope<'gcc, 'tcx>(
94+
cx: &CodegenCx<'gcc, 'tcx>,
95+
instance: Instance<'tcx>,
96+
mir: &Body<'tcx>,
97+
variables: &Option<BitSet<SourceScope>>,
98+
debug_context: &mut FunctionDebugContext<'tcx, (), Location<'gcc>>,
99+
instantiated: &mut BitSet<SourceScope>,
100+
scope: SourceScope,
101+
) {
102+
if instantiated.contains(scope) {
103+
return;
104+
}
105+
106+
let scope_data = &mir.source_scopes[scope];
107+
let parent_scope = if let Some(parent) = scope_data.parent_scope {
108+
make_mir_scope(cx, instance, mir, variables, debug_context, instantiated, parent);
109+
debug_context.scopes[parent]
110+
} else {
111+
// The root is the function itself.
112+
let file = cx.sess().source_map().lookup_source_file(mir.span.lo());
113+
debug_context.scopes[scope] = DebugScope {
114+
file_start_pos: file.start_pos,
115+
file_end_pos: file.end_position(),
116+
..debug_context.scopes[scope]
117+
};
118+
instantiated.insert(scope);
119+
return;
120+
};
121+
122+
if let Some(vars) = variables
123+
{
124+
if !vars.contains(scope)
125+
&& scope_data.inlined.is_none() {
126+
// Do not create a DIScope if there are no variables defined in this
127+
// MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
128+
debug_context.scopes[scope] = parent_scope;
129+
instantiated.insert(scope);
130+
return;
131+
}
132+
}
133+
134+
let loc = cx.lookup_debug_loc(scope_data.span.lo());
135+
136+
// FIXME(tempdragon): Add the scope related code here if the scope is supported.
137+
let dbg_scope = ();
138+
139+
let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
140+
// FIXME(eddyb) this doesn't account for the macro-related
141+
// `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does.
142+
let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span);
143+
cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span)
144+
});
145+
let p_inlined_at = parent_scope.inlined_at;
146+
// TODO(tempdragon): dbg_scope: Add support for scope extension here.
147+
inlined_at.or(p_inlined_at);
148+
149+
debug_context.scopes[scope] = DebugScope {
150+
dbg_scope,
151+
inlined_at,
152+
file_start_pos: loc.file.start_pos,
153+
file_end_pos: loc.file.end_position(),
154+
};
155+
instantiated.insert(scope);
156+
}
157+
158+
/// A source code location used to generate debug information.
159+
// FIXME(eddyb) rename this to better indicate it's a duplicate of
160+
// `rustc_span::Loc` rather than `DILocation`, perhaps by making
161+
// `lookup_char_pos` return the right information instead.
162+
pub struct DebugLoc {
163+
/// Information about the original source file.
164+
pub file: Lrc<SourceFile>,
165+
/// The (1-based) line number.
166+
pub line: u32,
167+
/// The (1-based) column number.
168+
pub col: u32,
169+
}
170+
171+
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
172+
/// Looks up debug source information about a `BytePos`.
173+
// FIXME(eddyb) rename this to better indicate it's a duplicate of
174+
// `lookup_char_pos` rather than `dbg_loc`, perhaps by making
175+
// `lookup_char_pos` return the right information instead.
176+
// Source of Origin: cg_llvm
177+
pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
178+
let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
179+
Ok(SourceFileAndLine { sf: file, line }) => {
180+
let line_pos = file.lines()[line];
181+
182+
// Use 1-based indexing.
183+
let line = (line + 1) as u32;
184+
let col = (file.relative_position(pos) - line_pos).to_u32() + 1;
185+
186+
(file, line, col)
187+
}
188+
Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER),
189+
};
190+
191+
// For MSVC, omit the column number.
192+
// Otherwise, emit it. This mimics clang behaviour.
193+
// See discussion in https://github.com/rust-lang/rust/issues/42921
194+
if self.sess().target.is_like_msvc {
195+
DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER }
196+
} else {
197+
DebugLoc { file, line, col }
198+
}
39199
}
40200
}
41201

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

52212
fn create_function_debug_context(
53213
&self,
54-
_instance: Instance<'tcx>,
55-
_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
56-
_llfn: RValue<'gcc>,
57-
_mir: &mir::Body<'tcx>,
214+
instance: Instance<'tcx>,
215+
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
216+
llfn: RValue<'gcc>,
217+
mir: &mir::Body<'tcx>,
58218
) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>> {
59219
// TODO(antoyo)
60-
None
220+
if self.sess().opts.debuginfo == DebugInfo::None {
221+
return None;
222+
}
223+
224+
// Initialize fn debug context (including scopes).
225+
let empty_scope = DebugScope {
226+
dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
227+
inlined_at: None,
228+
file_start_pos: BytePos(0),
229+
file_end_pos: BytePos(0),
230+
};
231+
let mut fn_debug_context = FunctionDebugContext {
232+
scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes.as_slice()),
233+
inlined_function_scopes: Default::default(),
234+
};
235+
236+
// Fill in all the scopes, with the information from the MIR body.
237+
compute_mir_scopes(self, instance, mir, &mut fn_debug_context);
238+
239+
Some(fn_debug_context)
61240
}
62241

63242
fn extend_scope_to_file(
64243
&self,
65244
_scope_metadata: Self::DIScope,
66245
_file: &SourceFile,
67246
) -> Self::DIScope {
68-
unimplemented!();
247+
// TODO(antoyo): implement.
69248
}
70249

71250
fn debuginfo_finalize(&self) {
72-
// TODO(antoyo)
251+
self.context.set_debug_info(true)
73252
}
74253

75254
fn create_dbg_var(
@@ -80,7 +259,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
80259
_variable_kind: VariableKind,
81260
_span: Span,
82261
) -> Self::DIVariable {
83-
unimplemented!();
262+
()
84263
}
85264

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

95274
fn dbg_loc(
96275
&self,
97276
_scope: Self::DIScope,
98277
_inlined_at: Option<Self::DILocation>,
99-
_span: Span,
278+
span: Span,
100279
) -> Self::DILocation {
101-
unimplemented!();
280+
let pos = span.lo();
281+
let DebugLoc{file, line, col} = self.lookup_debug_loc(pos);
282+
let loc = match &file.name {
283+
rustc_span::FileName::Real(name) => match name {
284+
rustc_span::RealFileName::LocalPath(name) => {
285+
if let Some(name) = name.to_str() {
286+
self.context
287+
.new_location(name, line as i32, col as i32)
288+
} else{
289+
Location::null()
290+
}
291+
}
292+
rustc_span::RealFileName::Remapped {
293+
local_path,
294+
virtual_name:_,
295+
} => if let Some(name) = local_path.as_ref() {
296+
if let Some(name) = name.to_str(){
297+
self.context.new_location(
298+
name,
299+
line as i32,
300+
col as i32,
301+
)
302+
} else {
303+
Location::null()
304+
}
305+
} else{
306+
Location::null()
307+
},
308+
},
309+
_ => Location::null(),
310+
};
311+
loc
102312
}
103313
}

0 commit comments

Comments
 (0)