1
Fork 0

mv compiler to compiler/

This commit is contained in:
mark 2020-08-27 22:58:48 -05:00 committed by Vadim Petrochenkov
parent db534b3ac2
commit 9e5f7d5631
1686 changed files with 941 additions and 1051 deletions

View file

@ -0,0 +1,95 @@
use super::metadata::{file_metadata, UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER};
use super::utils::DIB;
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
use rustc_codegen_ssa::traits::*;
use crate::common::CodegenCx;
use crate::llvm;
use crate::llvm::debuginfo::{DIScope, DISubprogram};
use rustc_middle::mir::{Body, SourceScope};
use rustc_session::config::DebugInfo;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx;
/// Produces DIScope DIEs for each MIR Scope which has variables defined in it.
pub fn compute_mir_scopes(
cx: &CodegenCx<'ll, '_>,
mir: &Body<'_>,
fn_metadata: &'ll DISubprogram,
debug_context: &mut FunctionDebugContext<&'ll DIScope>,
) {
// Find all the scopes with variables defined in them.
let mut has_variables = BitSet::new_empty(mir.source_scopes.len());
// Only consider variables when they're going to be emitted.
// FIXME(eddyb) don't even allocate `has_variables` otherwise.
if cx.sess().opts.debuginfo == DebugInfo::Full {
// FIXME(eddyb) take into account that arguments always have debuginfo,
// irrespective of their name (assuming full debuginfo is enabled).
// NOTE(eddyb) actually, on second thought, those are always in the
// function scope, which always exists.
for var_debug_info in &mir.var_debug_info {
has_variables.insert(var_debug_info.source_info.scope);
}
}
// Instantiate all scopes.
for idx in 0..mir.source_scopes.len() {
let scope = SourceScope::new(idx);
make_mir_scope(cx, &mir, fn_metadata, &has_variables, debug_context, scope);
}
}
fn make_mir_scope(
cx: &CodegenCx<'ll, '_>,
mir: &Body<'_>,
fn_metadata: &'ll DISubprogram,
has_variables: &BitSet<SourceScope>,
debug_context: &mut FunctionDebugContext<&'ll DISubprogram>,
scope: SourceScope,
) {
if debug_context.scopes[scope].is_valid() {
return;
}
let scope_data = &mir.source_scopes[scope];
let parent_scope = if let Some(parent) = scope_data.parent_scope {
make_mir_scope(cx, mir, fn_metadata, has_variables, debug_context, parent);
debug_context.scopes[parent]
} else {
// The root is the function itself.
let loc = cx.lookup_debug_loc(mir.span.lo());
debug_context.scopes[scope] = DebugScope {
scope_metadata: Some(fn_metadata),
file_start_pos: loc.file.start_pos,
file_end_pos: loc.file.end_pos,
};
return;
};
if !has_variables.contains(scope) {
// Do not create a DIScope if there are no variables
// defined in this MIR Scope, to avoid debuginfo bloat.
debug_context.scopes[scope] = parent_scope;
return;
}
let loc = cx.lookup_debug_loc(scope_data.span.lo());
let file_metadata = file_metadata(cx, &loc.file, debug_context.defining_crate);
let scope_metadata = unsafe {
Some(llvm::LLVMRustDIBuilderCreateLexicalBlock(
DIB(cx),
parent_scope.scope_metadata.unwrap(),
file_metadata,
loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
loc.col.unwrap_or(UNKNOWN_COLUMN_NUMBER),
))
};
debug_context.scopes[scope] = DebugScope {
scope_metadata,
file_start_pos: loc.file.start_pos,
file_end_pos: loc.file.end_pos,
};
}

View file

@ -0,0 +1,179 @@
//! # Debug Info Module
//!
//! This module serves the purpose of generating debug symbols. We use LLVM's
//! [source level debugging](https://llvm.org/docs/SourceLevelDebugging.html)
//! features for generating the debug information. The general principle is
//! this:
//!
//! Given the right metadata in the LLVM IR, the LLVM code generator is able to
//! create DWARF debug symbols for the given code. The
//! [metadata](https://llvm.org/docs/LangRef.html#metadata-type) is structured
//! much like DWARF *debugging information entries* (DIE), representing type
//! information such as datatype layout, function signatures, block layout,
//! variable location and scope information, etc. It is the purpose of this
//! module to generate correct metadata and insert it into the LLVM IR.
//!
//! As the exact format of metadata trees may change between different LLVM
//! versions, we now use LLVM
//! [DIBuilder](https://llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html)
//! to create metadata where possible. This will hopefully ease the adaption of
//! this module to future LLVM versions.
//!
//! The public API of the module is a set of functions that will insert the
//! correct metadata into the LLVM IR when called with the right parameters.
//! The module is thus driven from an outside client with functions like
//! `debuginfo::create_local_var_metadata(bx: block, local: &ast::local)`.
//!
//! Internally the module will try to reuse already created metadata by
//! utilizing a cache. The way to get a shared metadata node when needed is
//! thus to just call the corresponding function in this module:
//!
//! let file_metadata = file_metadata(crate_context, path);
//!
//! The function will take care of probing the cache for an existing node for
//! that exact file path.
//!
//! All private state used by the module is stored within either the
//! CrateDebugContext struct (owned by the CodegenCx) or the
//! FunctionDebugContext (owned by the FunctionCx).
//!
//! This file consists of three conceptual sections:
//! 1. The public interface of the module
//! 2. Module-internal metadata creation functions
//! 3. Minor utility functions
//!
//!
//! ## Recursive Types
//!
//! Some kinds of types, such as structs and enums can be recursive. That means
//! that the type definition of some type X refers to some other type which in
//! turn (transitively) refers to X. This introduces cycles into the type
//! referral graph. A naive algorithm doing an on-demand, depth-first traversal
//! of this graph when describing types, can get trapped in an endless loop
//! when it reaches such a cycle.
//!
//! For example, the following simple type for a singly-linked list...
//!
//! ```
//! struct List {
//! value: i32,
//! tail: Option<Box<List>>,
//! }
//! ```
//!
//! will generate the following callstack with a naive DFS algorithm:
//!
//! ```
//! describe(t = List)
//! describe(t = i32)
//! describe(t = Option<Box<List>>)
//! describe(t = Box<List>)
//! describe(t = List) // at the beginning again...
//! ...
//! ```
//!
//! To break cycles like these, we use "forward declarations". That is, when
//! the algorithm encounters a possibly recursive type (any struct or enum), it
//! immediately creates a type description node and inserts it into the cache
//! *before* describing the members of the type. This type description is just
//! a stub (as type members are not described and added to it yet) but it
//! allows the algorithm to already refer to the type. After the stub is
//! inserted into the cache, the algorithm continues as before. If it now
//! encounters a recursive reference, it will hit the cache and does not try to
//! describe the type anew.
//!
//! This behavior is encapsulated in the 'RecursiveTypeDescription' enum,
//! which represents a kind of continuation, storing all state needed to
//! continue traversal at the type members after the type has been registered
//! with the cache. (This implementation approach might be a tad over-
//! engineered and may change in the future)
//!
//!
//! ## Source Locations and Line Information
//!
//! In addition to data type descriptions the debugging information must also
//! allow to map machine code locations back to source code locations in order
//! to be useful. This functionality is also handled in this module. The
//! following functions allow to control source mappings:
//!
//! + set_source_location()
//! + clear_source_location()
//! + start_emitting_source_locations()
//!
//! `set_source_location()` allows to set the current source location. All IR
//! instructions created after a call to this function will be linked to the
//! given source location, until another location is specified with
//! `set_source_location()` or the source location is cleared with
//! `clear_source_location()`. In the later case, subsequent IR instruction
//! will not be linked to any source location. As you can see, this is a
//! stateful API (mimicking the one in LLVM), so be careful with source
//! locations set by previous calls. It's probably best to not rely on any
//! specific state being present at a given point in code.
//!
//! One topic that deserves some extra attention is *function prologues*. At
//! the beginning of a function's machine code there are typically a few
//! instructions for loading argument values into allocas and checking if
//! there's enough stack space for the function to execute. This *prologue* is
//! not visible in the source code and LLVM puts a special PROLOGUE END marker
//! into the line table at the first non-prologue instruction of the function.
//! In order to find out where the prologue ends, LLVM looks for the first
//! instruction in the function body that is linked to a source location. So,
//! when generating prologue instructions we have to make sure that we don't
//! emit source location information until the 'real' function body begins. For
//! this reason, source location emission is disabled by default for any new
//! function being codegened and is only activated after a call to the third
//! function from the list above, `start_emitting_source_locations()`. This
//! function should be called right before regularly starting to codegen the
//! top-level block of the given function.
//!
//! There is one exception to the above rule: `llvm.dbg.declare` instruction
//! must be linked to the source location of the variable being declared. For
//! function parameters these `llvm.dbg.declare` instructions typically occur
//! in the middle of the prologue, however, they are ignored by LLVM's prologue
//! detection. The `create_argument_metadata()` and related functions take care
//! of linking the `llvm.dbg.declare` instructions to the correct source
//! locations even while source location emission is still disabled, so there
//! is no need to do anything special with source location handling here.
//!
//! ## Unique Type Identification
//!
//! In order for link-time optimization to work properly, LLVM needs a unique
//! type identifier that tells it across compilation units which types are the
//! same as others. This type identifier is created by
//! `TypeMap::get_unique_type_id_of_type()` using the following algorithm:
//!
//! (1) Primitive types have their name as ID
//! (2) Structs, enums and traits have a multipart identifier
//!
//! (1) The first part is the SVH (strict version hash) of the crate they
//! were originally defined in
//!
//! (2) The second part is the ast::NodeId of the definition in their
//! original crate
//!
//! (3) The final part is a concatenation of the type IDs of their concrete
//! type arguments if they are generic types.
//!
//! (3) Tuple-, pointer and function types are structurally identified, which
//! means that they are equivalent if their component types are equivalent
//! (i.e., (i32, i32) is the same regardless in which crate it is used).
//!
//! This algorithm also provides a stable ID for types that are defined in one
//! crate but instantiated from metadata within another crate. We just have to
//! take care to always map crate and `NodeId`s back to the original crate
//! context.
//!
//! As a side-effect these unique type IDs also help to solve a problem arising
//! from lifetime parameters. Since lifetime parameters are completely omitted
//! in debuginfo, more than one `Ty` instance may map to the same debuginfo
//! type metadata, that is, some struct `Struct<'a>` may have N instantiations
//! with different concrete substitutions for `'a`, and thus there will be N
//! `Ty` instances for the type `Struct<'a>` even though it is not generic
//! otherwise. Unfortunately this means that we cannot use `ty::type_id()` as
//! cheap identifier for type metadata -- we have done this in the past, but it
//! led to unnecessary metadata duplication in the best case and LLVM
//! assertions in the worst. However, the unique type ID as described above
//! *can* be used as identifier. Since it is comparatively expensive to
//! construct, though, `ty::type_id()` is still used additionally as an
//! optimization for cases where the exact same type has been seen before
//! (which is most of the time).

View file

@ -0,0 +1,71 @@
// .debug_gdb_scripts binary section.
use crate::llvm;
use crate::builder::Builder;
use crate::common::CodegenCx;
use crate::value::Value;
use rustc_codegen_ssa::traits::*;
use rustc_middle::bug;
use rustc_session::config::DebugInfo;
use rustc_span::symbol::sym;
/// Inserts a side-effect free instruction sequence that makes sure that the
/// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
pub fn insert_reference_to_gdb_debug_scripts_section_global(bx: &mut Builder<'_, '_, '_>) {
if needs_gdb_debug_scripts_section(bx) {
let gdb_debug_scripts_section = get_or_insert_gdb_debug_scripts_section_global(bx);
// Load just the first byte as that's all that's necessary to force
// LLVM to keep around the reference to the global.
let indices = [bx.const_i32(0), bx.const_i32(0)];
let element = bx.inbounds_gep(gdb_debug_scripts_section, &indices);
let volative_load_instruction = bx.volatile_load(element);
unsafe {
llvm::LLVMSetAlignment(volative_load_instruction, 1);
}
}
}
/// Allocates the global variable responsible for the .debug_gdb_scripts binary
/// section.
pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>) -> &'ll Value {
let c_section_var_name = "__rustc_debug_gdb_scripts_section__\0";
let section_var_name = &c_section_var_name[..c_section_var_name.len() - 1];
let section_var =
unsafe { llvm::LLVMGetNamedGlobal(cx.llmod, c_section_var_name.as_ptr().cast()) };
section_var.unwrap_or_else(|| {
let section_name = b".debug_gdb_scripts\0";
let section_contents = b"\x01gdb_load_rust_pretty_printers.py\0";
unsafe {
let llvm_type = cx.type_array(cx.type_i8(), section_contents.len() as u64);
let section_var = cx
.define_global(section_var_name, llvm_type)
.unwrap_or_else(|| bug!("symbol `{}` is already defined", section_var_name));
llvm::LLVMSetSection(section_var, section_name.as_ptr().cast());
llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents));
llvm::LLVMSetGlobalConstant(section_var, llvm::True);
llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global);
llvm::LLVMRustSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
// This should make sure that the whole section is not larger than
// the string it contains. Otherwise we get a warning from GDB.
llvm::LLVMSetAlignment(section_var, 1);
section_var
}
})
}
pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
let omit_gdb_pretty_printer_section = cx
.tcx
.sess
.contains_name(&cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
!omit_gdb_pretty_printer_section
&& cx.sess().opts.debuginfo != DebugInfo::None
&& cx.sess().target.target.options.emit_debug_gdb_scripts
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,563 @@
// See doc.rs for documentation.
mod doc;
use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
use self::metadata::{file_metadata, type_metadata, TypeMap, UNKNOWN_LINE_NUMBER};
use self::namespace::mangled_name_of_instance;
use self::type_names::compute_debuginfo_type_name;
use self::utils::{create_DIArray, is_node_local_to_unit, DIB};
use crate::abi::FnAbi;
use crate::builder::Builder;
use crate::common::CodegenCx;
use crate::llvm;
use crate::llvm::debuginfo::{
DIArray, DIBuilder, DIFile, DIFlags, DILexicalBlock, DISPFlags, DIScope, DIType, DIVariable,
};
use crate::value::Value;
use rustc_codegen_ssa::debuginfo::type_names;
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
use rustc_index::vec::IndexVec;
use rustc_middle::mir;
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeFoldable};
use rustc_session::config::{self, DebugInfo};
use rustc_span::symbol::Symbol;
use rustc_span::{self, BytePos, Span};
use rustc_target::abi::{LayoutOf, Primitive, Size};
use libc::c_uint;
use smallvec::SmallVec;
use std::cell::RefCell;
use tracing::debug;
mod create_scope_map;
pub mod gdb;
pub mod metadata;
mod namespace;
mod source_loc;
mod utils;
pub use self::create_scope_map::compute_mir_scopes;
pub use self::metadata::create_global_var_metadata;
pub use self::metadata::extend_scope_to_file;
#[allow(non_upper_case_globals)]
const DW_TAG_auto_variable: c_uint = 0x100;
#[allow(non_upper_case_globals)]
const DW_TAG_arg_variable: c_uint = 0x101;
/// A context object for maintaining all state needed by the debuginfo module.
pub struct CrateDebugContext<'a, 'tcx> {
llcontext: &'a llvm::Context,
llmod: &'a llvm::Module,
builder: &'a mut DIBuilder<'a>,
created_files: RefCell<FxHashMap<(Option<String>, Option<String>), &'a DIFile>>,
created_enum_disr_types: RefCell<FxHashMap<(DefId, Primitive), &'a DIType>>,
type_map: RefCell<TypeMap<'a, 'tcx>>,
namespace_map: RefCell<DefIdMap<&'a DIScope>>,
// This collection is used to assert that composite types (structs, enums,
// ...) have their members only set once:
composite_types_completed: RefCell<FxHashSet<&'a DIType>>,
}
impl Drop for CrateDebugContext<'a, 'tcx> {
fn drop(&mut self) {
unsafe {
llvm::LLVMRustDIBuilderDispose(&mut *(self.builder as *mut _));
}
}
}
impl<'a, 'tcx> CrateDebugContext<'a, 'tcx> {
pub fn new(llmod: &'a llvm::Module) -> Self {
debug!("CrateDebugContext::new");
let builder = unsafe { llvm::LLVMRustDIBuilderCreate(llmod) };
// DIBuilder inherits context from the module, so we'd better use the same one
let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
CrateDebugContext {
llcontext,
llmod,
builder,
created_files: Default::default(),
created_enum_disr_types: Default::default(),
type_map: Default::default(),
namespace_map: RefCell::new(Default::default()),
composite_types_completed: Default::default(),
}
}
}
/// Creates any deferred debug metadata nodes
pub fn finalize(cx: &CodegenCx<'_, '_>) {
if cx.dbg_cx.is_none() {
return;
}
debug!("finalize");
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.
gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
}
unsafe {
llvm::LLVMRustDIBuilderFinalize(DIB(cx));
// Debuginfo generation in LLVM by default uses a higher
// version of dwarf than macOS currently understands. We can
// instruct LLVM to emit an older version of dwarf, however,
// for macOS 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().cast(), 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().cast(), 1)
}
// Prevent bitcode readers from deleting the debug info.
let ptr = "Debug Info Version\0".as_ptr();
llvm::LLVMRustAddModuleFlag(cx.llmod, ptr.cast(), llvm::LLVMRustDebugMetadataVersion());
};
}
impl DebugInfoBuilderMethods for Builder<'a, 'll, 'tcx> {
// FIXME(eddyb) find a common convention for all of the debuginfo-related
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
fn dbg_var_addr(
&mut self,
dbg_var: &'ll DIVariable,
scope_metadata: &'ll DIScope,
variable_alloca: Self::Value,
direct_offset: Size,
indirect_offsets: &[Size],
span: Span,
) {
let cx = self.cx();
// Convert the direct and indirect offsets to address ops.
// FIXME(eddyb) use `const`s instead of getting the values via FFI,
// the values should match the ones in the DWARF standard anyway.
let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
let mut addr_ops = SmallVec::<[_; 8]>::new();
if direct_offset.bytes() > 0 {
addr_ops.push(op_plus_uconst());
addr_ops.push(direct_offset.bytes() as i64);
}
for &offset in indirect_offsets {
addr_ops.push(op_deref());
if offset.bytes() > 0 {
addr_ops.push(op_plus_uconst());
addr_ops.push(offset.bytes() as i64);
}
}
// FIXME(eddyb) maybe this information could be extracted from `dbg_var`,
// to avoid having to pass it down in both places?
// NB: `var` doesn't seem to know about the column, so that's a limitation.
let dbg_loc = cx.create_debug_loc(scope_metadata, span);
unsafe {
// FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`.
llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
DIB(cx),
variable_alloca,
dbg_var,
addr_ops.as_ptr(),
addr_ops.len() as c_uint,
dbg_loc,
self.llbb(),
);
}
}
fn set_source_location(&mut self, scope: &'ll DIScope, span: Span) {
debug!("set_source_location: {}", self.sess().source_map().span_to_string(span));
let dbg_loc = self.cx().create_debug_loc(scope, span);
unsafe {
llvm::LLVMSetCurrentDebugLocation(self.llbuilder, dbg_loc);
}
}
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
}
fn set_var_name(&mut self, value: &'ll Value, name: &str) {
// Avoid wasting time if LLVM value names aren't even enabled.
if self.sess().fewer_names() {
return;
}
// Only function parameters and instructions are local to a function,
// don't change the name of anything else (e.g. globals).
let param_or_inst = unsafe {
llvm::LLVMIsAArgument(value).is_some() || llvm::LLVMIsAInstruction(value).is_some()
};
if !param_or_inst {
return;
}
// Avoid replacing the name if it already exists.
// While we could combine the names somehow, it'd
// get noisy quick, and the usefulness is dubious.
if llvm::get_value_name(value).is_empty() {
llvm::set_value_name(value, name.as_bytes());
}
}
}
impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn create_function_debug_context(
&self,
instance: Instance<'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
llfn: &'ll Value,
mir: &mir::Body<'_>,
) -> Option<FunctionDebugContext<&'ll DIScope>> {
if self.sess().opts.debuginfo == DebugInfo::None {
return None;
}
let span = mir.span;
// This can be the case for functions inlined from another crate
if span.is_dummy() {
// FIXME(simulacrum): Probably can't happen; remove.
return None;
}
let def_id = instance.def_id();
let containing_scope = get_containing_scope(self, instance);
let loc = self.lookup_debug_loc(span.lo());
let file_metadata = file_metadata(self, &loc.file, def_id.krate);
let function_type_metadata = unsafe {
let fn_signature = get_function_signature(self, fn_abi);
llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), fn_signature)
};
// Find the enclosing function, in case this is a closure.
let def_key = self.tcx().def_key(def_id);
let mut name = def_key.disambiguated_data.data.to_string();
let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id);
// Get_template_parameters() will append a `<...>` clause to the function
// name if necessary.
let generics = self.tcx().generics_of(enclosing_fn_def_id);
let substs = instance.substs.truncate_to(self.tcx(), generics);
let template_parameters = get_template_parameters(self, &generics, substs, &mut name);
let linkage_name = &mangled_name_of_instance(self, instance).name;
// Omit the linkage_name if it is the same as subprogram name.
let linkage_name = if &name == linkage_name { "" } else { linkage_name };
// FIXME(eddyb) does this need to be separate from `loc.line` for some reason?
let scope_line = loc.line;
let mut flags = DIFlags::FlagPrototyped;
if fn_abi.ret.layout.abi.is_uninhabited() {
flags |= DIFlags::FlagNoReturn;
}
let mut spflags = DISPFlags::SPFlagDefinition;
if is_node_local_to_unit(self, def_id) {
spflags |= DISPFlags::SPFlagLocalToUnit;
}
if self.sess().opts.optimize != config::OptLevel::No {
spflags |= DISPFlags::SPFlagOptimized;
}
if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) {
if id.to_def_id() == def_id {
spflags |= DISPFlags::SPFlagMainSubprogram;
}
}
let fn_metadata = unsafe {
llvm::LLVMRustDIBuilderCreateFunction(
DIB(self),
containing_scope,
name.as_ptr().cast(),
name.len(),
linkage_name.as_ptr().cast(),
linkage_name.len(),
file_metadata,
loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
function_type_metadata,
scope_line.unwrap_or(UNKNOWN_LINE_NUMBER),
flags,
spflags,
llfn,
template_parameters,
None,
)
};
// Initialize fn debug context (including scopes).
// FIXME(eddyb) figure out a way to not need `Option` for `scope_metadata`.
let null_scope = DebugScope {
scope_metadata: None,
file_start_pos: BytePos(0),
file_end_pos: BytePos(0),
};
let mut fn_debug_context = FunctionDebugContext {
scopes: IndexVec::from_elem(null_scope, &mir.source_scopes),
defining_crate: def_id.krate,
};
// Fill in all the scopes, with the information from the MIR body.
compute_mir_scopes(self, mir, fn_metadata, &mut fn_debug_context);
return Some(fn_debug_context);
fn get_function_signature<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
) -> &'ll DIArray {
if cx.sess().opts.debuginfo == DebugInfo::Limited {
return create_DIArray(DIB(cx), &[]);
}
let mut signature = Vec::with_capacity(fn_abi.args.len() + 1);
// Return type -- llvm::DIBuilder wants this at index 0
signature.push(if fn_abi.ret.is_ignore() {
None
} else {
Some(type_metadata(cx, fn_abi.ret.layout.ty, rustc_span::DUMMY_SP))
});
// Arguments types
if cx.sess().target.target.options.is_like_msvc {
// FIXME(#42800):
// There is a bug in MSDIA that leads to a crash when it encounters
// a fixed-size array of `u8` or something zero-sized in a
// function-type (see #40477).
// As a workaround, we replace those fixed-size arrays with a
// pointer-type. So a function `fn foo(a: u8, b: [u8; 4])` would
// appear as `fn foo(a: u8, b: *const u8)` in debuginfo,
// and a function `fn bar(x: [(); 7])` as `fn bar(x: *const ())`.
// This transformed type is wrong, but these function types are
// already inaccurate due to ABI adjustments (see #42800).
signature.extend(fn_abi.args.iter().map(|arg| {
let t = arg.layout.ty;
let t = match t.kind {
ty::Array(ct, _)
if (ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() =>
{
cx.tcx.mk_imm_ptr(ct)
}
_ => t,
};
Some(type_metadata(cx, t, rustc_span::DUMMY_SP))
}));
} else {
signature.extend(
fn_abi
.args
.iter()
.map(|arg| Some(type_metadata(cx, arg.layout.ty, rustc_span::DUMMY_SP))),
);
}
create_DIArray(DIB(cx), &signature[..])
}
fn get_template_parameters<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
generics: &ty::Generics,
substs: SubstsRef<'tcx>,
name_to_append_suffix_to: &mut String,
) -> &'ll DIArray {
if substs.types().next().is_none() {
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_erasing_regions(ParamEnv::reveal_all(), actual_type);
// Add actual type name to <...> clause of function name
let actual_type_name = compute_debuginfo_type_name(cx.tcx(), 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 == DebugInfo::Full {
let names = get_parameter_names(cx, generics);
substs
.iter()
.zip(names)
.filter_map(|(kind, name)| {
if let GenericArgKind::Type(ty) = kind.unpack() {
let actual_type =
cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
let actual_type_metadata =
type_metadata(cx, actual_type, rustc_span::DUMMY_SP);
let name = name.as_str();
Some(unsafe {
Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
DIB(cx),
None,
name.as_ptr().cast(),
name.len(),
actual_type_metadata,
))
})
} else {
None
}
})
.collect()
} else {
vec![]
};
create_DIArray(DIB(cx), &template_params[..])
}
fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
let mut names = generics
.parent
.map_or(vec![], |def_id| get_parameter_names(cx, cx.tcx.generics_of(def_id)));
names.extend(generics.params.iter().map(|param| param.name));
names
}
fn get_containing_scope<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
instance: Instance<'tcx>,
) -> &'ll 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_id()).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.subst_and_normalize_erasing_regions(
instance.substs,
ty::ParamEnv::reveal_all(),
&cx.tcx.type_of(impl_def_id),
);
// Only "class" methods are generally understood by LLVM,
// so avoid methods on other types (e.g., `<*mut T>::null`).
match impl_self_ty.kind {
ty::Adt(def, ..) if !def.is_box() => {
// Again, only create type information if full debuginfo is enabled
if cx.sess().opts.debuginfo == DebugInfo::Full
&& !impl_self_ty.needs_subst()
{
Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP))
} else {
Some(namespace::item_namespace(cx, def.did))
}
}
_ => 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_id().krate,
index: cx
.tcx
.def_key(instance.def_id())
.parent
.expect("get_containing_scope: missing parent?"),
},
)
})
}
}
fn create_vtable_metadata(&self, ty: Ty<'tcx>, vtable: Self::Value) {
metadata::create_vtable_metadata(self, ty, vtable)
}
fn extend_scope_to_file(
&self,
scope_metadata: &'ll DIScope,
file: &rustc_span::SourceFile,
defining_crate: CrateNum,
) -> &'ll DILexicalBlock {
metadata::extend_scope_to_file(&self, scope_metadata, file, defining_crate)
}
fn debuginfo_finalize(&self) {
finalize(self)
}
// FIXME(eddyb) find a common convention for all of the debuginfo-related
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
fn create_dbg_var(
&self,
dbg_context: &FunctionDebugContext<&'ll DIScope>,
variable_name: Symbol,
variable_type: Ty<'tcx>,
scope_metadata: &'ll DIScope,
variable_kind: VariableKind,
span: Span,
) -> &'ll DIVariable {
let loc = self.lookup_debug_loc(span.lo());
let file_metadata = file_metadata(self, &loc.file, dbg_context.defining_crate);
let type_metadata = type_metadata(self, variable_type, span);
let (argument_index, dwarf_tag) = match variable_kind {
ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
LocalVariable => (0, DW_TAG_auto_variable),
};
let align = self.align_of(variable_type);
let name = variable_name.as_str();
unsafe {
llvm::LLVMRustDIBuilderCreateVariable(
DIB(self),
dwarf_tag,
scope_metadata,
name.as_ptr().cast(),
name.len(),
file_metadata,
loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
type_metadata,
true,
DIFlags::FlagZero,
argument_index,
align.bytes() as u32,
)
}
}
}

View file

@ -0,0 +1,48 @@
// Namespace Handling.
use super::utils::{debug_context, DIB};
use rustc_middle::ty::{self, Instance};
use crate::common::CodegenCx;
use crate::llvm;
use crate::llvm::debuginfo::DIScope;
use rustc_hir::def_id::DefId;
use rustc_hir::definitions::DefPathData;
pub fn mangled_name_of_instance<'a, 'tcx>(
cx: &CodegenCx<'a, 'tcx>,
instance: Instance<'tcx>,
) -> ty::SymbolName<'tcx> {
let tcx = cx.tcx;
tcx.symbol_name(instance)
}
pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
if let Some(&scope) = debug_context(cx).namespace_map.borrow().get(&def_id) {
return scope;
}
let def_key = cx.tcx.def_key(def_id);
let parent_scope = def_key
.parent
.map(|parent| item_namespace(cx, DefId { krate: def_id.krate, index: parent }));
let namespace_name = match def_key.disambiguated_data.data {
DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate),
data => data.as_symbol(),
};
let namespace_name = namespace_name.as_str();
let scope = unsafe {
llvm::LLVMRustDIBuilderCreateNameSpace(
DIB(cx),
parent_scope,
namespace_name.as_ptr().cast(),
namespace_name.len(),
false, // ExportSymbols (only relevant for C++ anonymous namespaces)
)
};
debug_context(cx).namespace_map.borrow_mut().insert(def_id, scope);
scope
}

View file

@ -0,0 +1,61 @@
use super::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER};
use super::utils::debug_context;
use crate::common::CodegenCx;
use crate::llvm::debuginfo::DIScope;
use crate::llvm::{self, Value};
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::sync::Lrc;
use rustc_span::{BytePos, Pos, SourceFile, SourceFileAndLine, Span};
/// A source code location used to generate debug information.
pub struct DebugLoc {
/// Information about the original source file.
pub file: Lrc<SourceFile>,
/// The (1-based) line number.
pub line: Option<u32>,
/// The (1-based) column number.
pub col: Option<u32>,
}
impl CodegenCx<'ll, '_> {
/// Looks up debug source information about a `BytePos`.
pub fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
Ok(SourceFileAndLine { sf: file, line }) => {
let line_pos = file.line_begin_pos(pos);
// Use 1-based indexing.
let line = (line + 1) as u32;
let col = (pos - line_pos).to_u32() + 1;
(file, Some(line), Some(col))
}
Err(file) => (file, None, None),
};
// For MSVC, omit the column number.
// Otherwise, emit it. This mimics clang behaviour.
// See discussion in https://github.com/rust-lang/rust/issues/42921
if self.sess().target.target.options.is_like_msvc {
DebugLoc { file, line, col: None }
} else {
DebugLoc { file, line, col }
}
}
pub fn create_debug_loc(&self, scope: &'ll DIScope, span: Span) -> &'ll Value {
let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
unsafe {
llvm::LLVMRustDIBuilderCreateDebugLocation(
debug_context(self).llcontext,
line.unwrap_or(UNKNOWN_LINE_NUMBER),
col.unwrap_or(UNKNOWN_COLUMN_NUMBER),
scope,
None,
)
}
}
}

View file

@ -0,0 +1,43 @@
// Utility Functions.
use super::namespace::item_namespace;
use super::CrateDebugContext;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::DefIdTree;
use crate::common::CodegenCx;
use crate::llvm;
use crate::llvm::debuginfo::{DIArray, DIBuilder, DIDescriptor, DIScope};
pub fn is_node_local_to_unit(cx: &CodegenCx<'_, '_>, def_id: DefId) -> bool {
// The is_local_to_unit flag indicates whether a function is local to the
// current compilation unit (i.e., if it is *static* in the C-sense). The
// *reachable* set should provide a good approximation of this, as it
// contains everything that might leak out of the current crate (by being
// externally visible or by being inlined into something externally
// visible). It might better to use the `exported_items` set from
// `driver::CrateAnalysis` in the future, but (atm) this set is not
// available in the codegen pass.
!cx.tcx.is_reachable_non_generic(def_id)
}
#[allow(non_snake_case)]
pub fn create_DIArray(builder: &DIBuilder<'ll>, arr: &[Option<&'ll DIDescriptor>]) -> &'ll DIArray {
unsafe { llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) }
}
#[inline]
pub fn debug_context(cx: &'a CodegenCx<'ll, 'tcx>) -> &'a CrateDebugContext<'ll, 'tcx> {
cx.dbg_cx.as_ref().unwrap()
}
#[inline]
#[allow(non_snake_case)]
pub fn DIB(cx: &'a CodegenCx<'ll, '_>) -> &'a DIBuilder<'ll> {
cx.dbg_cx.as_ref().unwrap().builder
}
pub fn get_namespace_for_item(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
item_namespace(cx, cx.tcx.parent(def_id).expect("get_namespace_for_item: missing parent?"))
}