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