]> git.proxmox.com Git - rustc.git/blob - src/librustc_trans/trans/debuginfo/mod.rs
Imported Upstream version 1.2.0+dfsg1
[rustc.git] / src / librustc_trans / trans / debuginfo / mod.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // See doc.rs for documentation.
12 mod doc;
13
14 use self::VariableAccess::*;
15 use self::VariableKind::*;
16
17 use self::utils::{DIB, span_start, assert_type_for_node_id, contains_nodebug_attribute,
18 create_DIArray, is_node_local_to_unit};
19 use self::namespace::{namespace_for_item, NamespaceTreeNode};
20 use self::type_names::compute_debuginfo_type_name;
21 use self::metadata::{type_metadata, file_metadata, scope_metadata, TypeMap, compile_unit_metadata};
22 use self::source_loc::InternalDebugLocation;
23
24 use llvm;
25 use llvm::{ModuleRef, ContextRef, ValueRef};
26 use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray,
27 DIDescriptor, FlagPrototyped};
28 use middle::subst::{self, Substs};
29 use rustc::ast_map;
30 use trans::common::{NodeIdAndSpan, CrateContext, FunctionContext, Block};
31 use trans;
32 use trans::monomorphize;
33 use middle::ty::{self, Ty, ClosureTyper};
34 use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
35 use util::nodemap::{DefIdMap, NodeMap, FnvHashMap, FnvHashSet};
36
37 use libc::c_uint;
38 use std::cell::{Cell, RefCell};
39 use std::ffi::CString;
40 use std::ptr;
41 use std::rc::Rc;
42 use syntax::codemap::{Span, Pos};
43 use syntax::{ast, codemap, ast_util};
44 use syntax::parse::token::{self, special_idents};
45
46 pub mod gdb;
47 mod utils;
48 mod namespace;
49 mod type_names;
50 mod metadata;
51 mod create_scope_map;
52 mod source_loc;
53
54 pub use self::source_loc::set_source_location;
55 pub use self::source_loc::clear_source_location;
56 pub use self::source_loc::start_emitting_source_locations;
57 pub use self::source_loc::get_cleanup_debug_loc_for_ast_node;
58 pub use self::source_loc::with_source_location_override;
59 pub use self::metadata::create_match_binding_metadata;
60 pub use self::metadata::create_argument_metadata;
61 pub use self::metadata::create_captured_var_metadata;
62 pub use self::metadata::create_global_var_metadata;
63 pub use self::metadata::create_local_var_metadata;
64
65 #[allow(non_upper_case_globals)]
66 const DW_TAG_auto_variable: c_uint = 0x100;
67 #[allow(non_upper_case_globals)]
68 const DW_TAG_arg_variable: c_uint = 0x101;
69
70 /// A context object for maintaining all state needed by the debuginfo module.
71 pub struct CrateDebugContext<'tcx> {
72 llcontext: ContextRef,
73 builder: DIBuilderRef,
74 current_debug_location: Cell<InternalDebugLocation>,
75 created_files: RefCell<FnvHashMap<String, DIFile>>,
76 created_enum_disr_types: RefCell<DefIdMap<DIType>>,
77
78 type_map: RefCell<TypeMap<'tcx>>,
79 namespace_map: RefCell<FnvHashMap<Vec<ast::Name>, Rc<NamespaceTreeNode>>>,
80
81 // This collection is used to assert that composite types (structs, enums,
82 // ...) have their members only set once:
83 composite_types_completed: RefCell<FnvHashSet<DIType>>,
84 }
85
86 impl<'tcx> CrateDebugContext<'tcx> {
87 pub fn new(llmod: ModuleRef) -> CrateDebugContext<'tcx> {
88 debug!("CrateDebugContext::new");
89 let builder = unsafe { llvm::LLVMDIBuilderCreate(llmod) };
90 // DIBuilder inherits context from the module, so we'd better use the same one
91 let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
92 return CrateDebugContext {
93 llcontext: llcontext,
94 builder: builder,
95 current_debug_location: Cell::new(InternalDebugLocation::UnknownLocation),
96 created_files: RefCell::new(FnvHashMap()),
97 created_enum_disr_types: RefCell::new(DefIdMap()),
98 type_map: RefCell::new(TypeMap::new()),
99 namespace_map: RefCell::new(FnvHashMap()),
100 composite_types_completed: RefCell::new(FnvHashSet()),
101 };
102 }
103 }
104
105 pub enum FunctionDebugContext {
106 RegularContext(Box<FunctionDebugContextData>),
107 DebugInfoDisabled,
108 FunctionWithoutDebugInfo,
109 }
110
111 impl FunctionDebugContext {
112 fn get_ref<'a>(&'a self,
113 cx: &CrateContext,
114 span: Span)
115 -> &'a FunctionDebugContextData {
116 match *self {
117 FunctionDebugContext::RegularContext(box ref data) => data,
118 FunctionDebugContext::DebugInfoDisabled => {
119 cx.sess().span_bug(span,
120 FunctionDebugContext::debuginfo_disabled_message());
121 }
122 FunctionDebugContext::FunctionWithoutDebugInfo => {
123 cx.sess().span_bug(span,
124 FunctionDebugContext::should_be_ignored_message());
125 }
126 }
127 }
128
129 fn debuginfo_disabled_message() -> &'static str {
130 "debuginfo: Error trying to access FunctionDebugContext although debug info is disabled!"
131 }
132
133 fn should_be_ignored_message() -> &'static str {
134 "debuginfo: Error trying to access FunctionDebugContext for function that should be \
135 ignored by debug info!"
136 }
137 }
138
139 struct FunctionDebugContextData {
140 scope_map: RefCell<NodeMap<DIScope>>,
141 fn_metadata: DISubprogram,
142 argument_counter: Cell<usize>,
143 source_locations_enabled: Cell<bool>,
144 source_location_override: Cell<bool>,
145 }
146
147 pub enum VariableAccess<'a> {
148 // The llptr given is an alloca containing the variable's value
149 DirectVariable { alloca: ValueRef },
150 // The llptr given is an alloca containing the start of some pointer chain
151 // leading to the variable's content.
152 IndirectVariable { alloca: ValueRef, address_operations: &'a [i64] }
153 }
154
155 pub enum VariableKind {
156 ArgumentVariable(usize /*index*/),
157 LocalVariable,
158 CapturedVariable,
159 }
160
161 /// Create any deferred debug metadata nodes
162 pub fn finalize(cx: &CrateContext) {
163 if cx.dbg_cx().is_none() {
164 return;
165 }
166
167 debug!("finalize");
168 let _ = compile_unit_metadata(cx);
169
170 if gdb::needs_gdb_debug_scripts_section(cx) {
171 // Add a .debug_gdb_scripts section to this compile-unit. This will
172 // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
173 // which activates the Rust pretty printers for binary this section is
174 // contained in.
175 gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
176 }
177
178 unsafe {
179 llvm::LLVMDIBuilderFinalize(DIB(cx));
180 llvm::LLVMDIBuilderDispose(DIB(cx));
181 // Debuginfo generation in LLVM by default uses a higher
182 // version of dwarf than OS X currently understands. We can
183 // instruct LLVM to emit an older version of dwarf, however,
184 // for OS X to understand. For more info see #11352
185 // This can be overridden using --llvm-opts -dwarf-version,N.
186 // Android has the same issue (#22398)
187 if cx.sess().target.target.options.is_like_osx ||
188 cx.sess().target.target.options.is_like_android {
189 llvm::LLVMRustAddModuleFlag(cx.llmod(),
190 "Dwarf Version\0".as_ptr() as *const _,
191 2)
192 }
193
194 // Prevent bitcode readers from deleting the debug info.
195 let ptr = "Debug Info Version\0".as_ptr();
196 llvm::LLVMRustAddModuleFlag(cx.llmod(), ptr as *const _,
197 llvm::LLVMRustDebugMetadataVersion());
198 };
199 }
200
201 /// Creates the function-specific debug context.
202 ///
203 /// Returns the FunctionDebugContext for the function which holds state needed
204 /// for debug info creation. The function may also return another variant of the
205 /// FunctionDebugContext enum which indicates why no debuginfo should be created
206 /// for the function.
207 pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
208 fn_ast_id: ast::NodeId,
209 param_substs: &Substs<'tcx>,
210 llfn: ValueRef) -> FunctionDebugContext {
211 if cx.sess().opts.debuginfo == NoDebugInfo {
212 return FunctionDebugContext::DebugInfoDisabled;
213 }
214
215 // Clear the debug location so we don't assign them in the function prelude.
216 // Do this here already, in case we do an early exit from this function.
217 source_loc::set_debug_location(cx, InternalDebugLocation::UnknownLocation);
218
219 if fn_ast_id == ast::DUMMY_NODE_ID {
220 // This is a function not linked to any source location, so don't
221 // generate debuginfo for it.
222 return FunctionDebugContext::FunctionWithoutDebugInfo;
223 }
224
225 let empty_generics = ast_util::empty_generics();
226
227 let fnitem = cx.tcx().map.get(fn_ast_id);
228
229 let (name, fn_decl, generics, top_level_block, span, has_path) = match fnitem {
230 ast_map::NodeItem(ref item) => {
231 if contains_nodebug_attribute(&item.attrs) {
232 return FunctionDebugContext::FunctionWithoutDebugInfo;
233 }
234
235 match item.node {
236 ast::ItemFn(ref fn_decl, _, _, _, ref generics, ref top_level_block) => {
237 (item.ident.name, fn_decl, generics, top_level_block, item.span, true)
238 }
239 _ => {
240 cx.sess().span_bug(item.span,
241 "create_function_debug_context: item bound to non-function");
242 }
243 }
244 }
245 ast_map::NodeImplItem(impl_item) => {
246 match impl_item.node {
247 ast::MethodImplItem(ref sig, ref body) => {
248 if contains_nodebug_attribute(&impl_item.attrs) {
249 return FunctionDebugContext::FunctionWithoutDebugInfo;
250 }
251
252 (impl_item.ident.name,
253 &sig.decl,
254 &sig.generics,
255 body,
256 impl_item.span,
257 true)
258 }
259 _ => {
260 cx.sess().span_bug(impl_item.span,
261 "create_function_debug_context() \
262 called on non-method impl item?!")
263 }
264 }
265 }
266 ast_map::NodeExpr(ref expr) => {
267 match expr.node {
268 ast::ExprClosure(_, ref fn_decl, ref top_level_block) => {
269 let name = format!("fn{}", token::gensym("fn"));
270 let name = token::intern(&name[..]);
271 (name, fn_decl,
272 // This is not quite right. It should actually inherit
273 // the generics of the enclosing function.
274 &empty_generics,
275 top_level_block,
276 expr.span,
277 // Don't try to lookup the item path:
278 false)
279 }
280 _ => cx.sess().span_bug(expr.span,
281 "create_function_debug_context: expected an expr_fn_block here")
282 }
283 }
284 ast_map::NodeTraitItem(trait_item) => {
285 match trait_item.node {
286 ast::MethodTraitItem(ref sig, Some(ref body)) => {
287 if contains_nodebug_attribute(&trait_item.attrs) {
288 return FunctionDebugContext::FunctionWithoutDebugInfo;
289 }
290
291 (trait_item.ident.name,
292 &sig.decl,
293 &sig.generics,
294 body,
295 trait_item.span,
296 true)
297 }
298 _ => {
299 cx.sess()
300 .bug(&format!("create_function_debug_context: \
301 unexpected sort of node: {:?}",
302 fnitem))
303 }
304 }
305 }
306 ast_map::NodeForeignItem(..) |
307 ast_map::NodeVariant(..) |
308 ast_map::NodeStructCtor(..) => {
309 return FunctionDebugContext::FunctionWithoutDebugInfo;
310 }
311 _ => cx.sess().bug(&format!("create_function_debug_context: \
312 unexpected sort of node: {:?}",
313 fnitem))
314 };
315
316 // This can be the case for functions inlined from another crate
317 if span == codemap::DUMMY_SP {
318 return FunctionDebugContext::FunctionWithoutDebugInfo;
319 }
320
321 let loc = span_start(cx, span);
322 let file_metadata = file_metadata(cx, &loc.file.name);
323
324 let function_type_metadata = unsafe {
325 let fn_signature = get_function_signature(cx,
326 fn_ast_id,
327 &*fn_decl,
328 param_substs,
329 span);
330 llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
331 };
332
333 // Get_template_parameters() will append a `<...>` clause to the function
334 // name if necessary.
335 let mut function_name = String::from(&*token::get_name(name));
336 let template_parameters = get_template_parameters(cx,
337 generics,
338 param_substs,
339 file_metadata,
340 &mut function_name);
341
342 // There is no ast_map::Path for ast::ExprClosure-type functions. For now,
343 // just don't put them into a namespace. In the future this could be improved
344 // somehow (storing a path in the ast_map, or construct a path using the
345 // enclosing function).
346 let (linkage_name, containing_scope) = if has_path {
347 let namespace_node = namespace_for_item(cx, ast_util::local_def(fn_ast_id));
348 let linkage_name = namespace_node.mangled_name_of_contained_item(
349 &function_name[..]);
350 let containing_scope = namespace_node.scope;
351 (linkage_name, containing_scope)
352 } else {
353 (function_name.clone(), file_metadata)
354 };
355
356 // Clang sets this parameter to the opening brace of the function's block,
357 // so let's do this too.
358 let scope_line = span_start(cx, top_level_block.span).line;
359
360 let is_local_to_unit = is_node_local_to_unit(cx, fn_ast_id);
361
362 let function_name = CString::new(function_name).unwrap();
363 let linkage_name = CString::new(linkage_name).unwrap();
364 let fn_metadata = unsafe {
365 llvm::LLVMDIBuilderCreateFunction(
366 DIB(cx),
367 containing_scope,
368 function_name.as_ptr(),
369 linkage_name.as_ptr(),
370 file_metadata,
371 loc.line as c_uint,
372 function_type_metadata,
373 is_local_to_unit,
374 true,
375 scope_line as c_uint,
376 FlagPrototyped as c_uint,
377 cx.sess().opts.optimize != config::No,
378 llfn,
379 template_parameters,
380 ptr::null_mut())
381 };
382
383 let scope_map = create_scope_map::create_scope_map(cx,
384 &fn_decl.inputs,
385 &*top_level_block,
386 fn_metadata,
387 fn_ast_id);
388
389 // Initialize fn debug context (including scope map and namespace map)
390 let fn_debug_context = box FunctionDebugContextData {
391 scope_map: RefCell::new(scope_map),
392 fn_metadata: fn_metadata,
393 argument_counter: Cell::new(1),
394 source_locations_enabled: Cell::new(false),
395 source_location_override: Cell::new(false),
396 };
397
398
399
400 return FunctionDebugContext::RegularContext(fn_debug_context);
401
402 fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
403 fn_ast_id: ast::NodeId,
404 fn_decl: &ast::FnDecl,
405 param_substs: &Substs<'tcx>,
406 error_reporting_span: Span) -> DIArray {
407 if cx.sess().opts.debuginfo == LimitedDebugInfo {
408 return create_DIArray(DIB(cx), &[]);
409 }
410
411 let mut signature = Vec::with_capacity(fn_decl.inputs.len() + 1);
412
413 // Return type -- llvm::DIBuilder wants this at index 0
414 assert_type_for_node_id(cx, fn_ast_id, error_reporting_span);
415 let return_type = ty::node_id_to_type(cx.tcx(), fn_ast_id);
416 let return_type = monomorphize::apply_param_substs(cx.tcx(),
417 param_substs,
418 &return_type);
419 if ty::type_is_nil(return_type) {
420 signature.push(ptr::null_mut())
421 } else {
422 signature.push(type_metadata(cx, return_type, codemap::DUMMY_SP));
423 }
424
425 // Arguments types
426 for arg in &fn_decl.inputs {
427 assert_type_for_node_id(cx, arg.pat.id, arg.pat.span);
428 let arg_type = ty::node_id_to_type(cx.tcx(), arg.pat.id);
429 let arg_type = monomorphize::apply_param_substs(cx.tcx(),
430 param_substs,
431 &arg_type);
432 signature.push(type_metadata(cx, arg_type, codemap::DUMMY_SP));
433 }
434
435 return create_DIArray(DIB(cx), &signature[..]);
436 }
437
438 fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
439 generics: &ast::Generics,
440 param_substs: &Substs<'tcx>,
441 file_metadata: DIFile,
442 name_to_append_suffix_to: &mut String)
443 -> DIArray
444 {
445 let self_type = param_substs.self_ty();
446 let self_type = monomorphize::normalize_associated_type(cx.tcx(), &self_type);
447
448 // Only true for static default methods:
449 let has_self_type = self_type.is_some();
450
451 if !generics.is_type_parameterized() && !has_self_type {
452 return create_DIArray(DIB(cx), &[]);
453 }
454
455 name_to_append_suffix_to.push('<');
456
457 // The list to be filled with template parameters:
458 let mut template_params: Vec<DIDescriptor> =
459 Vec::with_capacity(generics.ty_params.len() + 1);
460
461 // Handle self type
462 if has_self_type {
463 let actual_self_type = self_type.unwrap();
464 // Add self type name to <...> clause of function name
465 let actual_self_type_name = compute_debuginfo_type_name(
466 cx,
467 actual_self_type,
468 true);
469
470 name_to_append_suffix_to.push_str(&actual_self_type_name[..]);
471
472 if generics.is_type_parameterized() {
473 name_to_append_suffix_to.push_str(",");
474 }
475
476 // Only create type information if full debuginfo is enabled
477 if cx.sess().opts.debuginfo == FullDebugInfo {
478 let actual_self_type_metadata = type_metadata(cx,
479 actual_self_type,
480 codemap::DUMMY_SP);
481
482 let name = token::get_name(special_idents::type_self.name);
483
484 let name = CString::new(name.as_bytes()).unwrap();
485 let param_metadata = unsafe {
486 llvm::LLVMDIBuilderCreateTemplateTypeParameter(
487 DIB(cx),
488 ptr::null_mut(),
489 name.as_ptr(),
490 actual_self_type_metadata,
491 file_metadata,
492 0,
493 0)
494 };
495
496 template_params.push(param_metadata);
497 }
498 }
499
500 // Handle other generic parameters
501 let actual_types = param_substs.types.get_slice(subst::FnSpace);
502 for (index, &ast::TyParam{ ident, .. }) in generics.ty_params.iter().enumerate() {
503 let actual_type = actual_types[index];
504 // Add actual type name to <...> clause of function name
505 let actual_type_name = compute_debuginfo_type_name(cx,
506 actual_type,
507 true);
508 name_to_append_suffix_to.push_str(&actual_type_name[..]);
509
510 if index != generics.ty_params.len() - 1 {
511 name_to_append_suffix_to.push_str(",");
512 }
513
514 // Again, only create type information if full debuginfo is enabled
515 if cx.sess().opts.debuginfo == FullDebugInfo {
516 let actual_type_metadata = type_metadata(cx, actual_type, codemap::DUMMY_SP);
517 let ident = token::get_ident(ident);
518 let name = CString::new(ident.as_bytes()).unwrap();
519 let param_metadata = unsafe {
520 llvm::LLVMDIBuilderCreateTemplateTypeParameter(
521 DIB(cx),
522 ptr::null_mut(),
523 name.as_ptr(),
524 actual_type_metadata,
525 file_metadata,
526 0,
527 0)
528 };
529 template_params.push(param_metadata);
530 }
531 }
532
533 name_to_append_suffix_to.push('>');
534
535 return create_DIArray(DIB(cx), &template_params[..]);
536 }
537 }
538
539 fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
540 variable_name: ast::Name,
541 variable_type: Ty<'tcx>,
542 scope_metadata: DIScope,
543 variable_access: VariableAccess,
544 variable_kind: VariableKind,
545 span: Span) {
546 let cx: &CrateContext = bcx.ccx();
547
548 let filename = span_start(cx, span).file.name.clone();
549 let file_metadata = file_metadata(cx, &filename[..]);
550
551 let name = token::get_name(variable_name);
552 let loc = span_start(cx, span);
553 let type_metadata = type_metadata(cx, variable_type, span);
554
555 let (argument_index, dwarf_tag) = match variable_kind {
556 ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
557 LocalVariable |
558 CapturedVariable => (0, DW_TAG_auto_variable)
559 };
560
561 let name = CString::new(name.as_bytes()).unwrap();
562 match (variable_access, &[][..]) {
563 (DirectVariable { alloca }, address_operations) |
564 (IndirectVariable {alloca, address_operations}, _) => {
565 let metadata = unsafe {
566 llvm::LLVMDIBuilderCreateVariable(
567 DIB(cx),
568 dwarf_tag,
569 scope_metadata,
570 name.as_ptr(),
571 file_metadata,
572 loc.line as c_uint,
573 type_metadata,
574 cx.sess().opts.optimize != config::No,
575 0,
576 address_operations.as_ptr(),
577 address_operations.len() as c_uint,
578 argument_index)
579 };
580 source_loc::set_debug_location(cx, InternalDebugLocation::new(scope_metadata,
581 loc.line,
582 loc.col.to_usize()));
583 unsafe {
584 let debug_loc = llvm::LLVMGetCurrentDebugLocation(cx.raw_builder());
585 let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
586 DIB(cx),
587 alloca,
588 metadata,
589 address_operations.as_ptr(),
590 address_operations.len() as c_uint,
591 debug_loc,
592 bcx.llbb);
593
594 llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
595 }
596 }
597 }
598
599 match variable_kind {
600 ArgumentVariable(_) | CapturedVariable => {
601 assert!(!bcx.fcx
602 .debug_context
603 .get_ref(cx, span)
604 .source_locations_enabled
605 .get());
606 source_loc::set_debug_location(cx, InternalDebugLocation::UnknownLocation);
607 }
608 _ => { /* nothing to do */ }
609 }
610 }
611
612 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
613 pub enum DebugLoc {
614 At(ast::NodeId, Span),
615 None
616 }
617
618 impl DebugLoc {
619 pub fn apply(&self, fcx: &FunctionContext) {
620 match *self {
621 DebugLoc::At(node_id, span) => {
622 source_loc::set_source_location(fcx, node_id, span);
623 }
624 DebugLoc::None => {
625 source_loc::clear_source_location(fcx);
626 }
627 }
628 }
629 }
630
631 pub trait ToDebugLoc {
632 fn debug_loc(&self) -> DebugLoc;
633 }
634
635 impl ToDebugLoc for ast::Expr {
636 fn debug_loc(&self) -> DebugLoc {
637 DebugLoc::At(self.id, self.span)
638 }
639 }
640
641 impl ToDebugLoc for NodeIdAndSpan {
642 fn debug_loc(&self) -> DebugLoc {
643 DebugLoc::At(self.id, self.span)
644 }
645 }
646
647 impl ToDebugLoc for Option<NodeIdAndSpan> {
648 fn debug_loc(&self) -> DebugLoc {
649 match *self {
650 Some(NodeIdAndSpan { id, span }) => DebugLoc::At(id, span),
651 None => DebugLoc::None
652 }
653 }
654 }