@@ -8,11 +8,13 @@ mod unwind;
8
8
use cranelift_codegen:: ir:: Endianness ;
9
9
use cranelift_codegen:: isa:: TargetIsa ;
10
10
use 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 ,
13
13
} ;
14
- use gimli:: { Encoding , Format , LineEncoding , RunTimeEndian } ;
14
+ use gimli:: { AArch64 , Encoding , Format , LineEncoding , Register , RiscV , RunTimeEndian , X86_64 } ;
15
15
use indexmap:: IndexSet ;
16
+ use rustc_codegen_ssa:: debuginfo:: type_names;
17
+ use rustc_hir:: def_id:: DefIdMap ;
16
18
use rustc_session:: Session ;
17
19
18
20
pub ( crate ) use self :: emit:: { DebugReloc , DebugRelocName } ;
@@ -28,6 +30,8 @@ pub(crate) struct DebugContext {
28
30
29
31
dwarf : DwarfUnit ,
30
32
unit_range_list : RangeList ,
33
+ stack_pointer_register : Register ,
34
+ namespace_map : DefIdMap < UnitEntryId > ,
31
35
32
36
should_remap_filepaths : bool ,
33
37
}
@@ -39,7 +43,7 @@ pub(crate) struct FunctionDebugContext {
39
43
}
40
44
41
45
impl 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 {
43
47
let encoding = Encoding {
44
48
format : Format :: Dwarf32 ,
45
49
// FIXME this should be configurable
@@ -60,6 +64,15 @@ impl DebugContext {
60
64
Endianness :: Big => RunTimeEndian :: Big ,
61
65
} ;
62
66
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
+
63
76
let mut dwarf = DwarfUnit :: new ( encoding) ;
64
77
65
78
let should_remap_filepaths = tcx. sess . should_prefer_remapped_for_codegen ( ) ;
@@ -95,14 +108,20 @@ impl DebugContext {
95
108
dwarf. unit . line_program = line_program;
96
109
97
110
{
98
- let name = dwarf. strings . add ( name) ;
111
+ let name = dwarf. strings . add ( format ! ( "{ name}/@/{cgu_name}" ) ) ;
99
112
let comp_dir = dwarf. strings . add ( comp_dir) ;
100
113
101
114
let root = dwarf. unit . root ( ) ;
102
115
let root = dwarf. unit . get_mut ( root) ;
103
116
root. set ( gimli:: DW_AT_producer , AttributeValue :: StringRef ( dwarf. strings . add ( producer) ) ) ;
104
117
root. set ( gimli:: DW_AT_language , AttributeValue :: Language ( gimli:: DW_LANG_Rust ) ) ;
105
118
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
+
106
125
root. set ( gimli:: DW_AT_comp_dir , AttributeValue :: StringRef ( comp_dir) ) ;
107
126
root. set ( gimli:: DW_AT_low_pc , AttributeValue :: Address ( Address :: Constant ( 0 ) ) ) ;
108
127
}
@@ -111,33 +130,99 @@ impl DebugContext {
111
130
endian,
112
131
dwarf,
113
132
unit_range_list : RangeList ( Vec :: new ( ) ) ,
133
+ stack_pointer_register,
134
+ namespace_map : DefIdMap :: default ( ) ,
114
135
should_remap_filepaths,
115
136
}
116
137
}
117
138
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 > (
119
166
& mut self ,
120
- tcx : TyCtxt < ' _ > ,
121
- name : & str ,
167
+ tcx : TyCtxt < ' tcx > ,
168
+ instance : Instance < ' tcx > ,
169
+ linkage_name : & str ,
122
170
function_span : Span ,
123
171
) -> FunctionDebugContext {
124
172
let ( file, line, column) = DebugContext :: get_span_loc ( tcx, function_span, function_span) ;
125
173
126
174
let file_id = self . add_source_file ( & file) ;
127
175
128
176
// 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
+ ) ;
130
197
131
198
let entry_id = self . dwarf . unit . add ( scope, gimli:: DW_TAG_subprogram ) ;
132
199
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 } ;
133
202
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
+ }
134
217
// Gdb requires DW_AT_name. Otherwise the DW_TAG_subprogram is skipped.
135
218
entry. set ( gimli:: DW_AT_name , AttributeValue :: StringRef ( name_id) ) ;
136
- entry. set ( gimli:: DW_AT_linkage_name , AttributeValue :: StringRef ( name_id) ) ;
137
219
138
220
entry. set ( gimli:: DW_AT_decl_file , AttributeValue :: FileIndex ( Some ( file_id) ) ) ;
139
221
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
+ }
141
226
142
227
FunctionDebugContext {
143
228
entry_id,
0 commit comments