]>
Commit | Line | Data |
---|---|---|
dfeec247 | 1 | use crate::traits::*; |
dfeec247 | 2 | use rustc_index::vec::IndexVec; |
3dfed10e | 3 | use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; |
ba9703b0 XL |
4 | use rustc_middle::mir; |
5 | use rustc_middle::ty; | |
c295e0f8 | 6 | use rustc_middle::ty::layout::LayoutOf; |
ba9703b0 | 7 | use rustc_session::config::DebugInfo; |
74b04a01 | 8 | use rustc_span::symbol::{kw, Symbol}; |
dfeec247 | 9 | use rustc_span::{BytePos, Span}; |
c295e0f8 | 10 | use rustc_target::abi::Abi; |
cdc7bbd5 | 11 | use rustc_target::abi::Size; |
e74abb32 | 12 | |
fc512014 | 13 | use super::operand::{OperandRef, OperandValue}; |
74b04a01 | 14 | use super::place::PlaceRef; |
dfeec247 | 15 | use super::{FunctionCx, LocalRef}; |
e74abb32 | 16 | |
29967ef6 XL |
17 | pub struct FunctionDebugContext<S, L> { |
18 | pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>, | |
e74abb32 XL |
19 | } |
20 | ||
21 | #[derive(Copy, Clone)] | |
22 | pub enum VariableKind { | |
23 | ArgumentVariable(usize /*index*/), | |
24 | LocalVariable, | |
25 | } | |
26 | ||
74b04a01 XL |
27 | /// Like `mir::VarDebugInfo`, but within a `mir::Local`. |
28 | #[derive(Copy, Clone)] | |
29 | pub struct PerLocalVarDebugInfo<'tcx, D> { | |
30 | pub name: Symbol, | |
31 | pub source_info: mir::SourceInfo, | |
32 | ||
33 | /// `DIVariable` returned by `create_dbg_var`. | |
34 | pub dbg_var: Option<D>, | |
35 | ||
36 | /// `.place.projection` from `mir::VarDebugInfo`. | |
37 | pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>, | |
38 | } | |
39 | ||
e74abb32 | 40 | #[derive(Clone, Copy, Debug)] |
29967ef6 XL |
41 | pub struct DebugScope<S, L> { |
42 | // FIXME(eddyb) this should never be `None`, after initialization. | |
43 | pub dbg_scope: Option<S>, | |
44 | ||
45 | /// Call site location, if this scope was inlined from another function. | |
46 | pub inlined_at: Option<L>, | |
47 | ||
e74abb32 XL |
48 | // Start and end offsets of the file to which this DIScope belongs. |
49 | // These are used to quickly determine whether some span refers to the same file. | |
50 | pub file_start_pos: BytePos, | |
51 | pub file_end_pos: BytePos, | |
52 | } | |
53 | ||
29967ef6 XL |
54 | impl<'tcx, S: Copy, L: Copy> DebugScope<S, L> { |
55 | /// DILocations inherit source file name from the parent DIScope. Due to macro expansions | |
56 | /// it may so happen that the current span belongs to a different file than the DIScope | |
57 | /// corresponding to span's containing source scope. If so, we need to create a DIScope | |
58 | /// "extension" into that file. | |
59 | pub fn adjust_dbg_scope_for_span<Cx: CodegenMethods<'tcx, DIScope = S, DILocation = L>>( | |
60 | &self, | |
61 | cx: &Cx, | |
62 | span: Span, | |
63 | ) -> S { | |
64 | // FIXME(eddyb) this should never be `None`. | |
65 | let dbg_scope = self | |
66 | .dbg_scope | |
67 | .unwrap_or_else(|| bug!("`dbg_scope` is only `None` during initialization")); | |
68 | ||
69 | let pos = span.lo(); | |
70 | if pos < self.file_start_pos || pos >= self.file_end_pos { | |
71 | let sm = cx.sess().source_map(); | |
72 | cx.extend_scope_to_file(dbg_scope, &sm.lookup_char_pos(pos).file) | |
73 | } else { | |
74 | dbg_scope | |
75 | } | |
e74abb32 XL |
76 | } |
77 | } | |
78 | ||
79 | impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { | |
74b04a01 | 80 | pub fn set_debug_loc(&self, bx: &mut Bx, source_info: mir::SourceInfo) { |
29967ef6 XL |
81 | bx.set_span(source_info.span); |
82 | if let Some(dbg_loc) = self.dbg_loc(source_info) { | |
83 | bx.set_dbg_loc(dbg_loc); | |
e74abb32 XL |
84 | } |
85 | } | |
86 | ||
29967ef6 XL |
87 | fn dbg_loc(&self, source_info: mir::SourceInfo) -> Option<Bx::DILocation> { |
88 | let (dbg_scope, inlined_at, span) = self.adjusted_span_and_dbg_scope(source_info)?; | |
89 | Some(self.cx.dbg_loc(dbg_scope, inlined_at, span)) | |
90 | } | |
91 | ||
92 | fn adjusted_span_and_dbg_scope( | |
93 | &self, | |
94 | source_info: mir::SourceInfo, | |
95 | ) -> Option<(Bx::DIScope, Option<Bx::DILocation>, Span)> { | |
96 | let span = self.adjust_span_for_debugging(source_info.span); | |
97 | let scope = &self.debug_context.as_ref()?.scopes[source_info.scope]; | |
98 | Some((scope.adjust_dbg_scope_for_span(self.cx, span), scope.inlined_at, span)) | |
99 | } | |
100 | ||
101 | /// In order to have a good line stepping behavior in debugger, we overwrite debug | |
102 | /// locations of macro expansions with that of the outermost expansion site | |
103 | /// (unless the crate is being compiled with `-Z debug-macros`). | |
104 | fn adjust_span_for_debugging(&self, mut span: Span) -> Span { | |
e74abb32 | 105 | // Bail out if debug info emission is not enabled. |
29967ef6 XL |
106 | if self.debug_context.is_none() { |
107 | return span; | |
e74abb32 XL |
108 | } |
109 | ||
29967ef6 | 110 | if span.from_expansion() && !self.cx.sess().opts.debugging_opts.debug_macros { |
e74abb32 XL |
111 | // Walk up the macro expansion chain until we reach a non-expanded span. |
112 | // We also stop at the function body level because no line stepping can occur | |
113 | // at the level above that. | |
e74abb32 | 114 | // Use span of the outermost expansion site, while keeping the original lexical scope. |
29967ef6 | 115 | span = rustc_span::hygiene::walk_chain(span, self.mir.span.ctxt()); |
e74abb32 | 116 | } |
e74abb32 | 117 | |
29967ef6 | 118 | span |
e74abb32 XL |
119 | } |
120 | ||
fc512014 XL |
121 | fn spill_operand_to_stack( |
122 | operand: &OperandRef<'tcx, Bx::Value>, | |
123 | name: Option<String>, | |
124 | bx: &mut Bx, | |
125 | ) -> PlaceRef<'tcx, Bx::Value> { | |
126 | // "Spill" the value onto the stack, for debuginfo, | |
127 | // without forcing non-debuginfo uses of the local | |
128 | // to also load from the stack every single time. | |
129 | // FIXME(#68817) use `llvm.dbg.value` instead, | |
130 | // at least for the cases which LLVM handles correctly. | |
131 | let spill_slot = PlaceRef::alloca(bx, operand.layout); | |
132 | if let Some(name) = name { | |
133 | bx.set_var_name(spill_slot.llval, &(name + ".dbg.spill")); | |
134 | } | |
135 | operand.val.store(bx, spill_slot); | |
136 | spill_slot | |
137 | } | |
138 | ||
e74abb32 XL |
139 | /// Apply debuginfo and/or name, after creating the `alloca` for a local, |
140 | /// or initializing the local with an operand (whichever applies). | |
e74abb32 | 141 | pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) { |
74b04a01 XL |
142 | let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full; |
143 | ||
e74abb32 | 144 | // FIXME(eddyb) maybe name the return place as `_0` or `return`? |
f9f354fc XL |
145 | if local == mir::RETURN_PLACE && !self.mir.local_decls[mir::RETURN_PLACE].is_user_variable() |
146 | { | |
e74abb32 XL |
147 | return; |
148 | } | |
149 | ||
150 | let vars = match &self.per_local_var_debug_info { | |
151 | Some(per_local) => &per_local[local], | |
152 | None => return, | |
153 | }; | |
74b04a01 XL |
154 | let whole_local_var = vars.iter().find(|var| var.projection.is_empty()).copied(); |
155 | let has_proj = || vars.iter().any(|var| !var.projection.is_empty()); | |
e74abb32 | 156 | |
74b04a01 | 157 | let fallback_var = if self.mir.local_kind(local) == mir::LocalKind::Arg { |
e74abb32 XL |
158 | let arg_index = local.index() - 1; |
159 | ||
160 | // Add debuginfo even to unnamed arguments. | |
161 | // FIXME(eddyb) is this really needed? | |
74b04a01 | 162 | if arg_index == 0 && has_proj() { |
e74abb32 XL |
163 | // Hide closure environments from debuginfo. |
164 | // FIXME(eddyb) shouldn't `ArgumentVariable` indices | |
165 | // be offset to account for the hidden environment? | |
166 | None | |
74b04a01 XL |
167 | } else if whole_local_var.is_some() { |
168 | // No need to make up anything, there is a `mir::VarDebugInfo` | |
169 | // covering the whole local. | |
170 | // FIXME(eddyb) take `whole_local_var.source_info.scope` into | |
171 | // account, just in case it doesn't use `ArgumentVariable` | |
172 | // (after #67586 gets fixed). | |
173 | None | |
e74abb32 | 174 | } else { |
5869c6ff | 175 | let name = kw::Empty; |
74b04a01 | 176 | let decl = &self.mir.local_decls[local]; |
29967ef6 XL |
177 | let dbg_var = if full_debug_info { |
178 | self.adjusted_span_and_dbg_scope(decl.source_info).map( | |
179 | |(dbg_scope, _, span)| { | |
180 | // FIXME(eddyb) is this `+ 1` needed at all? | |
181 | let kind = VariableKind::ArgumentVariable(arg_index + 1); | |
182 | ||
fc512014 | 183 | let arg_ty = self.monomorphize(decl.ty); |
29967ef6 XL |
184 | |
185 | self.cx.create_dbg_var(name, arg_ty, dbg_scope, kind, span) | |
186 | }, | |
187 | ) | |
74b04a01 | 188 | } else { |
29967ef6 | 189 | None |
74b04a01 | 190 | }; |
74b04a01 XL |
191 | |
192 | Some(PerLocalVarDebugInfo { | |
193 | name, | |
194 | source_info: decl.source_info, | |
195 | dbg_var, | |
196 | projection: ty::List::empty(), | |
e74abb32 | 197 | }) |
74b04a01 | 198 | } |
e74abb32 | 199 | } else { |
74b04a01 | 200 | None |
e74abb32 XL |
201 | }; |
202 | ||
203 | let local_ref = &self.locals[local]; | |
204 | ||
74b04a01 XL |
205 | let name = if bx.sess().fewer_names() { |
206 | None | |
207 | } else { | |
208 | Some(match whole_local_var.or(fallback_var) { | |
5869c6ff | 209 | Some(var) if var.name != kw::Empty => var.name.to_string(), |
e74abb32 | 210 | _ => format!("{:?}", local), |
74b04a01 XL |
211 | }) |
212 | }; | |
213 | ||
214 | if let Some(name) = &name { | |
e74abb32 | 215 | match local_ref { |
dfeec247 | 216 | LocalRef::Place(place) | LocalRef::UnsizedPlace(place) => { |
74b04a01 | 217 | bx.set_var_name(place.llval, name); |
e74abb32 XL |
218 | } |
219 | LocalRef::Operand(Some(operand)) => match operand.val { | |
dfeec247 | 220 | OperandValue::Ref(x, ..) | OperandValue::Immediate(x) => { |
74b04a01 | 221 | bx.set_var_name(x, name); |
e74abb32 XL |
222 | } |
223 | OperandValue::Pair(a, b) => { | |
224 | // FIXME(eddyb) these are scalar components, | |
225 | // maybe extract the high-level fields? | |
226 | bx.set_var_name(a, &(name.clone() + ".0")); | |
74b04a01 | 227 | bx.set_var_name(b, &(name.clone() + ".1")); |
e74abb32 | 228 | } |
dfeec247 | 229 | }, |
e74abb32 XL |
230 | LocalRef::Operand(None) => {} |
231 | } | |
232 | } | |
233 | ||
74b04a01 | 234 | if !full_debug_info || vars.is_empty() && fallback_var.is_none() { |
e74abb32 XL |
235 | return; |
236 | } | |
237 | ||
e74abb32 | 238 | let base = match local_ref { |
74b04a01 XL |
239 | LocalRef::Operand(None) => return, |
240 | ||
241 | LocalRef::Operand(Some(operand)) => { | |
3dfed10e XL |
242 | // Don't spill operands onto the stack in naked functions. |
243 | // See: https://github.com/rust-lang/rust/issues/42779 | |
244 | let attrs = bx.tcx().codegen_fn_attrs(self.instance.def_id()); | |
245 | if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { | |
246 | return; | |
247 | } | |
248 | ||
fc512014 | 249 | Self::spill_operand_to_stack(operand, name, bx) |
74b04a01 XL |
250 | } |
251 | ||
252 | LocalRef::Place(place) => *place, | |
253 | ||
254 | // FIXME(eddyb) add debuginfo for unsized places too. | |
255 | LocalRef::UnsizedPlace(_) => return, | |
e74abb32 XL |
256 | }; |
257 | ||
74b04a01 | 258 | let vars = vars.iter().copied().chain(fallback_var); |
e74abb32 XL |
259 | |
260 | for var in vars { | |
29967ef6 XL |
261 | let dbg_var = match var.dbg_var { |
262 | Some(dbg_var) => dbg_var, | |
263 | None => continue, | |
264 | }; | |
265 | let dbg_loc = match self.dbg_loc(var.source_info) { | |
266 | Some(dbg_loc) => dbg_loc, | |
267 | None => continue, | |
268 | }; | |
269 | ||
e74abb32 XL |
270 | let mut direct_offset = Size::ZERO; |
271 | // FIXME(eddyb) use smallvec here. | |
272 | let mut indirect_offsets = vec![]; | |
cdc7bbd5 | 273 | let mut place = base; |
e74abb32 | 274 | |
74b04a01 | 275 | for elem in &var.projection[..] { |
e74abb32 XL |
276 | match *elem { |
277 | mir::ProjectionElem::Deref => { | |
278 | indirect_offsets.push(Size::ZERO); | |
136023e0 | 279 | place = bx.load_operand(place).deref(bx.cx()); |
e74abb32 XL |
280 | } |
281 | mir::ProjectionElem::Field(field, _) => { | |
282 | let i = field.index(); | |
dfeec247 | 283 | let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset); |
cdc7bbd5 XL |
284 | *offset += place.layout.fields.offset(i); |
285 | place = place.project_field(bx, i); | |
e74abb32 XL |
286 | } |
287 | mir::ProjectionElem::Downcast(_, variant) => { | |
cdc7bbd5 | 288 | place = place.project_downcast(bx, variant); |
e74abb32 XL |
289 | } |
290 | _ => span_bug!( | |
291 | var.source_info.span, | |
292 | "unsupported var debuginfo place `{:?}`", | |
74b04a01 | 293 | mir::Place { local, projection: var.projection }, |
e74abb32 XL |
294 | ), |
295 | } | |
296 | } | |
297 | ||
cdc7bbd5 XL |
298 | // When targeting MSVC, create extra allocas for arguments instead of pointing multiple |
299 | // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records | |
300 | // not DWARF and LLVM doesn't support translating the resulting | |
301 | // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView. | |
302 | // Creating extra allocas on the stack makes the resulting debug info simple enough | |
303 | // that LLVM can generate correct CodeView records and thus the values appear in the | |
304 | // debugger. (#83709) | |
305 | let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc | |
306 | && self.mir.local_kind(local) == mir::LocalKind::Arg | |
307 | // LLVM can handle simple things but anything more complex than just a direct | |
308 | // offset or one indirect offset of 0 is too complex for it to generate CV records | |
309 | // correctly. | |
310 | && (direct_offset != Size::ZERO | |
311 | || !matches!(&indirect_offsets[..], [Size::ZERO] | [])); | |
312 | ||
313 | if should_create_individual_allocas { | |
314 | // Create a variable which will be a pointer to the actual value | |
315 | let ptr_ty = bx.tcx().mk_ty(ty::RawPtr(ty::TypeAndMut { | |
316 | mutbl: mir::Mutability::Mut, | |
317 | ty: place.layout.ty, | |
318 | })); | |
319 | let ptr_layout = bx.layout_of(ptr_ty); | |
320 | let alloca = PlaceRef::alloca(bx, ptr_layout); | |
321 | bx.set_var_name(alloca.llval, &(var.name.to_string() + ".dbg.spill")); | |
322 | ||
323 | // Write the pointer to the variable | |
324 | bx.store(place.llval, alloca.llval, alloca.align); | |
325 | ||
326 | // Point the debug info to `*alloca` for the current variable | |
327 | bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO]); | |
328 | } else { | |
329 | bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets); | |
330 | } | |
e74abb32 XL |
331 | } |
332 | } | |
333 | ||
334 | pub fn debug_introduce_locals(&self, bx: &mut Bx) { | |
335 | if bx.sess().opts.debuginfo == DebugInfo::Full || !bx.sess().fewer_names() { | |
336 | for local in self.locals.indices() { | |
337 | self.debug_introduce_local(bx, local); | |
338 | } | |
339 | } | |
340 | } | |
e74abb32 | 341 | |
74b04a01 XL |
342 | /// Partition all `VarDebugInfo` in `self.mir`, by their base `Local`. |
343 | pub fn compute_per_local_var_debug_info( | |
344 | &self, | |
fc512014 | 345 | bx: &mut Bx, |
74b04a01 XL |
346 | ) -> Option<IndexVec<mir::Local, Vec<PerLocalVarDebugInfo<'tcx, Bx::DIVariable>>>> { |
347 | let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full; | |
348 | ||
6a06907d XL |
349 | let target_is_msvc = self.cx.sess().target.is_like_msvc; |
350 | ||
74b04a01 XL |
351 | if !full_debug_info && self.cx.sess().fewer_names() { |
352 | return None; | |
353 | } | |
354 | ||
355 | let mut per_local = IndexVec::from_elem(vec![], &self.mir.local_decls); | |
356 | for var in &self.mir.var_debug_info { | |
29967ef6 XL |
357 | let dbg_scope_and_span = if full_debug_info { |
358 | self.adjusted_span_and_dbg_scope(var.source_info) | |
74b04a01 | 359 | } else { |
29967ef6 | 360 | None |
74b04a01 | 361 | }; |
fc512014 | 362 | |
29967ef6 | 363 | let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { |
fc512014 XL |
364 | let (var_ty, var_kind) = match var.value { |
365 | mir::VarDebugInfoContents::Place(place) => { | |
366 | let var_ty = self.monomorphized_place_ty(place.as_ref()); | |
367 | let var_kind = if self.mir.local_kind(place.local) == mir::LocalKind::Arg | |
368 | && place.projection.is_empty() | |
369 | && var.source_info.scope == mir::OUTERMOST_SOURCE_SCOPE | |
370 | { | |
371 | let arg_index = place.local.index() - 1; | |
6a06907d | 372 | if target_is_msvc { |
c295e0f8 XL |
373 | // ScalarPair parameters are spilled to the stack so they need to |
374 | // be marked as a `LocalVariable` for MSVC debuggers to visualize | |
375 | // their data correctly. (See #81894 & #88625) | |
376 | let var_ty_layout = self.cx.layout_of(var_ty); | |
377 | if let Abi::ScalarPair(_, _) = var_ty_layout.abi { | |
378 | VariableKind::LocalVariable | |
379 | } else { | |
380 | VariableKind::ArgumentVariable(arg_index + 1) | |
6a06907d XL |
381 | } |
382 | } else { | |
383 | // FIXME(eddyb) shouldn't `ArgumentVariable` indices be | |
384 | // offset in closures to account for the hidden environment? | |
385 | // Also, is this `+ 1` needed at all? | |
386 | VariableKind::ArgumentVariable(arg_index + 1) | |
387 | } | |
fc512014 XL |
388 | } else { |
389 | VariableKind::LocalVariable | |
390 | }; | |
391 | (var_ty, var_kind) | |
392 | } | |
393 | mir::VarDebugInfoContents::Const(c) => { | |
6a06907d | 394 | let ty = self.monomorphize(c.ty()); |
fc512014 XL |
395 | (ty, VariableKind::LocalVariable) |
396 | } | |
74b04a01 | 397 | }; |
fc512014 | 398 | |
29967ef6 | 399 | self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) |
74b04a01 XL |
400 | }); |
401 | ||
fc512014 XL |
402 | match var.value { |
403 | mir::VarDebugInfoContents::Place(place) => { | |
404 | per_local[place.local].push(PerLocalVarDebugInfo { | |
405 | name: var.name, | |
406 | source_info: var.source_info, | |
407 | dbg_var, | |
408 | projection: place.projection, | |
409 | }); | |
410 | } | |
411 | mir::VarDebugInfoContents::Const(c) => { | |
412 | if let Some(dbg_var) = dbg_var { | |
413 | let dbg_loc = match self.dbg_loc(var.source_info) { | |
414 | Some(dbg_loc) => dbg_loc, | |
415 | None => continue, | |
416 | }; | |
417 | ||
418 | if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) { | |
419 | let base = Self::spill_operand_to_stack( | |
420 | &operand, | |
421 | Some(var.name.to_string()), | |
422 | bx, | |
423 | ); | |
424 | ||
425 | bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[]); | |
426 | } | |
427 | } | |
428 | } | |
429 | } | |
e74abb32 | 430 | } |
e74abb32 | 431 | Some(per_local) |
e74abb32 XL |
432 | } |
433 | } |