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 middle
::def_id
::DefId
;
30 use middle
::infer
::normalize_associated_type
;
31 use middle
::subst
::{self, Substs}
;
35 use trans
::common
::{NodeIdAndSpan, CrateContext, FunctionContext, Block}
;
37 use trans
::{monomorphize, type_of}
;
39 use middle
::ty
::{self, Ty}
;
40 use session
::config
::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}
;
41 use util
::nodemap
::{NodeMap, FnvHashMap, FnvHashSet}
;
42 use rustc
::front
::map
as hir_map
;
45 use std
::cell
::{Cell, RefCell}
;
46 use std
::ffi
::CString
;
50 use syntax
::codemap
::{Span, Pos}
;
51 use syntax
::{ast, codemap}
;
53 use syntax
::attr
::IntType
;
54 use syntax
::parse
::token
::{self, special_idents}
;
64 pub use self::source_loc
::set_source_location
;
65 pub use self::source_loc
::clear_source_location
;
66 pub use self::source_loc
::start_emitting_source_locations
;
67 pub use self::source_loc
::get_cleanup_debug_loc_for_ast_node
;
68 pub use self::source_loc
::with_source_location_override
;
69 pub use self::metadata
::create_match_binding_metadata
;
70 pub use self::metadata
::create_argument_metadata
;
71 pub use self::metadata
::create_captured_var_metadata
;
72 pub use self::metadata
::create_global_var_metadata
;
73 pub use self::metadata
::create_local_var_metadata
;
75 #[allow(non_upper_case_globals)]
76 const DW_TAG_auto_variable
: c_uint
= 0x100;
77 #[allow(non_upper_case_globals)]
78 const DW_TAG_arg_variable
: c_uint
= 0x101;
80 /// A context object for maintaining all state needed by the debuginfo module.
81 pub struct CrateDebugContext
<'tcx
> {
82 llcontext
: ContextRef
,
83 builder
: DIBuilderRef
,
84 current_debug_location
: Cell
<InternalDebugLocation
>,
85 created_files
: RefCell
<FnvHashMap
<String
, DIFile
>>,
86 created_enum_disr_types
: RefCell
<FnvHashMap
<(DefId
, IntType
), DIType
>>,
88 type_map
: RefCell
<TypeMap
<'tcx
>>,
89 namespace_map
: RefCell
<FnvHashMap
<Vec
<ast
::Name
>, Rc
<NamespaceTreeNode
>>>,
91 // This collection is used to assert that composite types (structs, enums,
92 // ...) have their members only set once:
93 composite_types_completed
: RefCell
<FnvHashSet
<DIType
>>,
96 impl<'tcx
> CrateDebugContext
<'tcx
> {
97 pub fn new(llmod
: ModuleRef
) -> CrateDebugContext
<'tcx
> {
98 debug
!("CrateDebugContext::new");
99 let builder
= unsafe { llvm::LLVMDIBuilderCreate(llmod) }
;
100 // DIBuilder inherits context from the module, so we'd better use the same one
101 let llcontext
= unsafe { llvm::LLVMGetModuleContext(llmod) }
;
102 return CrateDebugContext
{
103 llcontext
: llcontext
,
105 current_debug_location
: Cell
::new(InternalDebugLocation
::UnknownLocation
),
106 created_files
: RefCell
::new(FnvHashMap()),
107 created_enum_disr_types
: RefCell
::new(FnvHashMap()),
108 type_map
: RefCell
::new(TypeMap
::new()),
109 namespace_map
: RefCell
::new(FnvHashMap()),
110 composite_types_completed
: RefCell
::new(FnvHashSet()),
115 pub enum FunctionDebugContext
{
116 RegularContext(Box
<FunctionDebugContextData
>),
118 FunctionWithoutDebugInfo
,
121 impl FunctionDebugContext
{
122 fn get_ref
<'a
>(&'a
self,
125 -> &'a FunctionDebugContextData
{
127 FunctionDebugContext
::RegularContext(box ref data
) => data
,
128 FunctionDebugContext
::DebugInfoDisabled
=> {
129 cx
.sess().span_bug(span
,
130 FunctionDebugContext
::debuginfo_disabled_message());
132 FunctionDebugContext
::FunctionWithoutDebugInfo
=> {
133 cx
.sess().span_bug(span
,
134 FunctionDebugContext
::should_be_ignored_message());
139 fn debuginfo_disabled_message() -> &'
static str {
140 "debuginfo: Error trying to access FunctionDebugContext although debug info is disabled!"
143 fn should_be_ignored_message() -> &'
static str {
144 "debuginfo: Error trying to access FunctionDebugContext for function that should be \
145 ignored by debug info!"
149 pub struct FunctionDebugContextData
{
150 scope_map
: RefCell
<NodeMap
<DIScope
>>,
151 fn_metadata
: DISubprogram
,
152 argument_counter
: Cell
<usize>,
153 source_locations_enabled
: Cell
<bool
>,
154 source_location_override
: Cell
<bool
>,
157 pub enum VariableAccess
<'a
> {
158 // The llptr given is an alloca containing the variable's value
159 DirectVariable { alloca: ValueRef }
,
160 // The llptr given is an alloca containing the start of some pointer chain
161 // leading to the variable's content.
162 IndirectVariable { alloca: ValueRef, address_operations: &'a [i64] }
165 pub enum VariableKind
{
166 ArgumentVariable(usize /*index*/),
171 /// Create any deferred debug metadata nodes
172 pub fn finalize(cx
: &CrateContext
) {
173 if cx
.dbg_cx().is_none() {
178 let _
= compile_unit_metadata(cx
);
180 if gdb
::needs_gdb_debug_scripts_section(cx
) {
181 // Add a .debug_gdb_scripts section to this compile-unit. This will
182 // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
183 // which activates the Rust pretty printers for binary this section is
185 gdb
::get_or_insert_gdb_debug_scripts_section_global(cx
);
189 llvm
::LLVMDIBuilderFinalize(DIB(cx
));
190 llvm
::LLVMDIBuilderDispose(DIB(cx
));
191 // Debuginfo generation in LLVM by default uses a higher
192 // version of dwarf than OS X currently understands. We can
193 // instruct LLVM to emit an older version of dwarf, however,
194 // for OS X to understand. For more info see #11352
195 // This can be overridden using --llvm-opts -dwarf-version,N.
196 // Android has the same issue (#22398)
197 if cx
.sess().target
.target
.options
.is_like_osx
||
198 cx
.sess().target
.target
.options
.is_like_android
{
199 llvm
::LLVMRustAddModuleFlag(cx
.llmod(),
200 "Dwarf Version\0".as_ptr() as *const _
,
204 // Indicate that we want CodeView debug information on MSVC
205 if cx
.sess().target
.target
.options
.is_like_msvc
{
206 llvm
::LLVMRustAddModuleFlag(cx
.llmod(),
207 "CodeView\0".as_ptr() as *const _
,
211 // Prevent bitcode readers from deleting the debug info.
212 let ptr
= "Debug Info Version\0".as_ptr();
213 llvm
::LLVMRustAddModuleFlag(cx
.llmod(), ptr
as *const _
,
214 llvm
::LLVMRustDebugMetadataVersion());
218 /// Creates the function-specific debug context.
220 /// Returns the FunctionDebugContext for the function which holds state needed
221 /// for debug info creation. The function may also return another variant of the
222 /// FunctionDebugContext enum which indicates why no debuginfo should be created
223 /// for the function.
224 pub fn create_function_debug_context
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
225 fn_ast_id
: ast
::NodeId
,
226 param_substs
: &Substs
<'tcx
>,
227 llfn
: ValueRef
) -> FunctionDebugContext
{
228 if cx
.sess().opts
.debuginfo
== NoDebugInfo
{
229 return FunctionDebugContext
::DebugInfoDisabled
;
232 // Clear the debug location so we don't assign them in the function prelude.
233 // Do this here already, in case we do an early exit from this function.
234 source_loc
::set_debug_location(cx
, InternalDebugLocation
::UnknownLocation
);
236 if fn_ast_id
== ast
::DUMMY_NODE_ID
{
237 // This is a function not linked to any source location, so don't
238 // generate debuginfo for it.
239 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
242 let empty_generics
= rustc_front
::util
::empty_generics();
244 let fnitem
= cx
.tcx().map
.get(fn_ast_id
);
246 let (name
, fn_decl
, generics
, top_level_block
, span
, has_path
) = match fnitem
{
247 hir_map
::NodeItem(ref item
) => {
248 if contains_nodebug_attribute(&item
.attrs
) {
249 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
253 hir
::ItemFn(ref fn_decl
, _
, _
, _
, ref generics
, ref top_level_block
) => {
254 (item
.name
, fn_decl
, generics
, top_level_block
, item
.span
, true)
257 cx
.sess().span_bug(item
.span
,
258 "create_function_debug_context: item bound to non-function");
262 hir_map
::NodeImplItem(impl_item
) => {
263 match impl_item
.node
{
264 hir
::ImplItemKind
::Method(ref sig
, ref body
) => {
265 if contains_nodebug_attribute(&impl_item
.attrs
) {
266 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
277 cx
.sess().span_bug(impl_item
.span
,
278 "create_function_debug_context() \
279 called on non-method impl item?!")
283 hir_map
::NodeExpr(ref expr
) => {
285 hir
::ExprClosure(_
, ref fn_decl
, ref top_level_block
) => {
286 let name
= format
!("fn{}", token
::gensym("fn"));
287 let name
= token
::intern(&name
[..]);
289 // This is not quite right. It should actually inherit
290 // the generics of the enclosing function.
294 // Don't try to lookup the item path:
297 _
=> cx
.sess().span_bug(expr
.span
,
298 "create_function_debug_context: expected an expr_fn_block here")
301 hir_map
::NodeTraitItem(trait_item
) => {
302 match trait_item
.node
{
303 hir
::MethodTraitItem(ref sig
, Some(ref body
)) => {
304 if contains_nodebug_attribute(&trait_item
.attrs
) {
305 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
317 .bug(&format
!("create_function_debug_context: \
318 unexpected sort of node: {:?}",
323 hir_map
::NodeForeignItem(..) |
324 hir_map
::NodeVariant(..) |
325 hir_map
::NodeStructCtor(..) => {
326 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
328 _
=> cx
.sess().bug(&format
!("create_function_debug_context: \
329 unexpected sort of node: {:?}",
333 // This can be the case for functions inlined from another crate
334 if span
== codemap
::DUMMY_SP
{
335 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
338 let loc
= span_start(cx
, span
);
339 let file_metadata
= file_metadata(cx
, &loc
.file
.name
);
341 let function_type_metadata
= unsafe {
342 let fn_signature
= get_function_signature(cx
,
346 llvm
::LLVMDIBuilderCreateSubroutineType(DIB(cx
), file_metadata
, fn_signature
)
349 // Get_template_parameters() will append a `<...>` clause to the function
350 // name if necessary.
351 let mut function_name
= name
.to_string();
352 let template_parameters
= get_template_parameters(cx
,
358 // There is no hir_map::Path for hir::ExprClosure-type functions. For now,
359 // just don't put them into a namespace. In the future this could be improved
360 // somehow (storing a path in the hir_map, or construct a path using the
361 // enclosing function).
362 let (linkage_name
, containing_scope
) = if has_path
{
363 let fn_ast_def_id
= cx
.tcx().map
.local_def_id(fn_ast_id
);
364 let namespace_node
= namespace_for_item(cx
, fn_ast_def_id
);
365 let linkage_name
= namespace_node
.mangled_name_of_contained_item(
367 let containing_scope
= namespace_node
.scope
;
368 (linkage_name
, containing_scope
)
370 (function_name
.clone(), file_metadata
)
373 // Clang sets this parameter to the opening brace of the function's block,
374 // so let's do this too.
375 let scope_line
= span_start(cx
, top_level_block
.span
).line
;
377 let is_local_to_unit
= is_node_local_to_unit(cx
, fn_ast_id
);
379 let function_name
= CString
::new(function_name
).unwrap();
380 let linkage_name
= CString
::new(linkage_name
).unwrap();
381 let fn_metadata
= unsafe {
382 llvm
::LLVMDIBuilderCreateFunction(
385 function_name
.as_ptr(),
386 linkage_name
.as_ptr(),
389 function_type_metadata
,
392 scope_line
as c_uint
,
393 FlagPrototyped
as c_uint
,
394 cx
.sess().opts
.optimize
!= config
::OptLevel
::No
,
400 let scope_map
= create_scope_map
::create_scope_map(cx
,
406 // Initialize fn debug context (including scope map and namespace map)
407 let fn_debug_context
= box FunctionDebugContextData
{
408 scope_map
: RefCell
::new(scope_map
),
409 fn_metadata
: fn_metadata
,
410 argument_counter
: Cell
::new(1),
411 source_locations_enabled
: Cell
::new(false),
412 source_location_override
: Cell
::new(false),
417 return FunctionDebugContext
::RegularContext(fn_debug_context
);
419 fn get_function_signature
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
420 fn_ast_id
: ast
::NodeId
,
421 param_substs
: &Substs
<'tcx
>,
422 error_reporting_span
: Span
) -> DIArray
{
423 if cx
.sess().opts
.debuginfo
== LimitedDebugInfo
{
424 return create_DIArray(DIB(cx
), &[]);
427 // Return type -- llvm::DIBuilder wants this at index 0
428 assert_type_for_node_id(cx
, fn_ast_id
, error_reporting_span
);
429 let fn_type
= cx
.tcx().node_id_to_type(fn_ast_id
);
430 let fn_type
= monomorphize
::apply_param_substs(cx
.tcx(), param_substs
, &fn_type
);
432 let (sig
, abi
) = match fn_type
.sty
{
433 ty
::TyBareFn(_
, ref barefnty
) => {
434 let sig
= cx
.tcx().erase_late_bound_regions(&barefnty
.sig
);
435 let sig
= infer
::normalize_associated_type(cx
.tcx(), &sig
);
438 ty
::TyClosure(def_id
, ref substs
) => {
439 let closure_type
= cx
.tcx().closure_type(def_id
, substs
);
440 let sig
= cx
.tcx().erase_late_bound_regions(&closure_type
.sig
);
441 let sig
= infer
::normalize_associated_type(cx
.tcx(), &sig
);
442 (sig
, closure_type
.abi
)
445 _
=> cx
.sess().bug("get_function_metdata: Expected a function type!")
448 let mut signature
= Vec
::with_capacity(sig
.inputs
.len() + 1);
450 // Return type -- llvm::DIBuilder wants this at index 0
451 signature
.push(match sig
.output
{
452 ty
::FnConverging(ret_ty
) => match ret_ty
.sty
{
453 ty
::TyTuple(ref tys
) if tys
.is_empty() => ptr
::null_mut(),
454 _
=> type_metadata(cx
, ret_ty
, codemap
::DUMMY_SP
)
456 ty
::FnDiverging
=> diverging_type_metadata(cx
)
459 let inputs
= &if abi
== Abi
::RustCall
{
460 type_of
::untuple_arguments(cx
, &sig
.inputs
)
466 for &argument_type
in inputs
{
467 signature
.push(type_metadata(cx
, argument_type
, codemap
::DUMMY_SP
));
470 return create_DIArray(DIB(cx
), &signature
[..]);
473 fn get_template_parameters
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
474 generics
: &hir
::Generics
,
475 param_substs
: &Substs
<'tcx
>,
476 file_metadata
: DIFile
,
477 name_to_append_suffix_to
: &mut String
)
480 let self_type
= param_substs
.self_ty();
481 let self_type
= normalize_associated_type(cx
.tcx(), &self_type
);
483 // Only true for static default methods:
484 let has_self_type
= self_type
.is_some();
486 if !generics
.is_type_parameterized() && !has_self_type
{
487 return create_DIArray(DIB(cx
), &[]);
490 name_to_append_suffix_to
.push('
<'
);
492 // The list to be filled with template parameters:
493 let mut template_params
: Vec
<DIDescriptor
> =
494 Vec
::with_capacity(generics
.ty_params
.len() + 1);
498 let actual_self_type
= self_type
.unwrap();
499 // Add self type name to <...> clause of function name
500 let actual_self_type_name
= compute_debuginfo_type_name(
505 name_to_append_suffix_to
.push_str(&actual_self_type_name
[..]);
507 if generics
.is_type_parameterized() {
508 name_to_append_suffix_to
.push_str(",");
511 // Only create type information if full debuginfo is enabled
512 if cx
.sess().opts
.debuginfo
== FullDebugInfo
{
513 let actual_self_type_metadata
= type_metadata(cx
,
517 let name
= special_idents
::type_self
.name
.as_str();
519 let name
= CString
::new(name
.as_bytes()).unwrap();
520 let param_metadata
= unsafe {
521 llvm
::LLVMDIBuilderCreateTemplateTypeParameter(
525 actual_self_type_metadata
,
531 template_params
.push(param_metadata
);
535 // Handle other generic parameters
536 let actual_types
= param_substs
.types
.get_slice(subst
::FnSpace
);
537 for (index
, &hir
::TyParam{ name, .. }
) in generics
.ty_params
.iter().enumerate() {
538 let actual_type
= actual_types
[index
];
539 // Add actual type name to <...> clause of function name
540 let actual_type_name
= compute_debuginfo_type_name(cx
,
543 name_to_append_suffix_to
.push_str(&actual_type_name
[..]);
545 if index
!= generics
.ty_params
.len() - 1 {
546 name_to_append_suffix_to
.push_str(",");
549 // Again, only create type information if full debuginfo is enabled
550 if cx
.sess().opts
.debuginfo
== FullDebugInfo
{
551 let actual_type_metadata
= type_metadata(cx
, actual_type
, codemap
::DUMMY_SP
);
552 let name
= CString
::new(name
.as_str().as_bytes()).unwrap();
553 let param_metadata
= unsafe {
554 llvm
::LLVMDIBuilderCreateTemplateTypeParameter(
558 actual_type_metadata
,
563 template_params
.push(param_metadata
);
567 name_to_append_suffix_to
.push('
>'
);
569 return create_DIArray(DIB(cx
), &template_params
[..]);
573 fn declare_local
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
574 variable_name
: ast
::Name
,
575 variable_type
: Ty
<'tcx
>,
576 scope_metadata
: DIScope
,
577 variable_access
: VariableAccess
,
578 variable_kind
: VariableKind
,
580 let cx
: &CrateContext
= bcx
.ccx();
582 let filename
= span_start(cx
, span
).file
.name
.clone();
583 let file_metadata
= file_metadata(cx
, &filename
[..]);
585 let loc
= span_start(cx
, span
);
586 let type_metadata
= type_metadata(cx
, variable_type
, span
);
588 let (argument_index
, dwarf_tag
) = match variable_kind
{
589 ArgumentVariable(index
) => (index
as c_uint
, DW_TAG_arg_variable
),
591 CapturedVariable
=> (0, DW_TAG_auto_variable
)
594 let name
= CString
::new(variable_name
.as_str().as_bytes()).unwrap();
595 match (variable_access
, &[][..]) {
596 (DirectVariable { alloca }
, address_operations
) |
597 (IndirectVariable {alloca, address_operations}
, _
) => {
598 let metadata
= unsafe {
599 llvm
::LLVMDIBuilderCreateVariable(
607 cx
.sess().opts
.optimize
!= config
::OptLevel
::No
,
609 address_operations
.as_ptr(),
610 address_operations
.len() as c_uint
,
613 source_loc
::set_debug_location(cx
, InternalDebugLocation
::new(scope_metadata
,
615 loc
.col
.to_usize()));
617 let debug_loc
= llvm
::LLVMGetCurrentDebugLocation(cx
.raw_builder());
618 let instr
= llvm
::LLVMDIBuilderInsertDeclareAtEnd(
622 address_operations
.as_ptr(),
623 address_operations
.len() as c_uint
,
627 llvm
::LLVMSetInstDebugLocation(trans
::build
::B(bcx
).llbuilder
, instr
);
632 match variable_kind
{
633 ArgumentVariable(_
) | CapturedVariable
=> {
637 .source_locations_enabled
639 source_loc
::set_debug_location(cx
, InternalDebugLocation
::UnknownLocation
);
641 _
=> { /* nothing to do */ }
645 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
647 At(ast
::NodeId
, Span
),
652 pub fn apply(&self, fcx
: &FunctionContext
) {
654 DebugLoc
::At(node_id
, span
) => {
655 source_loc
::set_source_location(fcx
, node_id
, span
);
658 source_loc
::clear_source_location(fcx
);
664 pub trait ToDebugLoc
{
665 fn debug_loc(&self) -> DebugLoc
;
668 impl ToDebugLoc
for hir
::Expr
{
669 fn debug_loc(&self) -> DebugLoc
{
670 DebugLoc
::At(self.id
, self.span
)
674 impl ToDebugLoc
for NodeIdAndSpan
{
675 fn debug_loc(&self) -> DebugLoc
{
676 DebugLoc
::At(self.id
, self.span
)
680 impl ToDebugLoc
for Option
<NodeIdAndSpan
> {
681 fn debug_loc(&self) -> DebugLoc
{
683 Some(NodeIdAndSpan { id, span }
) => DebugLoc
::At(id
, span
),
684 None
=> DebugLoc
::None