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, file_metadata, scope_metadata, TypeMap, compile_unit_metadata}
;
22 use self::source_loc
::InternalDebugLocation
;
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}
;
30 use trans
::common
::{NodeIdAndSpan, CrateContext, FunctionContext, Block}
;
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}
;
38 use std
::cell
::{Cell, RefCell}
;
39 use std
::ffi
::CString
;
42 use syntax
::codemap
::{Span, Pos}
;
43 use syntax
::{ast, codemap, ast_util}
;
44 use syntax
::parse
::token
::{self, special_idents}
;
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
;
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;
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
>>,
78 type_map
: RefCell
<TypeMap
<'tcx
>>,
79 namespace_map
: RefCell
<FnvHashMap
<Vec
<ast
::Name
>, Rc
<NamespaceTreeNode
>>>,
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
>>,
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
{
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()),
105 pub enum FunctionDebugContext
{
106 RegularContext(Box
<FunctionDebugContextData
>),
108 FunctionWithoutDebugInfo
,
111 impl FunctionDebugContext
{
112 fn get_ref
<'a
>(&'a
self,
115 -> &'a FunctionDebugContextData
{
117 FunctionDebugContext
::RegularContext(box ref data
) => data
,
118 FunctionDebugContext
::DebugInfoDisabled
=> {
119 cx
.sess().span_bug(span
,
120 FunctionDebugContext
::debuginfo_disabled_message());
122 FunctionDebugContext
::FunctionWithoutDebugInfo
=> {
123 cx
.sess().span_bug(span
,
124 FunctionDebugContext
::should_be_ignored_message());
129 fn debuginfo_disabled_message() -> &'
static str {
130 "debuginfo: Error trying to access FunctionDebugContext although debug info is disabled!"
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!"
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
>,
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] }
155 pub enum VariableKind
{
156 ArgumentVariable(usize /*index*/),
161 /// Create any deferred debug metadata nodes
162 pub fn finalize(cx
: &CrateContext
) {
163 if cx
.dbg_cx().is_none() {
168 let _
= compile_unit_metadata(cx
);
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
175 gdb
::get_or_insert_gdb_debug_scripts_section_global(cx
);
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 _
,
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());
201 /// Creates the function-specific debug context.
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
;
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
);
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
;
225 let empty_generics
= ast_util
::empty_generics();
227 let fnitem
= cx
.tcx().map
.get(fn_ast_id
);
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
;
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)
240 cx
.sess().span_bug(item
.span
,
241 "create_function_debug_context: item bound to non-function");
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
;
252 (impl_item
.ident
.name
,
260 cx
.sess().span_bug(impl_item
.span
,
261 "create_function_debug_context() \
262 called on non-method impl item?!")
266 ast_map
::NodeExpr(ref expr
) => {
268 ast
::ExprClosure(_
, ref fn_decl
, ref top_level_block
) => {
269 let name
= format
!("fn{}", token
::gensym("fn"));
270 let name
= token
::intern(&name
[..]);
272 // This is not quite right. It should actually inherit
273 // the generics of the enclosing function.
277 // Don't try to lookup the item path:
280 _
=> cx
.sess().span_bug(expr
.span
,
281 "create_function_debug_context: expected an expr_fn_block here")
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
;
291 (trait_item
.ident
.name
,
300 .bug(&format
!("create_function_debug_context: \
301 unexpected sort of node: {:?}",
306 ast_map
::NodeForeignItem(..) |
307 ast_map
::NodeVariant(..) |
308 ast_map
::NodeStructCtor(..) => {
309 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
311 _
=> cx
.sess().bug(&format
!("create_function_debug_context: \
312 unexpected sort of node: {:?}",
316 // This can be the case for functions inlined from another crate
317 if span
== codemap
::DUMMY_SP
{
318 return FunctionDebugContext
::FunctionWithoutDebugInfo
;
321 let loc
= span_start(cx
, span
);
322 let file_metadata
= file_metadata(cx
, &loc
.file
.name
);
324 let function_type_metadata
= unsafe {
325 let fn_signature
= get_function_signature(cx
,
330 llvm
::LLVMDIBuilderCreateSubroutineType(DIB(cx
), file_metadata
, fn_signature
)
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
,
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(
350 let containing_scope
= namespace_node
.scope
;
351 (linkage_name
, containing_scope
)
353 (function_name
.clone(), file_metadata
)
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
;
360 let is_local_to_unit
= is_node_local_to_unit(cx
, fn_ast_id
);
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(
368 function_name
.as_ptr(),
369 linkage_name
.as_ptr(),
372 function_type_metadata
,
375 scope_line
as c_uint
,
376 FlagPrototyped
as c_uint
,
377 cx
.sess().opts
.optimize
!= config
::No
,
383 let scope_map
= create_scope_map
::create_scope_map(cx
,
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),
400 return FunctionDebugContext
::RegularContext(fn_debug_context
);
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
), &[]);
411 let mut signature
= Vec
::with_capacity(fn_decl
.inputs
.len() + 1);
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(),
419 if ty
::type_is_nil(return_type
) {
420 signature
.push(ptr
::null_mut())
422 signature
.push(type_metadata(cx
, return_type
, codemap
::DUMMY_SP
));
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(),
432 signature
.push(type_metadata(cx
, arg_type
, codemap
::DUMMY_SP
));
435 return create_DIArray(DIB(cx
), &signature
[..]);
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
)
445 let self_type
= param_substs
.self_ty();
446 let self_type
= monomorphize
::normalize_associated_type(cx
.tcx(), &self_type
);
448 // Only true for static default methods:
449 let has_self_type
= self_type
.is_some();
451 if !generics
.is_type_parameterized() && !has_self_type
{
452 return create_DIArray(DIB(cx
), &[]);
455 name_to_append_suffix_to
.push('
<'
);
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);
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(
470 name_to_append_suffix_to
.push_str(&actual_self_type_name
[..]);
472 if generics
.is_type_parameterized() {
473 name_to_append_suffix_to
.push_str(",");
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
,
482 let name
= token
::get_name(special_idents
::type_self
.name
);
484 let name
= CString
::new(name
.as_bytes()).unwrap();
485 let param_metadata
= unsafe {
486 llvm
::LLVMDIBuilderCreateTemplateTypeParameter(
490 actual_self_type_metadata
,
496 template_params
.push(param_metadata
);
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
,
508 name_to_append_suffix_to
.push_str(&actual_type_name
[..]);
510 if index
!= generics
.ty_params
.len() - 1 {
511 name_to_append_suffix_to
.push_str(",");
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(
524 actual_type_metadata
,
529 template_params
.push(param_metadata
);
533 name_to_append_suffix_to
.push('
>'
);
535 return create_DIArray(DIB(cx
), &template_params
[..]);
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
,
546 let cx
: &CrateContext
= bcx
.ccx();
548 let filename
= span_start(cx
, span
).file
.name
.clone();
549 let file_metadata
= file_metadata(cx
, &filename
[..]);
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
);
555 let (argument_index
, dwarf_tag
) = match variable_kind
{
556 ArgumentVariable(index
) => (index
as c_uint
, DW_TAG_arg_variable
),
558 CapturedVariable
=> (0, DW_TAG_auto_variable
)
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(
574 cx
.sess().opts
.optimize
!= config
::No
,
576 address_operations
.as_ptr(),
577 address_operations
.len() as c_uint
,
580 source_loc
::set_debug_location(cx
, InternalDebugLocation
::new(scope_metadata
,
582 loc
.col
.to_usize()));
584 let debug_loc
= llvm
::LLVMGetCurrentDebugLocation(cx
.raw_builder());
585 let instr
= llvm
::LLVMDIBuilderInsertDeclareAtEnd(
589 address_operations
.as_ptr(),
590 address_operations
.len() as c_uint
,
594 llvm
::LLVMSetInstDebugLocation(trans
::build
::B(bcx
).llbuilder
, instr
);
599 match variable_kind
{
600 ArgumentVariable(_
) | CapturedVariable
=> {
604 .source_locations_enabled
606 source_loc
::set_debug_location(cx
, InternalDebugLocation
::UnknownLocation
);
608 _
=> { /* nothing to do */ }
612 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
614 At(ast
::NodeId
, Span
),
619 pub fn apply(&self, fcx
: &FunctionContext
) {
621 DebugLoc
::At(node_id
, span
) => {
622 source_loc
::set_source_location(fcx
, node_id
, span
);
625 source_loc
::clear_source_location(fcx
);
631 pub trait ToDebugLoc
{
632 fn debug_loc(&self) -> DebugLoc
;
635 impl ToDebugLoc
for ast
::Expr
{
636 fn debug_loc(&self) -> DebugLoc
{
637 DebugLoc
::At(self.id
, self.span
)
641 impl ToDebugLoc
for NodeIdAndSpan
{
642 fn debug_loc(&self) -> DebugLoc
{
643 DebugLoc
::At(self.id
, self.span
)
647 impl ToDebugLoc
for Option
<NodeIdAndSpan
> {
648 fn debug_loc(&self) -> DebugLoc
{
650 Some(NodeIdAndSpan { id, span }
) => DebugLoc
::At(id
, span
),
651 None
=> DebugLoc
::None