rust/src/librustc_trans/debuginfo/mod.rs

511 lines
20 KiB
Rust
Raw Normal View History

2015-04-24 13:20:54 +12:00
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
2015-04-24 17:25:35 +12:00
// http://rust-lang.org/COPYRIGHT.
2015-04-24 13:20:54 +12:00
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
2015-04-24 17:25:35 +12:00
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
2015-04-24 13:20:54 +12:00
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// See doc.rs for documentation.
mod doc;
2015-04-24 17:20:13 +12:00
use self::VariableAccess::*;
use self::VariableKind::*;
use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit};
use self::namespace::mangled_name_of_item;
2015-04-29 18:14:37 +12:00
use self::type_names::compute_debuginfo_type_name;
use self::metadata::{type_metadata, file_metadata, TypeMap};
use self::source_loc::InternalDebugLocation::{self, UnknownLocation};
use llvm;
use llvm::{ModuleRef, ContextRef, ValueRef};
use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, DIFlags};
use rustc::hir::def_id::DefId;
use rustc::ty::subst::Substs;
2015-07-31 00:04:06 -07:00
use abi::Abi;
2016-12-16 13:25:18 -07:00
use common::{CrateContext, BlockAndBuilder};
use monomorphize::{self, Instance};
use rustc::ty::{self, Ty};
2016-09-19 23:50:00 +03:00
use rustc::mir;
2015-01-03 22:42:21 -05:00
use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
use util::nodemap::{DefIdMap, FxHashMap, FxHashSet};
2015-04-24 16:48:10 +12:00
use libc::c_uint;
use std::cell::{Cell, RefCell};
use std::ffi::CString;
use std::ptr;
2015-07-31 00:04:06 -07:00
use syntax_pos::{self, Span, Pos};
use syntax::ast;
use rustc::ty::layout;
2015-04-24 17:25:35 +12:00
pub mod gdb;
mod utils;
mod namespace;
2015-04-29 18:14:37 +12:00
mod type_names;
pub mod metadata;
2015-04-29 18:14:37 +12:00
mod create_scope_map;
mod source_loc;
pub use self::create_scope_map::{create_mir_scopes, MirDebugScope};
2015-04-29 18:14:37 +12:00
pub use self::source_loc::start_emitting_source_locations;
pub use self::metadata::create_global_var_metadata;
pub use self::metadata::extend_scope_to_file;
2016-12-16 13:25:18 -07:00
pub use self::source_loc::set_source_location;
2015-04-24 17:25:35 +12:00
2014-10-27 15:37:07 -07:00
#[allow(non_upper_case_globals)]
2014-12-06 11:39:25 -05:00
const DW_TAG_auto_variable: c_uint = 0x100;
2014-10-27 15:37:07 -07:00
#[allow(non_upper_case_globals)]
2014-12-06 11:39:25 -05:00
const DW_TAG_arg_variable: c_uint = 0x101;
/// A context object for maintaining all state needed by the debuginfo module.
pub struct CrateDebugContext<'tcx> {
llcontext: ContextRef,
builder: DIBuilderRef,
current_debug_location: Cell<InternalDebugLocation>,
created_files: RefCell<FxHashMap<String, DIFile>>,
created_enum_disr_types: RefCell<FxHashMap<(DefId, layout::Integer), DIType>>,
type_map: RefCell<TypeMap<'tcx>>,
namespace_map: RefCell<DefIdMap<DIScope>>,
// This collection is used to assert that composite types (structs, enums,
// ...) have their members only set once:
composite_types_completed: RefCell<FxHashSet<DIType>>,
2013-06-14 11:38:29 -07:00
}
impl<'tcx> CrateDebugContext<'tcx> {
pub fn new(llmod: ModuleRef) -> CrateDebugContext<'tcx> {
debug!("CrateDebugContext::new");
let builder = unsafe { llvm::LLVMRustDIBuilderCreate(llmod) };
2013-06-17 08:42:05 -07:00
// DIBuilder inherits context from the module, so we'd better use the same one
let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
return CrateDebugContext {
2013-06-17 08:42:05 -07:00
llcontext: llcontext,
builder: builder,
2015-04-29 18:14:37 +12:00
current_debug_location: Cell::new(InternalDebugLocation::UnknownLocation),
created_files: RefCell::new(FxHashMap()),
created_enum_disr_types: RefCell::new(FxHashMap()),
type_map: RefCell::new(TypeMap::new()),
namespace_map: RefCell::new(DefIdMap()),
composite_types_completed: RefCell::new(FxHashSet()),
};
}
}
pub enum FunctionDebugContext {
RegularContext(FunctionDebugContextData),
DebugInfoDisabled,
FunctionWithoutDebugInfo,
}
impl FunctionDebugContext {
fn get_ref<'a>(&'a self,
span: Span)
-> &'a FunctionDebugContextData {
match *self {
FunctionDebugContext::RegularContext(ref data) => data,
FunctionDebugContext::DebugInfoDisabled => {
span_bug!(span,
"{}",
FunctionDebugContext::debuginfo_disabled_message());
}
FunctionDebugContext::FunctionWithoutDebugInfo => {
span_bug!(span,
"{}",
FunctionDebugContext::should_be_ignored_message());
}
}
}
fn debuginfo_disabled_message() -> &'static str {
"debuginfo: Error trying to access FunctionDebugContext although debug info is disabled!"
}
fn should_be_ignored_message() -> &'static str {
"debuginfo: Error trying to access FunctionDebugContext for function that should be \
ignored by debug info!"
}
}
2015-11-21 17:39:15 +03:00
pub struct FunctionDebugContextData {
fn_metadata: DISubprogram,
source_locations_enabled: Cell<bool>,
}
2015-04-24 15:49:20 +12:00
pub enum VariableAccess<'a> {
// The llptr given is an alloca containing the variable's value
DirectVariable { alloca: ValueRef },
// The llptr given is an alloca containing the start of some pointer chain
// leading to the variable's content.
2015-01-30 19:25:07 +01:00
IndirectVariable { alloca: ValueRef, address_operations: &'a [i64] }
}
2015-04-24 15:49:20 +12:00
pub enum VariableKind {
ArgumentVariable(usize /*index*/),
LocalVariable,
CapturedVariable,
}
2013-06-14 11:59:49 -07:00
/// Create any deferred debug metadata nodes
2014-03-06 18:47:24 +02:00
pub fn finalize(cx: &CrateContext) {
2014-09-05 09:18:53 -07:00
if cx.dbg_cx().is_none() {
return;
}
debug!("finalize");
2015-04-24 15:25:42 +12:00
if gdb::needs_gdb_debug_scripts_section(cx) {
// Add a .debug_gdb_scripts section to this compile-unit. This will
// cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
// which activates the Rust pretty printers for binary this section is
// contained in.
2015-04-24 15:25:42 +12:00
gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
}
unsafe {
llvm::LLVMRustDIBuilderFinalize(DIB(cx));
llvm::LLVMRustDIBuilderDispose(DIB(cx));
// Debuginfo generation in LLVM by default uses a higher
// version of dwarf than OS X currently understands. We can
// instruct LLVM to emit an older version of dwarf, however,
// for OS X to understand. For more info see #11352
// This can be overridden using --llvm-opts -dwarf-version,N.
// Android has the same issue (#22398)
if cx.sess().target.target.options.is_like_osx ||
cx.sess().target.target.options.is_like_android {
llvm::LLVMRustAddModuleFlag(cx.llmod(),
"Dwarf Version\0".as_ptr() as *const _,
2)
}
// Indicate that we want CodeView debug information on MSVC
if cx.sess().target.target.options.is_like_msvc {
llvm::LLVMRustAddModuleFlag(cx.llmod(),
"CodeView\0".as_ptr() as *const _,
1)
}
// Prevent bitcode readers from deleting the debug info.
let ptr = "Debug Info Version\0".as_ptr();
llvm::LLVMRustAddModuleFlag(cx.llmod(), ptr as *const _,
llvm::LLVMRustDebugMetadataVersion());
2013-06-14 11:38:29 -07:00
};
}
/// Creates a function-specific debug context for a function w/o debuginfo.
pub fn empty_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>)
-> FunctionDebugContext {
if cx.sess().opts.debuginfo == NoDebugInfo {
return FunctionDebugContext::DebugInfoDisabled;
}
// Clear the debug location so we don't assign them in the function prelude.
source_loc::set_debug_location(cx, None, UnknownLocation);
FunctionDebugContext::FunctionWithoutDebugInfo
}
/// Creates the function-specific debug context.
///
/// Returns the FunctionDebugContext for the function which holds state needed
/// for debug info creation. The function may also return another variant of the
/// FunctionDebugContext enum which indicates why no debuginfo should be created
/// for the function.
pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
instance: Instance<'tcx>,
sig: &ty::FnSig<'tcx>,
abi: Abi,
llfn: ValueRef,
mir: &mir::Mir) -> FunctionDebugContext {
2014-03-05 16:36:01 +02:00
if cx.sess().opts.debuginfo == NoDebugInfo {
return FunctionDebugContext::DebugInfoDisabled;
}
// Clear the debug location so we don't assign them in the function prelude.
// Do this here already, in case we do an early exit from this function.
source_loc::set_debug_location(cx, None, UnknownLocation);
let containing_scope = get_containing_scope(cx, instance);
let span = mir.span;
// This can be the case for functions inlined from another crate
if span == syntax_pos::DUMMY_SP {
return FunctionDebugContext::FunctionWithoutDebugInfo;
}
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path);
let function_type_metadata = unsafe {
let fn_signature = get_function_signature(cx, sig, abi);
llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
};
// Find the enclosing function, in case this is a closure.
let def_key = cx.tcx().def_key(instance.def);
let mut name = def_key.disambiguated_data.data.to_string();
let name_len = name.len();
let fn_def_id = cx.tcx().closure_base_def_id(instance.def);
// Get_template_parameters() will append a `<...>` clause to the function
// name if necessary.
let generics = cx.tcx().item_generics(fn_def_id);
let substs = instance.substs.truncate_to(cx.tcx(), generics);
let template_parameters = get_template_parameters(cx,
&generics,
substs,
file_metadata,
&mut name);
// Build the linkage_name out of the item path and "template" parameters.
let linkage_name = mangled_name_of_item(cx, instance.def, &name[name_len..]);
let scope_line = span_start(cx, span).line;
let local_id = cx.tcx().map.as_local_node_id(instance.def);
let is_local_to_unit = local_id.map_or(false, |id| is_node_local_to_unit(cx, id));
let function_name = CString::new(name).unwrap();
std: Implement CString-related RFCs This commit is an implementation of [RFC 592][r592] and [RFC 840][r840]. These two RFCs tweak the behavior of `CString` and add a new `CStr` unsized slice type to the module. [r592]: https://github.com/rust-lang/rfcs/blob/master/text/0592-c-str-deref.md [r840]: https://github.com/rust-lang/rfcs/blob/master/text/0840-no-panic-in-c-string.md The new `CStr` type is only constructable via two methods: 1. By `deref`'ing from a `CString` 2. Unsafely via `CStr::from_ptr` The purpose of `CStr` is to be an unsized type which is a thin pointer to a `libc::c_char` (currently it is a fat pointer slice due to implementation limitations). Strings from C can be safely represented with a `CStr` and an appropriate lifetime as well. Consumers of `&CString` should now consume `&CStr` instead to allow producers to pass in C-originating strings instead of just Rust-allocated strings. A new constructor was added to `CString`, `new`, which takes `T: IntoBytes` instead of separate `from_slice` and `from_vec` methods (both have been deprecated in favor of `new`). The `new` method returns a `Result` instead of panicking. The error variant contains the relevant information about where the error happened and bytes (if present). Conversions are provided to the `io::Error` and `old_io::IoError` types via the `FromError` trait which translate to `InvalidInput`. This is a breaking change due to the modification of existing `#[unstable]` APIs and new deprecation, and more detailed information can be found in the two RFCs. Notable breakage includes: * All construction of `CString` now needs to use `new` and handle the outgoing `Result`. * Usage of `CString` as a byte slice now explicitly needs a `.as_bytes()` call. * The `as_slice*` methods have been removed in favor of just having the `as_bytes*` methods. Closes #22469 Closes #22470 [breaking-change]
2015-02-17 22:47:40 -08:00
let linkage_name = CString::new(linkage_name).unwrap();
let fn_metadata = unsafe {
llvm::LLVMRustDIBuilderCreateFunction(
DIB(cx),
containing_scope,
function_name.as_ptr(),
linkage_name.as_ptr(),
file_metadata,
loc.line as c_uint,
function_type_metadata,
is_local_to_unit,
true,
scope_line as c_uint,
DIFlags::FlagPrototyped,
cx.sess().opts.optimize != config::OptLevel::No,
llfn,
template_parameters,
ptr::null_mut())
};
// Initialize fn debug context (including scope map and namespace map)
let fn_debug_context = FunctionDebugContextData {
fn_metadata: fn_metadata,
source_locations_enabled: Cell::new(false),
};
return FunctionDebugContext::RegularContext(fn_debug_context);
fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
sig: &ty::FnSig<'tcx>,
abi: Abi) -> DIArray {
2014-03-05 16:36:01 +02:00
if cx.sess().opts.debuginfo == LimitedDebugInfo {
2014-11-17 21:39:01 +13:00
return create_DIArray(DIB(cx), &[]);
}
let mut signature = Vec::with_capacity(sig.inputs().len() + 1);
// Return type -- llvm::DIBuilder wants this at index 0
signature.push(match sig.output().sty {
ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
_ => type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP)
});
let inputs = if abi == Abi::RustCall {
&sig.inputs()[..sig.inputs().len() - 1]
} else {
sig.inputs()
};
// Arguments types
for &argument_type in inputs {
signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP));
}
if abi == Abi::RustCall && !sig.inputs().is_empty() {
if let ty::TyTuple(args) = sig.inputs()[sig.inputs().len() - 1].sty {
for &argument_type in args {
signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP));
}
}
}
return create_DIArray(DIB(cx), &signature[..]);
}
fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
generics: &ty::Generics<'tcx>,
substs: &Substs<'tcx>,
file_metadata: DIFile,
name_to_append_suffix_to: &mut String)
-> DIArray
{
if substs.types().next().is_none() {
2014-11-17 21:39:01 +13:00
return create_DIArray(DIB(cx), &[]);
}
name_to_append_suffix_to.push('<');
for (i, actual_type) in substs.types().enumerate() {
if i != 0 {
name_to_append_suffix_to.push_str(",");
}
let actual_type = cx.tcx().normalize_associated_type(&actual_type);
// Add actual type name to <...> clause of function name
debuginfo: Make names of types in debuginfo reliable and omit source locations from debug info type descriptions. So far, type names generated for debuginfo where a bit sketchy. It was not clearly defined when a name should be fully qualified and when not, if region parameters should be shown or not, and other things like that. This commit makes the debuginfo module responsible for creating type names instead of using ppaux::ty_to_str() and brings type names, as they show up in the DWARF information, in line with GCC and Clang: * The name of the type being described is unqualified. It's path is defined by its position in the namespace hierarchy. * Type arguments are always fully qualified, no matter if they would actually be in scope at the type definition location. Care is also taken to reliably make type names consistent across crate boundaries. That is, the code now tries make the type name the same, regardless if the type is in the local crate or reconstructed from metadata. Otherwise LLVM will complain about violating the one-definition-rule when using link-time-optimization. This commit also removes all source location information from type descriptions because these cannot be reconstructed for types instantiated from metadata. Again, with LTO enabled, this can lead to two versions of the debuginfo type description, one with and one without source location information, which then triggers the LLVM ODR assertion. Fortunately, source location information about types is rarely used, so this has little impact. Once source location information is preserved in metadata (#1972) it can also be reenabled for type descriptions.
2014-06-26 13:46:54 +02:00
let actual_type_name = compute_debuginfo_type_name(cx,
actual_type,
true);
name_to_append_suffix_to.push_str(&actual_type_name[..]);
}
name_to_append_suffix_to.push('>');
// Again, only create type information if full debuginfo is enabled
let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo {
let names = get_type_parameter_names(cx, generics);
substs.types().zip(names).map(|(ty, name)| {
let actual_type = cx.tcx().normalize_associated_type(&ty);
let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
let name = CString::new(name.as_str().as_bytes()).unwrap();
unsafe {
llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
DIB(cx),
ptr::null_mut(),
name.as_ptr(),
actual_type_metadata,
file_metadata,
0,
0)
}
}).collect()
} else {
vec![]
};
return create_DIArray(DIB(cx), &template_params[..]);
}
fn get_type_parameter_names<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
generics: &ty::Generics<'tcx>)
-> Vec<ast::Name> {
let mut names = generics.parent.map_or(vec![], |def_id| {
get_type_parameter_names(cx, cx.tcx().item_generics(def_id))
});
names.extend(generics.types.iter().map(|param| param.name));
names
}
fn get_containing_scope<'ccx, 'tcx>(cx: &CrateContext<'ccx, 'tcx>,
instance: Instance<'tcx>)
-> DIScope {
// First, let's see if this is a method within an inherent impl. Because
// if yes, we want to make the result subroutine DIE a child of the
// subroutine's self-type.
let self_type = cx.tcx().impl_of_method(instance.def).and_then(|impl_def_id| {
// If the method does *not* belong to a trait, proceed
if cx.tcx().trait_id_of_impl(impl_def_id).is_none() {
let impl_self_ty = cx.tcx().item_type(impl_def_id);
let impl_self_ty = cx.tcx().erase_regions(&impl_self_ty);
let impl_self_ty = monomorphize::apply_param_substs(cx.shared(),
instance.substs,
&impl_self_ty);
// Only "class" methods are generally understood by LLVM,
// so avoid methods on other types (e.g. `<*mut T>::null`).
match impl_self_ty.sty {
ty::TyAdt(..) => {
Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP))
}
_ => None
}
} else {
// For trait method impls we still use the "parallel namespace"
// strategy
None
}
});
self_type.unwrap_or_else(|| {
namespace::item_namespace(cx, DefId {
krate: instance.def.krate,
index: cx.tcx()
.def_key(instance.def)
.parent
.expect("get_containing_scope: missing parent?")
})
})
}
}
2016-12-10 20:32:44 -07:00
pub fn declare_local<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
variable_name: ast::Name,
variable_type: Ty<'tcx>,
scope_metadata: DIScope,
variable_access: VariableAccess,
variable_kind: VariableKind,
span: Span) {
2015-04-29 18:14:37 +12:00
let cx: &CrateContext = bcx.ccx();
let file = span_start(cx, span).file;
let filename = file.name.clone();
let file_metadata = file_metadata(cx, &filename[..], &file.abs_path);
2015-04-29 18:14:37 +12:00
let loc = span_start(cx, span);
let type_metadata = type_metadata(cx, variable_type, span);
2015-04-29 18:14:37 +12:00
let (argument_index, dwarf_tag) = match variable_kind {
ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
LocalVariable |
CapturedVariable => (0, DW_TAG_auto_variable)
};
let align = ::type_of::align_of(cx, variable_type);
let name = CString::new(variable_name.as_str().as_bytes()).unwrap();
2015-04-29 18:14:37 +12:00
match (variable_access, &[][..]) {
(DirectVariable { alloca }, address_operations) |
(IndirectVariable {alloca, address_operations}, _) => {
let metadata = unsafe {
llvm::LLVMRustDIBuilderCreateVariable(
2015-04-29 18:14:37 +12:00
DIB(cx),
dwarf_tag,
scope_metadata,
name.as_ptr(),
file_metadata,
loc.line as c_uint,
type_metadata,
cx.sess().opts.optimize != config::OptLevel::No,
DIFlags::FlagZero,
argument_index,
align as u64,
)
2015-04-29 18:14:37 +12:00
};
source_loc::set_debug_location(cx, None,
InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize()));
2015-04-29 18:14:37 +12:00
unsafe {
let debug_loc = llvm::LLVMGetCurrentDebugLocation(cx.raw_builder());
let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
2015-04-29 18:14:37 +12:00
DIB(cx),
alloca,
metadata,
address_operations.as_ptr(),
address_operations.len() as c_uint,
debug_loc,
2016-12-10 20:32:44 -07:00
bcx.llbb());
2015-04-29 18:14:37 +12:00
2016-12-10 20:32:44 -07:00
llvm::LLVMSetInstDebugLocation(bcx.llbuilder, instr);
}
}
}
2015-04-29 18:14:37 +12:00
match variable_kind {
ArgumentVariable(_) | CapturedVariable => {
assert!(!bcx.fcx().debug_context.get_ref(span).source_locations_enabled.get());
source_loc::set_debug_location(cx, None, UnknownLocation);
2015-04-29 18:14:37 +12:00
}
_ => { /* nothing to do */ }
}
}