mv compiler to compiler/
This commit is contained in:
parent
db534b3ac2
commit
9e5f7d5631
1686 changed files with 941 additions and 1051 deletions
|
@ -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,
|
||||
};
|
||||
}
|
179
compiler/rustc_codegen_llvm/src/debuginfo/doc.rs
Normal file
179
compiler/rustc_codegen_llvm/src/debuginfo/doc.rs
Normal 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).
|
71
compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
Normal file
71
compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
Normal 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
|
||||
}
|
2585
compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Normal file
2585
compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Normal file
File diff suppressed because it is too large
Load diff
563
compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
Normal file
563
compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
Normal 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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
48
compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
Normal file
48
compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
Normal 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
|
||||
}
|
61
compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs
Normal file
61
compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs
Normal 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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
43
compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
Normal file
43
compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
Normal 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?"))
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue