@@ -8,11 +8,13 @@ mod unwind;
88use cranelift_codegen:: ir:: Endianness ;
99use cranelift_codegen:: isa:: TargetIsa ;
1010use gimli:: write:: {
11- Address , AttributeValue , DwarfUnit , FileId , LineProgram , LineString , Range , RangeList ,
12- UnitEntryId ,
11+ Address , AttributeValue , DwarfUnit , Expression , FileId , LineProgram , LineString , Range ,
12+ RangeList , UnitEntryId ,
1313} ;
14- use gimli:: { Encoding , Format , LineEncoding , RunTimeEndian } ;
14+ use gimli:: { AArch64 , Encoding , Format , LineEncoding , Register , RiscV , RunTimeEndian , X86_64 } ;
1515use indexmap:: IndexSet ;
16+ use rustc_codegen_ssa:: debuginfo:: type_names;
17+ use rustc_hir:: def_id:: DefIdMap ;
1618use rustc_session:: Session ;
1719
1820pub ( crate ) use self :: emit:: { DebugReloc , DebugRelocName } ;
@@ -28,6 +30,8 @@ pub(crate) struct DebugContext {
2830
2931 dwarf : DwarfUnit ,
3032 unit_range_list : RangeList ,
33+ stack_pointer_register : Register ,
34+ namespace_map : DefIdMap < UnitEntryId > ,
3135
3236 should_remap_filepaths : bool ,
3337}
@@ -39,7 +43,7 @@ pub(crate) struct FunctionDebugContext {
3943}
4044
4145impl DebugContext {
42- pub ( crate ) fn new ( tcx : TyCtxt < ' _ > , isa : & dyn TargetIsa ) -> Self {
46+ pub ( crate ) fn new ( tcx : TyCtxt < ' _ > , isa : & dyn TargetIsa , cgu_name : & str ) -> Self {
4347 let encoding = Encoding {
4448 format : Format :: Dwarf32 ,
4549 // FIXME this should be configurable
@@ -60,6 +64,15 @@ impl DebugContext {
6064 Endianness :: Big => RunTimeEndian :: Big ,
6165 } ;
6266
67+ let stack_pointer_register = match isa. triple ( ) . architecture {
68+ target_lexicon:: Architecture :: Aarch64 ( _) => AArch64 :: SP ,
69+ target_lexicon:: Architecture :: Riscv64 ( _) => RiscV :: SP ,
70+ target_lexicon:: Architecture :: X86_64 | target_lexicon:: Architecture :: X86_64h => {
71+ X86_64 :: RSP
72+ }
73+ _ => Register ( u16:: MAX ) ,
74+ } ;
75+
6376 let mut dwarf = DwarfUnit :: new ( encoding) ;
6477
6578 let should_remap_filepaths = tcx. sess . should_prefer_remapped_for_codegen ( ) ;
@@ -95,14 +108,20 @@ impl DebugContext {
95108 dwarf. unit . line_program = line_program;
96109
97110 {
98- let name = dwarf. strings . add ( name) ;
111+ let name = dwarf. strings . add ( format ! ( "{ name}/@/{cgu_name}" ) ) ;
99112 let comp_dir = dwarf. strings . add ( comp_dir) ;
100113
101114 let root = dwarf. unit . root ( ) ;
102115 let root = dwarf. unit . get_mut ( root) ;
103116 root. set ( gimli:: DW_AT_producer , AttributeValue :: StringRef ( dwarf. strings . add ( producer) ) ) ;
104117 root. set ( gimli:: DW_AT_language , AttributeValue :: Language ( gimli:: DW_LANG_Rust ) ) ;
105118 root. set ( gimli:: DW_AT_name , AttributeValue :: StringRef ( name) ) ;
119+
120+ // This will be replaced when emitting the debuginfo. It is only
121+ // defined here to ensure that the order of the attributes matches
122+ // rustc.
123+ root. set ( gimli:: DW_AT_stmt_list , AttributeValue :: Udata ( 0 ) ) ;
124+
106125 root. set ( gimli:: DW_AT_comp_dir , AttributeValue :: StringRef ( comp_dir) ) ;
107126 root. set ( gimli:: DW_AT_low_pc , AttributeValue :: Address ( Address :: Constant ( 0 ) ) ) ;
108127 }
@@ -111,33 +130,99 @@ impl DebugContext {
111130 endian,
112131 dwarf,
113132 unit_range_list : RangeList ( Vec :: new ( ) ) ,
133+ stack_pointer_register,
134+ namespace_map : DefIdMap :: default ( ) ,
114135 should_remap_filepaths,
115136 }
116137 }
117138
118- pub ( crate ) fn define_function (
139+ fn item_namespace ( & mut self , tcx : TyCtxt < ' _ > , def_id : DefId ) -> UnitEntryId {
140+ if let Some ( & scope) = self . namespace_map . get ( & def_id) {
141+ return scope;
142+ }
143+
144+ let def_key = tcx. def_key ( def_id) ;
145+ let parent_scope = def_key
146+ . parent
147+ . map ( |parent| self . item_namespace ( tcx, DefId { krate : def_id. krate , index : parent } ) )
148+ . unwrap_or ( self . dwarf . unit . root ( ) ) ;
149+
150+ let namespace_name = {
151+ let mut output = String :: new ( ) ;
152+ type_names:: push_item_name ( tcx, def_id, false , & mut output) ;
153+ output
154+ } ;
155+ let namespace_name_id = self . dwarf . strings . add ( namespace_name) ;
156+
157+ let scope = self . dwarf . unit . add ( parent_scope, gimli:: DW_TAG_namespace ) ;
158+ let scope_entry = self . dwarf . unit . get_mut ( scope) ;
159+ scope_entry. set ( gimli:: DW_AT_name , AttributeValue :: StringRef ( namespace_name_id) ) ;
160+
161+ self . namespace_map . insert ( def_id, scope) ;
162+ scope
163+ }
164+
165+ pub ( crate ) fn define_function < ' tcx > (
119166 & mut self ,
120- tcx : TyCtxt < ' _ > ,
121- name : & str ,
167+ tcx : TyCtxt < ' tcx > ,
168+ instance : Instance < ' tcx > ,
169+ linkage_name : & str ,
122170 function_span : Span ,
123171 ) -> FunctionDebugContext {
124172 let ( file, line, column) = DebugContext :: get_span_loc ( tcx, function_span, function_span) ;
125173
126174 let file_id = self . add_source_file ( & file) ;
127175
128176 // FIXME: add to appropriate scope instead of root
129- let scope = self . dwarf . unit . root ( ) ;
177+ let scope = self . item_namespace ( tcx, tcx. parent ( instance. def_id ( ) ) ) ;
178+
179+ let mut name = String :: new ( ) ;
180+ type_names:: push_item_name ( tcx, instance. def_id ( ) , false , & mut name) ;
181+
182+ // Find the enclosing function, in case this is a closure.
183+ let enclosing_fn_def_id = tcx. typeck_root_def_id ( instance. def_id ( ) ) ;
184+
185+ // We look up the generics of the enclosing function and truncate the args
186+ // to their length in order to cut off extra stuff that might be in there for
187+ // closures or coroutines.
188+ let generics = tcx. generics_of ( enclosing_fn_def_id) ;
189+ let args = instance. args . truncate_to ( tcx, generics) ;
190+
191+ type_names:: push_generic_params (
192+ tcx,
193+ tcx. normalize_erasing_regions ( ty:: ParamEnv :: reveal_all ( ) , args) ,
194+ enclosing_fn_def_id,
195+ & mut name,
196+ ) ;
130197
131198 let entry_id = self . dwarf . unit . add ( scope, gimli:: DW_TAG_subprogram ) ;
132199 let entry = self . dwarf . unit . get_mut ( entry_id) ;
200+ let linkage_name_id =
201+ if name != linkage_name { Some ( self . dwarf . strings . add ( linkage_name) ) } else { None } ;
133202 let name_id = self . dwarf . strings . add ( name) ;
203+
204+ // These will be replaced in FunctionDebugContext::finalize. They are
205+ // only defined here to ensure that the order of the attributes matches
206+ // rustc.
207+ entry. set ( gimli:: DW_AT_low_pc , AttributeValue :: Udata ( 0 ) ) ;
208+ entry. set ( gimli:: DW_AT_high_pc , AttributeValue :: Udata ( 0 ) ) ;
209+
210+ let mut frame_base_expr = Expression :: new ( ) ;
211+ frame_base_expr. op_reg ( self . stack_pointer_register ) ;
212+ entry. set ( gimli:: DW_AT_frame_base , AttributeValue :: Exprloc ( frame_base_expr) ) ;
213+
214+ if let Some ( linkage_name_id) = linkage_name_id {
215+ entry. set ( gimli:: DW_AT_linkage_name , AttributeValue :: StringRef ( linkage_name_id) ) ;
216+ }
134217 // Gdb requires DW_AT_name. Otherwise the DW_TAG_subprogram is skipped.
135218 entry. set ( gimli:: DW_AT_name , AttributeValue :: StringRef ( name_id) ) ;
136- entry. set ( gimli:: DW_AT_linkage_name , AttributeValue :: StringRef ( name_id) ) ;
137219
138220 entry. set ( gimli:: DW_AT_decl_file , AttributeValue :: FileIndex ( Some ( file_id) ) ) ;
139221 entry. set ( gimli:: DW_AT_decl_line , AttributeValue :: Udata ( line) ) ;
140- entry. set ( gimli:: DW_AT_decl_column , AttributeValue :: Udata ( column) ) ;
222+
223+ if tcx. is_reachable_non_generic ( instance. def_id ( ) ) {
224+ entry. set ( gimli:: DW_AT_external , AttributeValue :: FlagPresent ) ;
225+ }
141226
142227 FunctionDebugContext {
143228 entry_id,
0 commit comments