]> git.proxmox.com Git - rustc.git/blame - src/librustc_codegen_ssa/mir/debuginfo.rs
New upstream version 1.47.0+dfsg1
[rustc.git] / src / librustc_codegen_ssa / mir / debuginfo.rs
CommitLineData
dfeec247 1use crate::traits::*;
dfeec247
XL
2use rustc_hir::def_id::CrateNum;
3use rustc_index::vec::IndexVec;
3dfed10e 4use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
ba9703b0
XL
5use rustc_middle::mir;
6use rustc_middle::ty;
7use rustc_session::config::DebugInfo;
74b04a01 8use rustc_span::symbol::{kw, Symbol};
dfeec247 9use rustc_span::{BytePos, Span};
ba9703b0 10use rustc_target::abi::{LayoutOf, Size};
e74abb32 11
74b04a01
XL
12use super::operand::OperandValue;
13use super::place::PlaceRef;
dfeec247 14use super::{FunctionCx, LocalRef};
e74abb32
XL
15
16pub struct FunctionDebugContext<D> {
17 pub scopes: IndexVec<mir::SourceScope, DebugScope<D>>,
e74abb32
XL
18 pub defining_crate: CrateNum,
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
XL
40#[derive(Clone, Copy, Debug)]
41pub struct DebugScope<D> {
42 pub scope_metadata: Option<D>,
43 // Start and end offsets of the file to which this DIScope belongs.
44 // These are used to quickly determine whether some span refers to the same file.
45 pub file_start_pos: BytePos,
46 pub file_end_pos: BytePos,
47}
48
49impl<D> DebugScope<D> {
50 pub fn is_valid(&self) -> bool {
74b04a01 51 self.scope_metadata.is_some()
e74abb32
XL
52 }
53}
54
55impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
74b04a01 56 pub fn set_debug_loc(&self, bx: &mut Bx, source_info: mir::SourceInfo) {
e74abb32 57 let (scope, span) = self.debug_loc(source_info);
74b04a01
XL
58 if let Some(scope) = scope {
59 bx.set_source_location(scope, span);
e74abb32
XL
60 }
61 }
62
63 pub fn debug_loc(&self, source_info: mir::SourceInfo) -> (Option<Bx::DIScope>, Span) {
64 // Bail out if debug info emission is not enabled.
65 match self.debug_context {
66 None => return (None, source_info.span),
67 Some(_) => {}
68 }
69
70 // In order to have a good line stepping behavior in debugger, we overwrite debug
71 // locations of macro expansions with that of the outermost expansion site
72 // (unless the crate is being compiled with `-Z debug-macros`).
dfeec247 73 if !source_info.span.from_expansion() || self.cx.sess().opts.debugging_opts.debug_macros {
e74abb32
XL
74 let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo());
75 (scope, source_info.span)
76 } else {
77 // Walk up the macro expansion chain until we reach a non-expanded span.
78 // We also stop at the function body level because no line stepping can occur
79 // at the level above that.
dfeec247 80 let span = rustc_span::hygiene::walk_chain(source_info.span, self.mir.span.ctxt());
e74abb32
XL
81 let scope = self.scope_metadata_for_loc(source_info.scope, span.lo());
82 // Use span of the outermost expansion site, while keeping the original lexical scope.
83 (scope, span)
84 }
85 }
86
87 // DILocations inherit source file name from the parent DIScope. Due to macro expansions
88 // it may so happen that the current span belongs to a different file than the DIScope
89 // corresponding to span's containing source scope. If so, we need to create a DIScope
90 // "extension" into that file.
dfeec247
XL
91 fn scope_metadata_for_loc(
92 &self,
93 scope_id: mir::SourceScope,
94 pos: BytePos,
95 ) -> Option<Bx::DIScope> {
e74abb32
XL
96 let debug_context = self.debug_context.as_ref()?;
97 let scope_metadata = debug_context.scopes[scope_id].scope_metadata;
dfeec247
XL
98 if pos < debug_context.scopes[scope_id].file_start_pos
99 || pos >= debug_context.scopes[scope_id].file_end_pos
100 {
e74abb32
XL
101 let sm = self.cx.sess().source_map();
102 let defining_crate = debug_context.defining_crate;
103 Some(self.cx.extend_scope_to_file(
104 scope_metadata.unwrap(),
105 &sm.lookup_char_pos(pos).file,
dfeec247 106 defining_crate,
e74abb32
XL
107 ))
108 } else {
109 scope_metadata
110 }
111 }
112
113 /// Apply debuginfo and/or name, after creating the `alloca` for a local,
114 /// or initializing the local with an operand (whichever applies).
e74abb32 115 pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
74b04a01
XL
116 let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full;
117
e74abb32 118 // FIXME(eddyb) maybe name the return place as `_0` or `return`?
f9f354fc
XL
119 if local == mir::RETURN_PLACE && !self.mir.local_decls[mir::RETURN_PLACE].is_user_variable()
120 {
e74abb32
XL
121 return;
122 }
123
124 let vars = match &self.per_local_var_debug_info {
125 Some(per_local) => &per_local[local],
126 None => return,
127 };
74b04a01
XL
128 let whole_local_var = vars.iter().find(|var| var.projection.is_empty()).copied();
129 let has_proj = || vars.iter().any(|var| !var.projection.is_empty());
e74abb32 130
74b04a01 131 let fallback_var = if self.mir.local_kind(local) == mir::LocalKind::Arg {
e74abb32
XL
132 let arg_index = local.index() - 1;
133
134 // Add debuginfo even to unnamed arguments.
135 // FIXME(eddyb) is this really needed?
74b04a01 136 if arg_index == 0 && has_proj() {
e74abb32
XL
137 // Hide closure environments from debuginfo.
138 // FIXME(eddyb) shouldn't `ArgumentVariable` indices
139 // be offset to account for the hidden environment?
140 None
74b04a01
XL
141 } else if whole_local_var.is_some() {
142 // No need to make up anything, there is a `mir::VarDebugInfo`
143 // covering the whole local.
144 // FIXME(eddyb) take `whole_local_var.source_info.scope` into
145 // account, just in case it doesn't use `ArgumentVariable`
146 // (after #67586 gets fixed).
147 None
e74abb32 148 } else {
74b04a01
XL
149 let name = kw::Invalid;
150 let decl = &self.mir.local_decls[local];
151 let (scope, span) = if full_debug_info {
152 self.debug_loc(decl.source_info)
153 } else {
154 (None, decl.source_info.span)
155 };
156 let dbg_var = scope.map(|scope| {
157 // FIXME(eddyb) is this `+ 1` needed at all?
158 let kind = VariableKind::ArgumentVariable(arg_index + 1);
159
160 self.cx.create_dbg_var(
161 self.debug_context.as_ref().unwrap(),
162 name,
163 self.monomorphize(&decl.ty),
164 scope,
165 kind,
166 span,
167 )
168 });
169
170 Some(PerLocalVarDebugInfo {
171 name,
172 source_info: decl.source_info,
173 dbg_var,
174 projection: ty::List::empty(),
e74abb32 175 })
74b04a01 176 }
e74abb32 177 } else {
74b04a01 178 None
e74abb32
XL
179 };
180
181 let local_ref = &self.locals[local];
182
74b04a01
XL
183 let name = if bx.sess().fewer_names() {
184 None
185 } else {
186 Some(match whole_local_var.or(fallback_var) {
e74abb32
XL
187 Some(var) if var.name != kw::Invalid => var.name.to_string(),
188 _ => format!("{:?}", local),
74b04a01
XL
189 })
190 };
191
192 if let Some(name) = &name {
e74abb32 193 match local_ref {
dfeec247 194 LocalRef::Place(place) | LocalRef::UnsizedPlace(place) => {
74b04a01 195 bx.set_var_name(place.llval, name);
e74abb32
XL
196 }
197 LocalRef::Operand(Some(operand)) => match operand.val {
dfeec247 198 OperandValue::Ref(x, ..) | OperandValue::Immediate(x) => {
74b04a01 199 bx.set_var_name(x, name);
e74abb32
XL
200 }
201 OperandValue::Pair(a, b) => {
202 // FIXME(eddyb) these are scalar components,
203 // maybe extract the high-level fields?
204 bx.set_var_name(a, &(name.clone() + ".0"));
74b04a01 205 bx.set_var_name(b, &(name.clone() + ".1"));
e74abb32 206 }
dfeec247 207 },
e74abb32
XL
208 LocalRef::Operand(None) => {}
209 }
210 }
211
74b04a01 212 if !full_debug_info || vars.is_empty() && fallback_var.is_none() {
e74abb32
XL
213 return;
214 }
215
e74abb32 216 let base = match local_ref {
74b04a01
XL
217 LocalRef::Operand(None) => return,
218
219 LocalRef::Operand(Some(operand)) => {
3dfed10e
XL
220 // Don't spill operands onto the stack in naked functions.
221 // See: https://github.com/rust-lang/rust/issues/42779
222 let attrs = bx.tcx().codegen_fn_attrs(self.instance.def_id());
223 if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
224 return;
225 }
226
74b04a01
XL
227 // "Spill" the value onto the stack, for debuginfo,
228 // without forcing non-debuginfo uses of the local
229 // to also load from the stack every single time.
230 // FIXME(#68817) use `llvm.dbg.value` instead,
231 // at least for the cases which LLVM handles correctly.
232 let spill_slot = PlaceRef::alloca(bx, operand.layout);
233 if let Some(name) = name {
234 bx.set_var_name(spill_slot.llval, &(name + ".dbg.spill"));
235 }
236 operand.val.store(bx, spill_slot);
237 spill_slot
238 }
239
240 LocalRef::Place(place) => *place,
241
242 // FIXME(eddyb) add debuginfo for unsized places too.
243 LocalRef::UnsizedPlace(_) => return,
e74abb32
XL
244 };
245
74b04a01 246 let vars = vars.iter().copied().chain(fallback_var);
e74abb32
XL
247
248 for var in vars {
249 let mut layout = base.layout;
250 let mut direct_offset = Size::ZERO;
251 // FIXME(eddyb) use smallvec here.
252 let mut indirect_offsets = vec![];
253
74b04a01 254 for elem in &var.projection[..] {
e74abb32
XL
255 match *elem {
256 mir::ProjectionElem::Deref => {
257 indirect_offsets.push(Size::ZERO);
258 layout = bx.cx().layout_of(
dfeec247
XL
259 layout
260 .ty
261 .builtin_deref(true)
e74abb32 262 .unwrap_or_else(|| {
74b04a01 263 span_bug!(var.source_info.span, "cannot deref `{}`", layout.ty)
dfeec247
XL
264 })
265 .ty,
e74abb32
XL
266 );
267 }
268 mir::ProjectionElem::Field(field, _) => {
269 let i = field.index();
dfeec247 270 let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
e74abb32
XL
271 *offset += layout.fields.offset(i);
272 layout = layout.field(bx.cx(), i);
273 }
274 mir::ProjectionElem::Downcast(_, variant) => {
275 layout = layout.for_variant(bx.cx(), variant);
276 }
277 _ => span_bug!(
278 var.source_info.span,
279 "unsupported var debuginfo place `{:?}`",
74b04a01 280 mir::Place { local, projection: var.projection },
e74abb32
XL
281 ),
282 }
283 }
284
285 let (scope, span) = self.debug_loc(var.source_info);
286 if let Some(scope) = scope {
74b04a01
XL
287 if let Some(dbg_var) = var.dbg_var {
288 bx.dbg_var_addr(
289 dbg_var,
290 scope,
291 base.llval,
292 direct_offset,
293 &indirect_offsets,
294 span,
295 );
296 }
e74abb32
XL
297 }
298 }
299 }
300
301 pub fn debug_introduce_locals(&self, bx: &mut Bx) {
302 if bx.sess().opts.debuginfo == DebugInfo::Full || !bx.sess().fewer_names() {
303 for local in self.locals.indices() {
304 self.debug_introduce_local(bx, local);
305 }
306 }
307 }
e74abb32 308
74b04a01
XL
309 /// Partition all `VarDebugInfo` in `self.mir`, by their base `Local`.
310 pub fn compute_per_local_var_debug_info(
311 &self,
312 ) -> Option<IndexVec<mir::Local, Vec<PerLocalVarDebugInfo<'tcx, Bx::DIVariable>>>> {
313 let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full;
314
315 if !full_debug_info && self.cx.sess().fewer_names() {
316 return None;
317 }
318
319 let mut per_local = IndexVec::from_elem(vec![], &self.mir.local_decls);
320 for var in &self.mir.var_debug_info {
321 let (scope, span) = if full_debug_info {
322 self.debug_loc(var.source_info)
323 } else {
324 (None, var.source_info.span)
325 };
326 let dbg_var = scope.map(|scope| {
327 let place = var.place;
328 let var_ty = self.monomorphized_place_ty(place.as_ref());
329 let var_kind = if self.mir.local_kind(place.local) == mir::LocalKind::Arg
330 && place.projection.is_empty()
331 && var.source_info.scope == mir::OUTERMOST_SOURCE_SCOPE
332 {
333 let arg_index = place.local.index() - 1;
334
335 // FIXME(eddyb) shouldn't `ArgumentVariable` indices be
336 // offset in closures to account for the hidden environment?
337 // Also, is this `+ 1` needed at all?
338 VariableKind::ArgumentVariable(arg_index + 1)
339 } else {
340 VariableKind::LocalVariable
341 };
342 self.cx.create_dbg_var(
343 self.debug_context.as_ref().unwrap(),
344 var.name,
345 var_ty,
346 scope,
347 var_kind,
348 span,
349 )
350 });
351
352 per_local[var.place.local].push(PerLocalVarDebugInfo {
353 name: var.name,
354 source_info: var.source_info,
355 dbg_var,
356 projection: var.place.projection,
357 });
e74abb32 358 }
e74abb32 359 Some(per_local)
e74abb32
XL
360 }
361}