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