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
::subst
::{self, Substs}
;
31 use trans
::common
::{NodeIdAndSpan, CrateContext, FunctionContext, Block}
;
33 use trans
::{monomorphize, type_of}
;
34 use middle
::ty
::{self, Ty}
;
35 use session
::config
::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}
;
36 use util
::nodemap
::{NodeMap, FnvHashMap, FnvHashSet}
;
39 use std
::cell
::{Cell, RefCell}
;
40 use std
::ffi
::CString
;
43 use syntax
::codemap
::{Span, Pos}
;
44 use syntax
::{abi, ast, codemap, ast_util}
;
45 use syntax
::attr
::IntType
;
46 use syntax
::parse
::token
::{self, special_idents}
;
56 pub use self::source_loc
::set_source_location
;
57 pub use self::source_loc
::clear_source_location
;
58 pub use self::source_loc
::start_emitting_source_locations
;
59 pub use self::source_loc
::get_cleanup_debug_loc_for_ast_node
;
60 pub use self::source_loc
::with_source_location_override
;
61 pub use self::metadata
::create_match_binding_metadata
;
62 pub use self::metadata
::create_argument_metadata
;
63 pub use self::metadata
::create_captured_var_metadata
;
64 pub use self::metadata
::create_global_var_metadata
;
65 pub use self::metadata
::create_local_var_metadata
;
67 #[allow(non_upper_case_globals)]
68 const DW_TAG_auto_variable
: c_uint
= 0x100;
69 #[allow(non_upper_case_globals)]
70 const DW_TAG_arg_variable
: c_uint
= 0x101;
72 /// A context object for maintaining all state needed by the debuginfo module.
73 pub struct CrateDebugContext
<'tcx
> {
74 llcontext
: ContextRef
,
75 builder
: DIBuilderRef
,
76 current_debug_location
: Cell
<InternalDebugLocation
>,
77 created_files
: RefCell
<FnvHashMap
<String
, DIFile
>>,
78 created_enum_disr_types
: RefCell
<FnvHashMap
<(ast
::DefId
, IntType
), DIType
>>,
80 type_map
: RefCell
<TypeMap
<'tcx
>>,
81 namespace_map
: RefCell
<FnvHashMap
<Vec
<ast
::Name
>, Rc
<NamespaceTreeNode
>>>,
83 // This collection is used to assert that composite types (structs, enums,
84 // ...) have their members only set once:
85 composite_types_completed
: RefCell
<FnvHashSet
<DIType
>>,
88 impl<'tcx
> CrateDebugContext
<'tcx
> {
89 pub fn new(llmod
: ModuleRef
) -> CrateDebugContext
<'tcx
> {
90 debug
!("CrateDebugContext::new");
91 let builder
= unsafe { llvm::LLVMDIBuilderCreate(llmod) }
;
92 // DIBuilder inherits context from the module, so we'd better use the same one
93 let llcontext
= unsafe { llvm::LLVMGetModuleContext(llmod) }
;
94 return CrateDebugContext
{
97 current_debug_location
: Cell
::new(InternalDebugLocation
::UnknownLocation
),
98 created_files
: RefCell
::new(FnvHashMap()),
99 created_enum_disr_types
: RefCell
::new(FnvHashMap()),
100 type_map
: RefCell
::new(TypeMap
::new()),
101 namespace_map
: RefCell
::new(FnvHashMap()),
102 composite_types_completed
: RefCell
::new(FnvHashSet()),
107 pub enum FunctionDebugContext
{
108 RegularContext(Box
<FunctionDebugContextData
>),
110 FunctionWithoutDebugInfo
,
113 impl FunctionDebugContext
{
114 fn get_ref
<'a
>(&'a
self,
117 -> &'a FunctionDebugContextData
{
119 FunctionDebugContext
::RegularContext(box ref data
) => data
,
120 FunctionDebugContext
::DebugInfoDisabled
=> {
121 cx
.sess().span_bug(span
,
122 FunctionDebugContext
::debuginfo_disabled_message());
124 FunctionDebugContext
::FunctionWithoutDebugInfo
=> {
125 cx
.sess().span_bug(span
,
126 FunctionDebugContext
::should_be_ignored_message());
131 fn debuginfo_disabled_message() -> &'
static str {
132 "debuginfo: Error trying to access FunctionDebugContext although debug info is disabled!"
135 fn should_be_ignored_message() -> &'
static str {
136 "debuginfo: Error trying to access FunctionDebugContext for function that should be \
137 ignored by debug info!"
141 struct FunctionDebugContextData
{
142 scope_map
: RefCell
<NodeMap
<DIScope
>>,
143 fn_metadata
: DISubprogram
,
144 argument_counter
: Cell
<usize>,
145 source_locations_enabled
: Cell
<bool
>,
146 source_location_override
: Cell
<bool
>,
149 pub enum VariableAccess
<'a
> {
150 // The llptr given is an alloca containing the variable's value
151 DirectVariable { alloca: ValueRef }
,
152 // The llptr given is an alloca containing the start of some pointer chain
153 // leading to the variable's content.
154 IndirectVariable { alloca: ValueRef, address_operations: &'a [i64] }
157 pub enum VariableKind
{
158 ArgumentVariable(usize /*index*/),
163 /// Create any deferred debug metadata nodes
164 pub fn finalize(cx
: &CrateContext
) {
165 if cx
.dbg_cx().is_none() {
170 let _
= compile_unit_metadata(cx
);
172 if gdb
::needs_gdb_debug_scripts_section(cx
) {
173 // Add a .debug_gdb_scripts section to this compile-unit. This will
174 // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
175 // which activates the Rust pretty printers for binary this section is
177 gdb
::get_or_insert_gdb_debug_scripts_section_global(cx
);
181 llvm
::LLVMDIBuilderFinalize(DIB(cx
));
182 llvm
::LLVMDIBuilderDispose(DIB(cx
));
183 // Debuginfo generation in LLVM by default uses a higher
184 // version of dwarf than OS X currently understands. We can
185 // instruct LLVM to emit an older version of dwarf, however,
186 // for OS X to understand. For more info see #11352
187 // This can be overridden using --llvm-opts -dwarf-version,N.
188 // Android has the same issue (#22398)
189 if cx
.sess().target
.target
.options
.is_like_osx
||
190 cx
.sess().target
.target
.options
.is_like_android
{
191 llvm
::LLVMRustAddModuleFlag(cx
.llmod(),
192 "Dwarf Version\0".as_ptr() as *const _
,
196 // Prevent bitcode readers from deleting the debug info.
197 let ptr
= "Debug Info Version\0".as_ptr();
198 llvm
::LLVMRustAddModuleFlag(cx
.llmod(), ptr
as *const _
,
199 llvm
::LLVMRustDebugMetadataVersion());
203 /// Creates the function-specific debug context.
205 /// Returns the FunctionDebugContext for the function which holds state needed
206 /// for debug info creation. The function may also return another variant of the
207 /// FunctionDebugContext enum which indicates why no debuginfo should be created
208 /// for the function.
209 pub fn create_function_debug_context
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
210 fn_ast_id
: ast
::NodeId
,
211 param_substs
: &Substs
<'tcx
>,
212 llfn
: ValueRef
) -> FunctionDebugContext
{
213 if cx
.sess().opts
.debuginfo
== NoDebugInfo
{
214 return FunctionDebugContext
::DebugInfoDisabled
;
217 // Clear the debug location so we don't assign them in the function prelude.
218 // Do this here already, in case we do an early exit from this function.
219 source_loc
::set_debug_location(cx
, InternalDebugLocation
::UnknownLocation
);
221 if fn_ast_id
== ast
::DUMMY_NODE_ID
{
222 // This is a function not linked to any source location, so don't
223 // generate debuginfo for it.
224 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
227 let empty_generics
= ast_util
::empty_generics();
229 let fnitem
= cx
.tcx().map
.get(fn_ast_id
);
231 let (name
, fn_decl
, generics
, top_level_block
, span
, has_path
) = match fnitem
{
232 ast_map
::NodeItem(ref item
) => {
233 if contains_nodebug_attribute(&item
.attrs
) {
234 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
238 ast
::ItemFn(ref fn_decl
, _
, _
, _
, ref generics
, ref top_level_block
) => {
239 (item
.ident
.name
, fn_decl
, generics
, top_level_block
, item
.span
, true)
242 cx
.sess().span_bug(item
.span
,
243 "create_function_debug_context: item bound to non-function");
247 ast_map
::NodeImplItem(impl_item
) => {
248 match impl_item
.node
{
249 ast
::MethodImplItem(ref sig
, ref body
) => {
250 if contains_nodebug_attribute(&impl_item
.attrs
) {
251 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
254 (impl_item
.ident
.name
,
262 cx
.sess().span_bug(impl_item
.span
,
263 "create_function_debug_context() \
264 called on non-method impl item?!")
268 ast_map
::NodeExpr(ref expr
) => {
270 ast
::ExprClosure(_
, ref fn_decl
, ref top_level_block
) => {
271 let name
= format
!("fn{}", token
::gensym("fn"));
272 let name
= token
::intern(&name
[..]);
274 // This is not quite right. It should actually inherit
275 // the generics of the enclosing function.
279 // Don't try to lookup the item path:
282 _
=> cx
.sess().span_bug(expr
.span
,
283 "create_function_debug_context: expected an expr_fn_block here")
286 ast_map
::NodeTraitItem(trait_item
) => {
287 match trait_item
.node
{
288 ast
::MethodTraitItem(ref sig
, Some(ref body
)) => {
289 if contains_nodebug_attribute(&trait_item
.attrs
) {
290 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
293 (trait_item
.ident
.name
,
302 .bug(&format
!("create_function_debug_context: \
303 unexpected sort of node: {:?}",
308 ast_map
::NodeForeignItem(..) |
309 ast_map
::NodeVariant(..) |
310 ast_map
::NodeStructCtor(..) => {
311 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
313 _
=> cx
.sess().bug(&format
!("create_function_debug_context: \
314 unexpected sort of node: {:?}",
318 // This can be the case for functions inlined from another crate
319 if span
== codemap
::DUMMY_SP
{
320 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
323 let loc
= span_start(cx
, span
);
324 let file_metadata
= file_metadata(cx
, &loc
.file
.name
);
326 let function_type_metadata
= unsafe {
327 let fn_signature
= get_function_signature(cx
,
331 llvm
::LLVMDIBuilderCreateSubroutineType(DIB(cx
), file_metadata
, fn_signature
)
334 // Get_template_parameters() will append a `<...>` clause to the function
335 // name if necessary.
336 let mut function_name
= name
.to_string();
337 let template_parameters
= get_template_parameters(cx
,
343 // There is no ast_map::Path for ast::ExprClosure-type functions. For now,
344 // just don't put them into a namespace. In the future this could be improved
345 // somehow (storing a path in the ast_map, or construct a path using the
346 // enclosing function).
347 let (linkage_name
, containing_scope
) = if has_path
{
348 let namespace_node
= namespace_for_item(cx
, ast_util
::local_def(fn_ast_id
));
349 let linkage_name
= namespace_node
.mangled_name_of_contained_item(
351 let containing_scope
= namespace_node
.scope
;
352 (linkage_name
, containing_scope
)
354 (function_name
.clone(), file_metadata
)
357 // Clang sets this parameter to the opening brace of the function's block,
358 // so let's do this too.
359 let scope_line
= span_start(cx
, top_level_block
.span
).line
;
361 let is_local_to_unit
= is_node_local_to_unit(cx
, fn_ast_id
);
363 let function_name
= CString
::new(function_name
).unwrap();
364 let linkage_name
= CString
::new(linkage_name
).unwrap();
365 let fn_metadata
= unsafe {
366 llvm
::LLVMDIBuilderCreateFunction(
369 function_name
.as_ptr(),
370 linkage_name
.as_ptr(),
373 function_type_metadata
,
376 scope_line
as c_uint
,
377 FlagPrototyped
as c_uint
,
378 cx
.sess().opts
.optimize
!= config
::No
,
384 let scope_map
= create_scope_map
::create_scope_map(cx
,
390 // Initialize fn debug context (including scope map and namespace map)
391 let fn_debug_context
= box FunctionDebugContextData
{
392 scope_map
: RefCell
::new(scope_map
),
393 fn_metadata
: fn_metadata
,
394 argument_counter
: Cell
::new(1),
395 source_locations_enabled
: Cell
::new(false),
396 source_location_override
: Cell
::new(false),
401 return FunctionDebugContext
::RegularContext(fn_debug_context
);
403 fn get_function_signature
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
404 fn_ast_id
: ast
::NodeId
,
405 param_substs
: &Substs
<'tcx
>,
406 error_reporting_span
: Span
) -> DIArray
{
407 if cx
.sess().opts
.debuginfo
== LimitedDebugInfo
{
408 return create_DIArray(DIB(cx
), &[]);
411 // Return type -- llvm::DIBuilder wants this at index 0
412 assert_type_for_node_id(cx
, fn_ast_id
, error_reporting_span
);
413 let fn_type
= cx
.tcx().node_id_to_type(fn_ast_id
);
415 let (sig
, abi
) = match fn_type
.sty
{
416 ty
::TyBareFn(_
, ref barefnty
) => {
417 (cx
.tcx().erase_late_bound_regions(&barefnty
.sig
), barefnty
.abi
)
419 ty
::TyClosure(def_id
, ref substs
) => {
420 let closure_type
= cx
.tcx().closure_type(def_id
, substs
);
421 (cx
.tcx().erase_late_bound_regions(&closure_type
.sig
), closure_type
.abi
)
424 _
=> cx
.sess().bug("get_function_metdata: Expected a function type!")
426 let sig
= monomorphize
::apply_param_substs(cx
.tcx(), param_substs
, &sig
);
428 let mut signature
= Vec
::with_capacity(sig
.inputs
.len() + 1);
430 // Return type -- llvm::DIBuilder wants this at index 0
431 signature
.push(match sig
.output
{
432 ty
::FnConverging(ret_ty
) => match ret_ty
.sty
{
433 ty
::TyTuple(ref tys
) if tys
.is_empty() => ptr
::null_mut(),
434 _
=> type_metadata(cx
, ret_ty
, codemap
::DUMMY_SP
)
436 ty
::FnDiverging
=> diverging_type_metadata(cx
)
439 let inputs
= &if abi
== abi
::RustCall
{
440 type_of
::untuple_arguments(cx
, &sig
.inputs
)
446 for &argument_type
in inputs
{
447 signature
.push(type_metadata(cx
, argument_type
, codemap
::DUMMY_SP
));
450 return create_DIArray(DIB(cx
), &signature
[..]);
453 fn get_template_parameters
<'a
, 'tcx
>(cx
: &CrateContext
<'a
, 'tcx
>,
454 generics
: &ast
::Generics
,
455 param_substs
: &Substs
<'tcx
>,
456 file_metadata
: DIFile
,
457 name_to_append_suffix_to
: &mut String
)
460 let self_type
= param_substs
.self_ty();
461 let self_type
= monomorphize
::normalize_associated_type(cx
.tcx(), &self_type
);
463 // Only true for static default methods:
464 let has_self_type
= self_type
.is_some();
466 if !generics
.is_type_parameterized() && !has_self_type
{
467 return create_DIArray(DIB(cx
), &[]);
470 name_to_append_suffix_to
.push('
<'
);
472 // The list to be filled with template parameters:
473 let mut template_params
: Vec
<DIDescriptor
> =
474 Vec
::with_capacity(generics
.ty_params
.len() + 1);
478 let actual_self_type
= self_type
.unwrap();
479 // Add self type name to <...> clause of function name
480 let actual_self_type_name
= compute_debuginfo_type_name(
485 name_to_append_suffix_to
.push_str(&actual_self_type_name
[..]);
487 if generics
.is_type_parameterized() {
488 name_to_append_suffix_to
.push_str(",");
491 // Only create type information if full debuginfo is enabled
492 if cx
.sess().opts
.debuginfo
== FullDebugInfo
{
493 let actual_self_type_metadata
= type_metadata(cx
,
497 let name
= special_idents
::type_self
.name
.as_str();
499 let name
= CString
::new(name
.as_bytes()).unwrap();
500 let param_metadata
= unsafe {
501 llvm
::LLVMDIBuilderCreateTemplateTypeParameter(
505 actual_self_type_metadata
,
511 template_params
.push(param_metadata
);
515 // Handle other generic parameters
516 let actual_types
= param_substs
.types
.get_slice(subst
::FnSpace
);
517 for (index
, &ast
::TyParam{ ident, .. }
) in generics
.ty_params
.iter().enumerate() {
518 let actual_type
= actual_types
[index
];
519 // Add actual type name to <...> clause of function name
520 let actual_type_name
= compute_debuginfo_type_name(cx
,
523 name_to_append_suffix_to
.push_str(&actual_type_name
[..]);
525 if index
!= generics
.ty_params
.len() - 1 {
526 name_to_append_suffix_to
.push_str(",");
529 // Again, only create type information if full debuginfo is enabled
530 if cx
.sess().opts
.debuginfo
== FullDebugInfo
{
531 let actual_type_metadata
= type_metadata(cx
, actual_type
, codemap
::DUMMY_SP
);
532 let name
= CString
::new(ident
.name
.as_str().as_bytes()).unwrap();
533 let param_metadata
= unsafe {
534 llvm
::LLVMDIBuilderCreateTemplateTypeParameter(
538 actual_type_metadata
,
543 template_params
.push(param_metadata
);
547 name_to_append_suffix_to
.push('
>'
);
549 return create_DIArray(DIB(cx
), &template_params
[..]);
553 fn declare_local
<'blk
, 'tcx
>(bcx
: Block
<'blk
, 'tcx
>,
554 variable_name
: ast
::Name
,
555 variable_type
: Ty
<'tcx
>,
556 scope_metadata
: DIScope
,
557 variable_access
: VariableAccess
,
558 variable_kind
: VariableKind
,
560 let cx
: &CrateContext
= bcx
.ccx();
562 let filename
= span_start(cx
, span
).file
.name
.clone();
563 let file_metadata
= file_metadata(cx
, &filename
[..]);
565 let loc
= span_start(cx
, span
);
566 let type_metadata
= type_metadata(cx
, variable_type
, span
);
568 let (argument_index
, dwarf_tag
) = match variable_kind
{
569 ArgumentVariable(index
) => (index
as c_uint
, DW_TAG_arg_variable
),
571 CapturedVariable
=> (0, DW_TAG_auto_variable
)
574 let name
= CString
::new(variable_name
.as_str().as_bytes()).unwrap();
575 match (variable_access
, &[][..]) {
576 (DirectVariable { alloca }
, address_operations
) |
577 (IndirectVariable {alloca, address_operations}
, _
) => {
578 let metadata
= unsafe {
579 llvm
::LLVMDIBuilderCreateVariable(
587 cx
.sess().opts
.optimize
!= config
::No
,
589 address_operations
.as_ptr(),
590 address_operations
.len() as c_uint
,
593 source_loc
::set_debug_location(cx
, InternalDebugLocation
::new(scope_metadata
,
595 loc
.col
.to_usize()));
597 let debug_loc
= llvm
::LLVMGetCurrentDebugLocation(cx
.raw_builder());
598 let instr
= llvm
::LLVMDIBuilderInsertDeclareAtEnd(
602 address_operations
.as_ptr(),
603 address_operations
.len() as c_uint
,
607 llvm
::LLVMSetInstDebugLocation(trans
::build
::B(bcx
).llbuilder
, instr
);
612 match variable_kind
{
613 ArgumentVariable(_
) | CapturedVariable
=> {
617 .source_locations_enabled
619 source_loc
::set_debug_location(cx
, InternalDebugLocation
::UnknownLocation
);
621 _
=> { /* nothing to do */ }
625 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
627 At(ast
::NodeId
, Span
),
632 pub fn apply(&self, fcx
: &FunctionContext
) {
634 DebugLoc
::At(node_id
, span
) => {
635 source_loc
::set_source_location(fcx
, node_id
, span
);
638 source_loc
::clear_source_location(fcx
);
644 pub trait ToDebugLoc
{
645 fn debug_loc(&self) -> DebugLoc
;
648 impl ToDebugLoc
for ast
::Expr
{
649 fn debug_loc(&self) -> DebugLoc
{
650 DebugLoc
::At(self.id
, self.span
)
654 impl ToDebugLoc
for NodeIdAndSpan
{
655 fn debug_loc(&self) -> DebugLoc
{
656 DebugLoc
::At(self.id
, self.span
)
660 impl ToDebugLoc
for Option
<NodeIdAndSpan
> {
661 fn debug_loc(&self) -> DebugLoc
{
663 Some(NodeIdAndSpan { id, span }
) => DebugLoc
::At(id
, span
),
664 None
=> DebugLoc
::None