1 use rustc_index::vec::Idx;
2 use rustc::hir::def_id::CrateNum;
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};
10 use syntax_pos::{DUMMY_SP, BytePos, Span};
11 use syntax::symbol::kw;
13 use super::{FunctionCx, LocalRef};
15 pub enum FunctionDebugContext<D> {
16 RegularContext(FunctionDebugContextData<D>),
18 FunctionWithoutDebugInfo,
21 impl<D> FunctionDebugContext<D> {
22 pub fn get_ref(&self, span: Span) -> &FunctionDebugContextData<D> {
24 FunctionDebugContext::RegularContext(ref data) => data,
25 FunctionDebugContext::DebugInfoDisabled => {
28 "debuginfo: Error trying to access FunctionDebugContext \
29 although debug info is disabled!",
32 FunctionDebugContext::FunctionWithoutDebugInfo => {
35 "debuginfo: Error trying to access FunctionDebugContext \
36 for function that should be ignored by debug info!",
43 /// Enables emitting source locations for the given functions.
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>) {
51 FunctionDebugContext::RegularContext(ref mut data) => {
52 data.source_locations_enabled = true;
54 _ => { /* safe to ignore */ }
58 pub struct FunctionDebugContextData<D> {
60 pub source_locations_enabled: bool,
61 pub defining_crate: CrateNum,
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] }
72 pub enum VariableKind {
73 ArgumentVariable(usize /*index*/),
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,
87 impl<D> DebugScope<D> {
88 pub fn is_valid(&self) -> bool {
89 !self.scope_metadata.is_none()
93 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
97 source_info: mir::SourceInfo
99 let (scope, span) = self.debug_loc(source_info);
100 bx.set_source_location(&mut self.debug_context, scope, span);
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);
110 FunctionDebugContext::RegularContext(_) =>{}
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)
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.
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,
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;
156 if bx.sess().opts.debuginfo != DebugInfo::Full {
160 for (local, local_ref) in self.locals.iter_enumerated() {
161 if local == mir::RETURN_PLACE {
165 // FIXME(eddyb) add debuginfo for unsized places too.
166 let place = match local_ref {
167 LocalRef::Place(place) => place,
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;
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?
183 Some(decl.name.unwrap_or(kw::Invalid))
185 (name, VariableKind::ArgumentVariable(arg_index + 1))
187 (decl.name, VariableKind::LocalVariable)
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,
194 if let Some(scope) = scope {
195 bx.declare_local(&self.debug_context, name, place.layout.ty, scope,
196 VariableAccess::DirectVariable { alloca: place.llval },
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
209 if let Some(scope) = upvar_scope {
210 let place = match self.locals[mir::Local::new(1)] {
211 LocalRef::Place(place) => place,
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),
225 _ => (place.layout, false)
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)
233 let upvar_tys = upvar_substs.upvar_tys(def_id, tcx);
236 let upvars = upvar_debuginfo
240 .map(|(i, (upvar, ty))| {
241 (None, i, upvar.debug_name, upvar.by_ref, ty, scope, DUMMY_SP)
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"),
249 let state_tys = gen_substs.as_generator().state_tys(def_id, tcx);
251 generator_layout.variant_fields.iter()
254 .flat_map(move |(variant_idx, (fields, tys))| {
255 let variant_idx = Some(VariantIdx::from(variant_idx));
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,
268 let var_scope = var_scope.unwrap_or(scope);
269 Some((variant_idx, i, name, false, ty, var_scope, var_span))
275 }).into_iter().flatten();
277 upvars.chain(generator_fields)
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
287 _ => bug!("variant index on univariant layout"),
290 None => &closure_layout.fields,
292 let byte_offset_of_var_in_env = fields.offset(field).bytes();
294 let ops = bx.debuginfo_upvar_ops_sequence(byte_offset_of_var_in_env);
296 // The environment and the capture can each be indirect.
297 let mut ops = if env_ref { &ops[..] } else { &ops[1..] };
299 let ty = if let (true, &ty::Ref(_, ty, _)) = (by_ref, &ty.kind) {
302 ops = &ops[..ops.len() - 1];
306 let variable_access = VariableAccess::IndirectVariable {
308 address_operations: &ops
316 VariableKind::LocalVariable,