]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_ssa/mir/debuginfo.rs
d6b91c1f6bbb8b0518776107b3878a7dddfe3108
[rust.git] / src / librustc_codegen_ssa / mir / debuginfo.rs
1 use rustc_index::vec::Idx;
2 use rustc::hir::def_id::CrateNum;
3 use rustc::mir;
4 use rustc::session::config::DebugInfo;
5 use rustc::ty::{self, UpvarSubsts};
6 use rustc::ty::layout::HasTyCtxt;
7 use rustc_target::abi::{Variants, VariantIdx};
8 use crate::traits::*;
9
10 use syntax_pos::{DUMMY_SP, BytePos, Span};
11 use syntax::symbol::kw;
12
13 use super::{FunctionCx, LocalRef};
14
15 pub enum FunctionDebugContext<D> {
16     RegularContext(FunctionDebugContextData<D>),
17     DebugInfoDisabled,
18     FunctionWithoutDebugInfo,
19 }
20
21 impl<D> FunctionDebugContext<D> {
22     pub fn get_ref(&self, span: Span) -> &FunctionDebugContextData<D> {
23         match *self {
24             FunctionDebugContext::RegularContext(ref data) => data,
25             FunctionDebugContext::DebugInfoDisabled => {
26                 span_bug!(
27                     span,
28                     "debuginfo: Error trying to access FunctionDebugContext \
29                      although debug info is disabled!",
30                 );
31             }
32             FunctionDebugContext::FunctionWithoutDebugInfo => {
33                 span_bug!(
34                     span,
35                     "debuginfo: Error trying to access FunctionDebugContext \
36                      for function that should be ignored by debug info!",
37                 );
38             }
39         }
40     }
41 }
42
43 /// Enables emitting source locations for the given functions.
44 ///
45 /// Since we don't want source locations to be emitted for the function prelude,
46 /// they are disabled when beginning to codegen a new function. This functions
47 /// switches source location emitting on and must therefore be called before the
48 /// first real statement/expression of the function is codegened.
49 pub fn start_emitting_source_locations<D>(dbg_context: &mut FunctionDebugContext<D>) {
50     match *dbg_context {
51         FunctionDebugContext::RegularContext(ref mut data) => {
52             data.source_locations_enabled = true;
53         },
54         _ => { /* safe to ignore */ }
55     }
56 }
57
58 pub struct FunctionDebugContextData<D> {
59     pub fn_metadata: D,
60     pub source_locations_enabled: bool,
61     pub defining_crate: CrateNum,
62 }
63
64 pub enum VariableAccess<'a, V> {
65     // The llptr given is an alloca containing the variable's value
66     DirectVariable { alloca: V },
67     // The llptr given is an alloca containing the start of some pointer chain
68     // leading to the variable's content.
69     IndirectVariable { alloca: V, address_operations: &'a [i64] }
70 }
71
72 pub enum VariableKind {
73     ArgumentVariable(usize /*index*/),
74     LocalVariable,
75 }
76
77
78 #[derive(Clone, Copy, Debug)]
79 pub struct DebugScope<D> {
80     pub scope_metadata: Option<D>,
81     // Start and end offsets of the file to which this DIScope belongs.
82     // These are used to quickly determine whether some span refers to the same file.
83     pub file_start_pos: BytePos,
84     pub file_end_pos: BytePos,
85 }
86
87 impl<D> DebugScope<D> {
88     pub fn is_valid(&self) -> bool {
89         !self.scope_metadata.is_none()
90     }
91 }
92
93 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
94     pub fn set_debug_loc(
95         &mut self,
96         bx: &mut Bx,
97         source_info: mir::SourceInfo
98     ) {
99         let (scope, span) = self.debug_loc(source_info);
100         bx.set_source_location(&mut self.debug_context, scope, span);
101     }
102
103     pub fn debug_loc(&self, source_info: mir::SourceInfo) -> (Option<Bx::DIScope>, Span) {
104         // Bail out if debug info emission is not enabled.
105         match self.debug_context {
106             FunctionDebugContext::DebugInfoDisabled |
107             FunctionDebugContext::FunctionWithoutDebugInfo => {
108                 return (self.scopes[source_info.scope].scope_metadata, source_info.span);
109             }
110             FunctionDebugContext::RegularContext(_) =>{}
111         }
112
113         // In order to have a good line stepping behavior in debugger, we overwrite debug
114         // locations of macro expansions with that of the outermost expansion site
115         // (unless the crate is being compiled with `-Z debug-macros`).
116         if !source_info.span.from_expansion() ||
117            self.cx.sess().opts.debugging_opts.debug_macros {
118             let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo());
119             (scope, source_info.span)
120         } else {
121             // Walk up the macro expansion chain until we reach a non-expanded span.
122             // We also stop at the function body level because no line stepping can occur
123             // at the level above that.
124             let span = syntax_pos::hygiene::walk_chain(source_info.span, self.mir.span.ctxt());
125             let scope = self.scope_metadata_for_loc(source_info.scope, span.lo());
126             // Use span of the outermost expansion site, while keeping the original lexical scope.
127             (scope, span)
128         }
129     }
130
131     // DILocations inherit source file name from the parent DIScope.  Due to macro expansions
132     // it may so happen that the current span belongs to a different file than the DIScope
133     // corresponding to span's containing source scope.  If so, we need to create a DIScope
134     // "extension" into that file.
135     fn scope_metadata_for_loc(&self, scope_id: mir::SourceScope, pos: BytePos)
136                               -> Option<Bx::DIScope> {
137         let scope_metadata = self.scopes[scope_id].scope_metadata;
138         if pos < self.scopes[scope_id].file_start_pos ||
139            pos >= self.scopes[scope_id].file_end_pos {
140             let sm = self.cx.sess().source_map();
141             let defining_crate = self.debug_context.get_ref(DUMMY_SP).defining_crate;
142             Some(self.cx.extend_scope_to_file(
143                 scope_metadata.unwrap(),
144                 &sm.lookup_char_pos(pos).file,
145                 defining_crate
146             ))
147         } else {
148             scope_metadata
149         }
150     }
151
152     pub fn debug_declare_locals(&self, bx: &mut Bx) {
153         let tcx = self.cx.tcx();
154         let upvar_debuginfo = &self.mir.__upvar_debuginfo_codegen_only_do_not_use;
155
156         if bx.sess().opts.debuginfo != DebugInfo::Full {
157             return;
158         }
159
160         for (local, local_ref) in self.locals.iter_enumerated() {
161             if local == mir::RETURN_PLACE {
162                 continue;
163             }
164
165             // FIXME(eddyb) add debuginfo for unsized places too.
166             let place = match local_ref {
167                 LocalRef::Place(place) => place,
168                 _ => continue,
169             };
170
171             let decl = &self.mir.local_decls[local];
172             let (name, kind) = if self.mir.local_kind(local) == mir::LocalKind::Arg {
173                 let arg_index = local.index() - 1;
174
175                 // Add debuginfo even to unnamed arguments.
176                 // FIXME(eddyb) is this really needed?
177                 let name = if arg_index == 0 && !upvar_debuginfo.is_empty() {
178                     // Hide closure environments from debuginfo.
179                     // FIXME(eddyb) shouldn't `ArgumentVariable` indices
180                     // be offset to account for the hidden environment?
181                     None
182                 } else {
183                     Some(decl.name.unwrap_or(kw::Invalid))
184                 };
185                 (name, VariableKind::ArgumentVariable(arg_index + 1))
186             } else {
187                 (decl.name, VariableKind::LocalVariable)
188             };
189             if let Some(name) = name {
190                 let (scope, span) = self.debug_loc(mir::SourceInfo {
191                     span: decl.source_info.span,
192                     scope: decl.visibility_scope,
193                 });
194                 if let Some(scope) = scope {
195                     bx.declare_local(&self.debug_context, name, place.layout.ty, scope,
196                         VariableAccess::DirectVariable { alloca: place.llval },
197                         kind, span);
198                 }
199             }
200         }
201
202         // Declare closure captures as if they were local variables.
203         // FIXME(eddyb) generalize this to `name => place` mappings.
204         let upvar_scope = if !upvar_debuginfo.is_empty() {
205             self.scopes[mir::OUTERMOST_SOURCE_SCOPE].scope_metadata
206         } else {
207             None
208         };
209         if let Some(scope) = upvar_scope {
210             let place = match self.locals[mir::Local::new(1)] {
211                 LocalRef::Place(place) => place,
212                 _ => bug!(),
213             };
214
215             let pin_did = tcx.lang_items().pin_type();
216             let (closure_layout, env_ref) = match place.layout.ty.kind {
217                 ty::RawPtr(ty::TypeAndMut { ty, .. }) |
218                 ty::Ref(_, ty, _)  => (bx.layout_of(ty), true),
219                 ty::Adt(def, substs) if Some(def.did) == pin_did => {
220                     match substs.type_at(0).kind {
221                         ty::Ref(_, ty, _)  => (bx.layout_of(ty), true),
222                         _ => (place.layout, false),
223                     }
224                 }
225                 _ => (place.layout, false)
226             };
227
228             let (def_id, upvar_substs) = match closure_layout.ty.kind {
229                 ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)),
230                 ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)),
231                 _ => bug!("upvar debuginfo with non-closure arg0 type `{}`", closure_layout.ty)
232             };
233             let upvar_tys = upvar_substs.upvar_tys(def_id, tcx);
234
235             let extra_locals = {
236                 let upvars = upvar_debuginfo
237                     .iter()
238                     .zip(upvar_tys)
239                     .enumerate()
240                     .map(|(i, (upvar, ty))| {
241                         (None, i, upvar.debug_name, upvar.by_ref, ty, scope, DUMMY_SP)
242                     });
243
244                 let generator_fields = self.mir.generator_layout.as_ref().map(|generator_layout| {
245                     let (def_id, gen_substs) = match closure_layout.ty.kind {
246                         ty::Generator(def_id, substs, _) => (def_id, substs),
247                         _ => bug!("generator layout without generator substs"),
248                     };
249                     let state_tys = gen_substs.as_generator().state_tys(def_id, tcx);
250
251                     generator_layout.variant_fields.iter()
252                         .zip(state_tys)
253                         .enumerate()
254                         .flat_map(move |(variant_idx, (fields, tys))| {
255                             let variant_idx = Some(VariantIdx::from(variant_idx));
256                             fields.iter()
257                                 .zip(tys)
258                                 .enumerate()
259                                 .filter_map(move |(i, (field, ty))| {
260                                     let decl = &generator_layout.
261                                         __local_debuginfo_codegen_only_do_not_use[*field];
262                                     if let Some(name) = decl.name {
263                                         let ty = self.monomorphize(&ty);
264                                         let (var_scope, var_span) = self.debug_loc(mir::SourceInfo {
265                                             span: decl.source_info.span,
266                                             scope: decl.visibility_scope,
267                                         });
268                                         let var_scope = var_scope.unwrap_or(scope);
269                                         Some((variant_idx, i, name, false, ty, var_scope, var_span))
270                                     } else {
271                                         None
272                                     }
273                             })
274                         })
275                 }).into_iter().flatten();
276
277                 upvars.chain(generator_fields)
278             };
279
280             for (variant_idx, field, name, by_ref, ty, var_scope, var_span) in extra_locals {
281                 let fields = match variant_idx {
282                     Some(variant_idx) => {
283                         match &closure_layout.variants {
284                             Variants::Multiple { variants, .. } => {
285                                 &variants[variant_idx].fields
286                             },
287                             _ => bug!("variant index on univariant layout"),
288                         }
289                     }
290                     None => &closure_layout.fields,
291                 };
292                 let byte_offset_of_var_in_env = fields.offset(field).bytes();
293
294                 let ops = bx.debuginfo_upvar_ops_sequence(byte_offset_of_var_in_env);
295
296                 // The environment and the capture can each be indirect.
297                 let mut ops = if env_ref { &ops[..] } else { &ops[1..] };
298
299                 let ty = if let (true, &ty::Ref(_, ty, _)) = (by_ref, &ty.kind) {
300                     ty
301                 } else {
302                     ops = &ops[..ops.len() - 1];
303                     ty
304                 };
305
306                 let variable_access = VariableAccess::IndirectVariable {
307                     alloca: place.llval,
308                     address_operations: &ops
309                 };
310                 bx.declare_local(
311                     &self.debug_context,
312                     name,
313                     ty,
314                     var_scope,
315                     variable_access,
316                     VariableKind::LocalVariable,
317                     var_span
318                 );
319             }
320         }
321     }
322 }