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 } ;
33use 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 } ;
57use 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 } ;
710use rustc_target:: abi:: call:: FnAbi ;
811use rustc_target:: abi:: Size ;
12+ use rustc_data_structures:: sync:: Lrc ;
13+ use crate :: rustc_index:: Idx ;
914use std:: ops:: Range ;
1015
1116use crate :: builder:: Builder ;
1217use crate :: context:: CodegenCx ;
1318
19+ pub ( super ) const UNKNOWN_LINE_NUMBER : u32 = 0 ;
20+ pub ( super ) const UNKNOWN_COLUMN_NUMBER : u32 = 0 ;
21+
1422impl < ' 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