]>
Commit | Line | Data |
---|---|---|
dfeec247 | 1 | use crate::traits::*; |
dfeec247 XL |
2 | use rustc_hir::def_id::CrateNum; |
3 | use rustc_index::vec::IndexVec; | |
3dfed10e | 4 | use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; |
ba9703b0 XL |
5 | use rustc_middle::mir; |
6 | use rustc_middle::ty; | |
7 | use rustc_session::config::DebugInfo; | |
74b04a01 | 8 | use rustc_span::symbol::{kw, Symbol}; |
dfeec247 | 9 | use rustc_span::{BytePos, Span}; |
ba9703b0 | 10 | use rustc_target::abi::{LayoutOf, Size}; |
e74abb32 | 11 | |
74b04a01 XL |
12 | use super::operand::OperandValue; |
13 | use super::place::PlaceRef; | |
dfeec247 | 14 | use super::{FunctionCx, LocalRef}; |
e74abb32 XL |
15 | |
16 | pub struct FunctionDebugContext<D> { | |
17 | pub scopes: IndexVec<mir::SourceScope, DebugScope<D>>, | |
e74abb32 XL |
18 | pub defining_crate: CrateNum, |
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 XL |
40 | #[derive(Clone, Copy, Debug)] |
41 | pub 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 | ||
49 | impl<D> DebugScope<D> { | |
50 | pub fn is_valid(&self) -> bool { | |
74b04a01 | 51 | self.scope_metadata.is_some() |
e74abb32 XL |
52 | } |
53 | } | |
54 | ||
55 | impl<'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 | } |