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.
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.
11 // See doc.rs for documentation.
14 use self::VariableAccess
::*;
15 use self::VariableKind
::*;
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, diverging_type_metadata}
;
22 use self::metadata
::{file_metadata, scope_metadata, TypeMap, compile_unit_metadata}
;
23 use self::source_loc
::InternalDebugLocation
;
26 use llvm
::{ModuleRef, ContextRef, ValueRef}
;
27 use llvm
::debuginfo
::{DIFile
, DIType
, DIScope
, DIBuilderRef
, DISubprogram
, DIArray
,
28 DIDescriptor
, FlagPrototyped
};
29 use rustc
::hir
::def_id
::DefId
;
30 use rustc
::infer
::normalize_associated_type
;
31 use rustc
::ty
::subst
::{self, Substs}
;
35 use common
::{NodeIdAndSpan, CrateContext, FunctionContext, Block}
;
38 use rustc
::ty
::{self, Ty}
;
39 use session
::config
::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}
;
40 use util
::nodemap
::{NodeMap, FnvHashMap, FnvHashSet}
;
41 use rustc
::hir
::map
as hir_map
;
44 use std
::cell
::{Cell, RefCell}
;
45 use std
::ffi
::CString
;
49 use syntax
::codemap
::{Span, Pos}
;
50 use syntax
::{ast, codemap}
;
51 use syntax
::attr
::IntType
;
52 use syntax
::parse
::token
::{self, special_idents}
;
62 pub use self::source_loc
::set_source_location
;
63 pub use self::source_loc
::clear_source_location
;
64 pub use self::source_loc
::start_emitting_source_locations
;
65 pub use self::source_loc
::get_cleanup_debug_loc_for_ast_node
;
66 pub use self::source_loc
::with_source_location_override
;
67 pub use self::metadata
::create_match_binding_metadata
;
68 pub use self::metadata
::create_argument_metadata
;
69 pub use self::metadata
::create_captured_var_metadata
;
70 pub use self::metadata
::create_global_var_metadata
;
71 pub use self::metadata
::create_local_var_metadata
;
73 #[allow(non_upper_case_globals)]
74 const DW_TAG_auto_variable
: c_uint
= 0x100;
75 #[allow(non_upper_case_globals)]
76 const DW_TAG_arg_variable
: c_uint
= 0x101;
78 /// A context object for maintaining all state needed by the debuginfo module.
79 pub struct CrateDebugContext
<'tcx
> {
80 llcontext
: ContextRef
,
81 builder
: DIBuilderRef
,
82 current_debug_location
: Cell
<InternalDebugLocation
>,
83 created_files
: RefCell
<FnvHashMap
<String
, DIFile
>>,
84 created_enum_disr_types
: RefCell
<FnvHashMap
<(DefId
, IntType
), DIType
>>,
86 type_map
: RefCell
<TypeMap
<'tcx
>>,
87 namespace_map
: RefCell
<FnvHashMap
<Vec
<ast
::Name
>, Rc
<NamespaceTreeNode
>>>,
89 // This collection is used to assert that composite types (structs, enums,
90 // ...) have their members only set once:
91 composite_types_completed
: RefCell
<FnvHashSet
<DIType
>>,
94 impl<'tcx
> CrateDebugContext
<'tcx
> {
95 pub fn new(llmod
: ModuleRef
) -> CrateDebugContext
<'tcx
> {
96 debug
!("CrateDebugContext::new");
97 let builder
= unsafe { llvm::LLVMDIBuilderCreate(llmod) }
;
98 // DIBuilder inherits context from the module, so we'd better use the same one
99 let llcontext
= unsafe { llvm::LLVMGetModuleContext(llmod) }
;
100 return CrateDebugContext
{
101 llcontext
: llcontext
,
103 current_debug_location
: Cell
::new(InternalDebugLocation
::UnknownLocation
),
104 created_files
: RefCell
::new(FnvHashMap()),
105 created_enum_disr_types
: RefCell
::new(FnvHashMap()),
106 type_map
: RefCell
::new(TypeMap
::new()),
107 namespace_map
: RefCell
::new(FnvHashMap()),
108 composite_types_completed
: RefCell
::new(FnvHashSet()),
113 pub enum FunctionDebugContext
{
114 RegularContext(Box
<FunctionDebugContextData
>),
116 FunctionWithoutDebugInfo
,
119 impl FunctionDebugContext
{
120 fn get_ref
<'a
>(&'a
self,
122 -> &'a FunctionDebugContextData
{
124 FunctionDebugContext
::RegularContext(box ref data
) => data
,
125 FunctionDebugContext
::DebugInfoDisabled
=> {
128 FunctionDebugContext
::debuginfo_disabled_message());
130 FunctionDebugContext
::FunctionWithoutDebugInfo
=> {
133 FunctionDebugContext
::should_be_ignored_message());
138 fn debuginfo_disabled_message() -> &'
static str {
139 "debuginfo: Error trying to access FunctionDebugContext although debug info is disabled!"
142 fn should_be_ignored_message() -> &'
static str {
143 "debuginfo: Error trying to access FunctionDebugContext for function that should be \
144 ignored by debug info!"
148 pub struct FunctionDebugContextData
{
149 scope_map
: RefCell
<NodeMap
<DIScope
>>,
150 fn_metadata
: DISubprogram
,
151 argument_counter
: Cell
<usize>,
152 source_locations_enabled
: Cell
<bool
>,
153 source_location_override
: Cell
<bool
>,
156 pub enum VariableAccess
<'a
> {
157 // The llptr given is an alloca containing the variable's value
158 DirectVariable { alloca: ValueRef }
,
159 // The llptr given is an alloca containing the start of some pointer chain
160 // leading to the variable's content.
161 IndirectVariable { alloca: ValueRef, address_operations: &'a [i64] }
164 pub enum VariableKind
{
165 ArgumentVariable(usize /*index*/),
170 /// Create any deferred debug metadata nodes
171 pub fn finalize(cx
: &CrateContext
) {
172 if cx
.dbg_cx().is_none() {
177 let _
= compile_unit_metadata(cx
);
179 if gdb
::needs_gdb_debug_scripts_section(cx
) {
180 // Add a .debug_gdb_scripts section to this compile-unit. This will
181 // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
182 // which activates the Rust pretty printers for binary this section is
184 gdb
::get_or_insert_gdb_debug_scripts_section_global(cx
);
188 llvm
::LLVMDIBuilderFinalize(DIB(cx
));
189 llvm
::LLVMDIBuilderDispose(DIB(cx
));
190 // Debuginfo generation in LLVM by default uses a higher
191 // version of dwarf than OS X currently understands. We can
192 // instruct LLVM to emit an older version of dwarf, however,
193 // for OS X to understand. For more info see #11352
194 // This can be overridden using --llvm-opts -dwarf-version,N.
195 // Android has the same issue (#22398)
196 if cx
.sess().target
.target
.options
.is_like_osx
||
197 cx
.sess().target
.target
.options
.is_like_android
{
198 llvm
::LLVMRustAddModuleFlag(cx
.llmod(),
199 "Dwarf Version\0".as_ptr() as *const _
,
203 // Indicate that we want CodeView debug information on MSVC
204 if cx
.sess().target
.target
.options
.is_like_msvc
{
205 llvm
::LLVMRustAddModuleFlag(cx
.llmod(),
206 "CodeView\0".as_ptr() as *const _
,
210 // Prevent bitcode readers from deleting the debug info.
211 let ptr
= "Debug Info Version\0".as_ptr();
212 llvm
::LLVMRustAddModuleFlag(cx
.llmod(), ptr
as *const _
,
213 llvm
::LLVMRustDebugMetadataVersion());
217 /// Creates the function-specific debug context.
219 /// Returns the FunctionDebugContext for the function which holds state needed
220 /// for debug info creation. The function may also return another variant of the
221 /// FunctionDebugContext enum which indicates why no debuginfo should be created
222 /// for the function.
223 pub fn create_function_debug_context
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
224 fn_ast_id
: ast
::NodeId
,
225 param_substs
: &Substs
<'tcx
>,
226 llfn
: ValueRef
) -> FunctionDebugContext
{
227 if cx
.sess().opts
.debuginfo
== NoDebugInfo
{
228 return FunctionDebugContext
::DebugInfoDisabled
;
231 // Clear the debug location so we don't assign them in the function prelude.
232 // Do this here already, in case we do an early exit from this function.
233 source_loc
::set_debug_location(cx
, InternalDebugLocation
::UnknownLocation
);
235 if fn_ast_id
== ast
::DUMMY_NODE_ID
{
236 // This is a function not linked to any source location, so don't
237 // generate debuginfo for it.
238 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
241 let empty_generics
= hir
::Generics
::empty();
243 let fnitem
= cx
.tcx().map
.get(fn_ast_id
);
245 let (name
, fn_decl
, generics
, top_level_block
, span
, has_path
) = match fnitem
{
246 hir_map
::NodeItem(ref item
) => {
247 if contains_nodebug_attribute(&item
.attrs
) {
248 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
252 hir
::ItemFn(ref fn_decl
, _
, _
, _
, ref generics
, ref top_level_block
) => {
253 (item
.name
, fn_decl
, generics
, top_level_block
, item
.span
, true)
257 "create_function_debug_context: item bound to non-function");
261 hir_map
::NodeImplItem(impl_item
) => {
262 match impl_item
.node
{
263 hir
::ImplItemKind
::Method(ref sig
, ref body
) => {
264 if contains_nodebug_attribute(&impl_item
.attrs
) {
265 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
276 span_bug
!(impl_item
.span
,
277 "create_function_debug_context() \
278 called on non-method impl item?!")
282 hir_map
::NodeExpr(ref expr
) => {
284 hir
::ExprClosure(_
, ref fn_decl
, ref top_level_block
) => {
285 let name
= format
!("fn{}", token
::gensym("fn"));
286 let name
= token
::intern(&name
[..]);
288 // This is not quite right. It should actually inherit
289 // the generics of the enclosing function.
293 // Don't try to lookup the item path:
296 _
=> span_bug
!(expr
.span
,
297 "create_function_debug_context: expected an expr_fn_block here")
300 hir_map
::NodeTraitItem(trait_item
) => {
301 match trait_item
.node
{
302 hir
::MethodTraitItem(ref sig
, Some(ref body
)) => {
303 if contains_nodebug_attribute(&trait_item
.attrs
) {
304 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
315 bug
!("create_function_debug_context: \
316 unexpected sort of node: {:?}",
321 hir_map
::NodeForeignItem(..) |
322 hir_map
::NodeVariant(..) |
323 hir_map
::NodeStructCtor(..) => {
324 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
326 _
=> bug
!("create_function_debug_context: \
327 unexpected sort of node: {:?}",
331 // This can be the case for functions inlined from another crate
332 if span
== codemap
::DUMMY_SP
{
333 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
336 let loc
= span_start(cx
, span
);
337 let file_metadata
= file_metadata(cx
, &loc
.file
.name
);
339 let function_type_metadata
= unsafe {
340 let fn_signature
= get_function_signature(cx
,
344 llvm
::LLVMDIBuilderCreateSubroutineType(DIB(cx
), file_metadata
, fn_signature
)
347 // Get_template_parameters() will append a `<...>` clause to the function
348 // name if necessary.
349 let mut function_name
= name
.to_string();
350 let template_parameters
= get_template_parameters(cx
,
356 // There is no hir_map::Path for hir::ExprClosure-type functions. For now,
357 // just don't put them into a namespace. In the future this could be improved
358 // somehow (storing a path in the hir_map, or construct a path using the
359 // enclosing function).
360 let (linkage_name
, containing_scope
) = if has_path
{
361 let fn_ast_def_id
= cx
.tcx().map
.local_def_id(fn_ast_id
);
362 let namespace_node
= namespace_for_item(cx
, fn_ast_def_id
);
363 let linkage_name
= namespace_node
.mangled_name_of_contained_item(
365 let containing_scope
= namespace_node
.scope
;
366 (linkage_name
, containing_scope
)
368 (function_name
.clone(), file_metadata
)
371 // Clang sets this parameter to the opening brace of the function's block,
372 // so let's do this too.
373 let scope_line
= span_start(cx
, top_level_block
.span
).line
;
375 let is_local_to_unit
= is_node_local_to_unit(cx
, fn_ast_id
);
377 let function_name
= CString
::new(function_name
).unwrap();
378 let linkage_name
= CString
::new(linkage_name
).unwrap();
379 let fn_metadata
= unsafe {
380 llvm
::LLVMDIBuilderCreateFunction(
383 function_name
.as_ptr(),
384 linkage_name
.as_ptr(),
387 function_type_metadata
,
390 scope_line
as c_uint
,
391 FlagPrototyped
as c_uint
,
392 cx
.sess().opts
.optimize
!= config
::OptLevel
::No
,
398 let scope_map
= create_scope_map
::create_scope_map(cx
,
404 // Initialize fn debug context (including scope map and namespace map)
405 let fn_debug_context
= box FunctionDebugContextData
{
406 scope_map
: RefCell
::new(scope_map
),
407 fn_metadata
: fn_metadata
,
408 argument_counter
: Cell
::new(1),
409 source_locations_enabled
: Cell
::new(false),
410 source_location_override
: Cell
::new(false),
415 return FunctionDebugContext
::RegularContext(fn_debug_context
);
417 fn get_function_signature
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
418 fn_ast_id
: ast
::NodeId
,
419 param_substs
: &Substs
<'tcx
>,
420 error_reporting_span
: Span
) -> DIArray
{
421 if cx
.sess().opts
.debuginfo
== LimitedDebugInfo
{
422 return create_DIArray(DIB(cx
), &[]);
425 // Return type -- llvm::DIBuilder wants this at index 0
426 assert_type_for_node_id(cx
, fn_ast_id
, error_reporting_span
);
427 let fn_type
= cx
.tcx().node_id_to_type(fn_ast_id
);
428 let fn_type
= monomorphize
::apply_param_substs(cx
.tcx(), param_substs
, &fn_type
);
430 let (sig
, abi
) = match fn_type
.sty
{
431 ty
::TyFnDef(_
, _
, ref barefnty
) | ty
::TyFnPtr(ref barefnty
) => {
432 let sig
= cx
.tcx().erase_late_bound_regions(&barefnty
.sig
);
433 let sig
= infer
::normalize_associated_type(cx
.tcx(), &sig
);
436 ty
::TyClosure(def_id
, ref substs
) => {
437 let closure_type
= cx
.tcx().closure_type(def_id
, substs
);
438 let sig
= cx
.tcx().erase_late_bound_regions(&closure_type
.sig
);
439 let sig
= infer
::normalize_associated_type(cx
.tcx(), &sig
);
440 (sig
, closure_type
.abi
)
443 _
=> bug
!("get_function_metdata: Expected a function type!")
446 let mut signature
= Vec
::with_capacity(sig
.inputs
.len() + 1);
448 // Return type -- llvm::DIBuilder wants this at index 0
449 signature
.push(match sig
.output
{
450 ty
::FnConverging(ret_ty
) => match ret_ty
.sty
{
451 ty
::TyTuple(ref tys
) if tys
.is_empty() => ptr
::null_mut(),
452 _
=> type_metadata(cx
, ret_ty
, codemap
::DUMMY_SP
)
454 ty
::FnDiverging
=> diverging_type_metadata(cx
)
457 let inputs
= if abi
== Abi
::RustCall
{
458 &sig
.inputs
[..sig
.inputs
.len()-1]
464 for &argument_type
in inputs
{
465 signature
.push(type_metadata(cx
, argument_type
, codemap
::DUMMY_SP
));
468 if abi
== Abi
::RustCall
&& !sig
.inputs
.is_empty() {
469 if let ty
::TyTuple(ref args
) = sig
.inputs
[sig
.inputs
.len() - 1].sty
{
470 for &argument_type
in args
{
471 signature
.push(type_metadata(cx
, argument_type
, codemap
::DUMMY_SP
));
476 return create_DIArray(DIB(cx
), &signature
[..]);
479 fn get_template_parameters
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
480 generics
: &hir
::Generics
,
481 param_substs
: &Substs
<'tcx
>,
482 file_metadata
: DIFile
,
483 name_to_append_suffix_to
: &mut String
)
486 let self_type
= param_substs
.self_ty();
487 let self_type
= normalize_associated_type(cx
.tcx(), &self_type
);
489 // Only true for static default methods:
490 let has_self_type
= self_type
.is_some();
492 if !generics
.is_type_parameterized() && !has_self_type
{
493 return create_DIArray(DIB(cx
), &[]);
496 name_to_append_suffix_to
.push('
<'
);
498 // The list to be filled with template parameters:
499 let mut template_params
: Vec
<DIDescriptor
> =
500 Vec
::with_capacity(generics
.ty_params
.len() + 1);
504 let actual_self_type
= self_type
.unwrap();
505 // Add self type name to <...> clause of function name
506 let actual_self_type_name
= compute_debuginfo_type_name(
511 name_to_append_suffix_to
.push_str(&actual_self_type_name
[..]);
513 if generics
.is_type_parameterized() {
514 name_to_append_suffix_to
.push_str(",");
517 // Only create type information if full debuginfo is enabled
518 if cx
.sess().opts
.debuginfo
== FullDebugInfo
{
519 let actual_self_type_metadata
= type_metadata(cx
,
523 let name
= special_idents
::type_self
.name
.as_str();
525 let name
= CString
::new(name
.as_bytes()).unwrap();
526 let param_metadata
= unsafe {
527 llvm
::LLVMDIBuilderCreateTemplateTypeParameter(
531 actual_self_type_metadata
,
537 template_params
.push(param_metadata
);
541 // Handle other generic parameters
542 let actual_types
= param_substs
.types
.get_slice(subst
::FnSpace
);
543 for (index
, &hir
::TyParam{ name, .. }
) in generics
.ty_params
.iter().enumerate() {
544 let actual_type
= actual_types
[index
];
545 // Add actual type name to <...> clause of function name
546 let actual_type_name
= compute_debuginfo_type_name(cx
,
549 name_to_append_suffix_to
.push_str(&actual_type_name
[..]);
551 if index
!= generics
.ty_params
.len() - 1 {
552 name_to_append_suffix_to
.push_str(",");
555 // Again, only create type information if full debuginfo is enabled
556 if cx
.sess().opts
.debuginfo
== FullDebugInfo
{
557 let actual_type_metadata
= type_metadata(cx
, actual_type
, codemap
::DUMMY_SP
);
558 let name
= CString
::new(name
.as_str().as_bytes()).unwrap();
559 let param_metadata
= unsafe {
560 llvm
::LLVMDIBuilderCreateTemplateTypeParameter(
564 actual_type_metadata
,
569 template_params
.push(param_metadata
);
573 name_to_append_suffix_to
.push('
>'
);
575 return create_DIArray(DIB(cx
), &template_params
[..]);
579 fn declare_local
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
580 variable_name
: ast
::Name
,
581 variable_type
: Ty
<'tcx
>,
582 scope_metadata
: DIScope
,
583 variable_access
: VariableAccess
,
584 variable_kind
: VariableKind
,
586 let cx
: &CrateContext
= bcx
.ccx();
588 let filename
= span_start(cx
, span
).file
.name
.clone();
589 let file_metadata
= file_metadata(cx
, &filename
[..]);
591 let loc
= span_start(cx
, span
);
592 let type_metadata
= type_metadata(cx
, variable_type
, span
);
594 let (argument_index
, dwarf_tag
) = match variable_kind
{
595 ArgumentVariable(index
) => (index
as c_uint
, DW_TAG_arg_variable
),
597 CapturedVariable
=> (0, DW_TAG_auto_variable
)
600 let name
= CString
::new(variable_name
.as_str().as_bytes()).unwrap();
601 match (variable_access
, &[][..]) {
602 (DirectVariable { alloca }
, address_operations
) |
603 (IndirectVariable {alloca, address_operations}
, _
) => {
604 let metadata
= unsafe {
605 llvm
::LLVMDIBuilderCreateVariable(
613 cx
.sess().opts
.optimize
!= config
::OptLevel
::No
,
615 address_operations
.as_ptr(),
616 address_operations
.len() as c_uint
,
619 source_loc
::set_debug_location(cx
, InternalDebugLocation
::new(scope_metadata
,
621 loc
.col
.to_usize()));
623 let debug_loc
= llvm
::LLVMGetCurrentDebugLocation(cx
.raw_builder());
624 let instr
= llvm
::LLVMDIBuilderInsertDeclareAtEnd(
628 address_operations
.as_ptr(),
629 address_operations
.len() as c_uint
,
633 llvm
::LLVMSetInstDebugLocation(::build
::B(bcx
).llbuilder
, instr
);
638 match variable_kind
{
639 ArgumentVariable(_
) | CapturedVariable
=> {
643 .source_locations_enabled
645 source_loc
::set_debug_location(cx
, InternalDebugLocation
::UnknownLocation
);
647 _
=> { /* nothing to do */ }
651 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
653 At(ast
::NodeId
, Span
),
658 pub fn apply(&self, fcx
: &FunctionContext
) {
660 DebugLoc
::At(node_id
, span
) => {
661 source_loc
::set_source_location(fcx
, node_id
, span
);
664 source_loc
::clear_source_location(fcx
);
670 pub trait ToDebugLoc
{
671 fn debug_loc(&self) -> DebugLoc
;
674 impl ToDebugLoc
for hir
::Expr
{
675 fn debug_loc(&self) -> DebugLoc
{
676 DebugLoc
::At(self.id
, self.span
)
680 impl ToDebugLoc
for NodeIdAndSpan
{
681 fn debug_loc(&self) -> DebugLoc
{
682 DebugLoc
::At(self.id
, self.span
)
686 impl ToDebugLoc
for Option
<NodeIdAndSpan
> {
687 fn debug_loc(&self) -> DebugLoc
{
689 Some(NodeIdAndSpan { id, span }
) => DebugLoc
::At(id
, span
),
690 None
=> DebugLoc
::None