diff options
| author | mark <markm@cs.wisc.edu> | 2020-08-27 22:58:48 -0500 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2020-08-30 18:45:07 +0300 |
| commit | 9e5f7d5631b8f4009ac1c693e585d4b7108d4275 (patch) | |
| tree | 158a05eb3f204a8e72939b58427d0c2787a4eade /compiler/rustc_codegen_llvm/src/debuginfo | |
| parent | db534b3ac286cf45688c3bbae6aa6e77439e52d2 (diff) | |
| download | rust-9e5f7d5631b8f4009ac1c693e585d4b7108d4275.tar.gz rust-9e5f7d5631b8f4009ac1c693e585d4b7108d4275.zip | |
mv compiler to compiler/
Diffstat (limited to 'compiler/rustc_codegen_llvm/src/debuginfo')
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs | 95 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/debuginfo/doc.rs | 179 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs | 71 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 2585 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | 563 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs | 48 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs | 61 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/debuginfo/utils.rs | 43 |
8 files changed, 3645 insertions, 0 deletions
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs new file mode 100644 index 00000000000..7f47b61de3f --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -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, + }; +} diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/doc.rs b/compiler/rustc_codegen_llvm/src/debuginfo/doc.rs new file mode 100644 index 00000000000..b3a8fa29887 --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/debuginfo/doc.rs @@ -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). diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs new file mode 100644 index 00000000000..29edd66049c --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -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 +} diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs new file mode 100644 index 00000000000..9d92d53775c --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -0,0 +1,2585 @@ +use self::EnumTagInfo::*; +use self::MemberDescriptionFactory::*; +use self::RecursiveTypeDescription::*; + +use super::namespace::mangled_name_of_instance; +use super::type_names::compute_debuginfo_type_name; +use super::utils::{ + create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, DIB, +}; +use super::CrateDebugContext; + +use crate::abi; +use crate::common::CodegenCx; +use crate::llvm; +use crate::llvm::debuginfo::{ + DIArray, DICompositeType, DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, + DebugEmissionKind, +}; +use crate::value::Value; + +use rustc_ast as ast; +use rustc_codegen_ssa::traits::*; +use rustc_data_structures::const_cstr; +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_fs_util::path_to_c_string; +use rustc_hir::def::CtorKind; +use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::ich::NodeIdHashingMode; +use rustc_middle::mir::interpret::truncate; +use rustc_middle::mir::{self, Field, GeneratorLayout}; +use rustc_middle::ty::layout::{self, IntegerExt, PrimitiveExt, TyAndLayout}; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::Instance; +use rustc_middle::ty::{self, AdtKind, GeneratorSubsts, ParamEnv, Ty, TyCtxt}; +use rustc_middle::{bug, span_bug}; +use rustc_session::config::{self, DebugInfo}; +use rustc_span::symbol::{Interner, Symbol}; +use rustc_span::{self, SourceFile, SourceFileHash, Span}; +use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, LayoutOf, TagEncoding}; +use rustc_target::abi::{Int, Pointer, F32, F64}; +use rustc_target::abi::{Primitive, Size, VariantIdx, Variants}; +use tracing::debug; + +use libc::{c_longlong, c_uint}; +use std::collections::hash_map::Entry; +use std::fmt::{self, Write}; +use std::hash::{Hash, Hasher}; +use std::iter; +use std::path::{Path, PathBuf}; +use std::ptr; + +impl PartialEq for llvm::Metadata { + fn eq(&self, other: &Self) -> bool { + ptr::eq(self, other) + } +} + +impl Eq for llvm::Metadata {} + +impl Hash for llvm::Metadata { + fn hash<H: Hasher>(&self, hasher: &mut H) { + (self as *const Self).hash(hasher); + } +} + +impl fmt::Debug for llvm::Metadata { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (self as *const Self).fmt(f) + } +} + +// From DWARF 5. +// See http://www.dwarfstd.org/ShowIssue.php?issue=140129.1. +const DW_LANG_RUST: c_uint = 0x1c; +#[allow(non_upper_case_globals)] +const DW_ATE_boolean: c_uint = 0x02; +#[allow(non_upper_case_globals)] +const DW_ATE_float: c_uint = 0x04; +#[allow(non_upper_case_globals)] +const DW_ATE_signed: c_uint = 0x05; +#[allow(non_upper_case_globals)] +const DW_ATE_unsigned: c_uint = 0x07; +#[allow(non_upper_case_globals)] +const DW_ATE_unsigned_char: c_uint = 0x08; + +pub const UNKNOWN_LINE_NUMBER: c_uint = 0; +pub const UNKNOWN_COLUMN_NUMBER: c_uint = 0; + +pub const NO_SCOPE_METADATA: Option<&DIScope> = None; + +#[derive(Copy, Debug, Hash, Eq, PartialEq, Clone)] +pub struct UniqueTypeId(Symbol); + +/// The `TypeMap` is where the `CrateDebugContext` holds the type metadata nodes +/// created so far. The metadata nodes are indexed by `UniqueTypeId`, and, for +/// faster lookup, also by `Ty`. The `TypeMap` is responsible for creating +/// `UniqueTypeId`s. +#[derive(Default)] +pub struct TypeMap<'ll, 'tcx> { + /// The `UniqueTypeId`s created so far. + unique_id_interner: Interner, + /// A map from `UniqueTypeId` to debuginfo metadata for that type. This is a 1:1 mapping. + unique_id_to_metadata: FxHashMap<UniqueTypeId, &'ll DIType>, + /// A map from types to debuginfo metadata. This is an N:1 mapping. + type_to_metadata: FxHashMap<Ty<'tcx>, &'ll DIType>, + /// A map from types to `UniqueTypeId`. This is an N:1 mapping. + type_to_unique_id: FxHashMap<Ty<'tcx>, UniqueTypeId>, +} + +impl TypeMap<'ll, 'tcx> { + /// Adds a Ty to metadata mapping to the TypeMap. The method will fail if + /// the mapping already exists. + fn register_type_with_metadata(&mut self, type_: Ty<'tcx>, metadata: &'ll DIType) { + if self.type_to_metadata.insert(type_, metadata).is_some() { + bug!("type metadata for `Ty` '{}' is already in the `TypeMap`!", type_); + } + } + + /// Removes a `Ty`-to-metadata mapping. + /// This is useful when computing the metadata for a potentially + /// recursive type (e.g., a function pointer of the form: + /// + /// fn foo() -> impl Copy { foo } + /// + /// This kind of type cannot be properly represented + /// via LLVM debuginfo. As a workaround, + /// we register a temporary Ty to metadata mapping + /// for the function before we compute its actual metadata. + /// If the metadata computation ends up recursing back to the + /// original function, it will use the temporary mapping + /// for the inner self-reference, preventing us from + /// recursing forever. + /// + /// This function is used to remove the temporary metadata + /// mapping after we've computed the actual metadata. + fn remove_type(&mut self, type_: Ty<'tcx>) { + if self.type_to_metadata.remove(type_).is_none() { + bug!("type metadata `Ty` '{}' is not in the `TypeMap`!", type_); + } + } + + /// Adds a `UniqueTypeId` to metadata mapping to the `TypeMap`. The method will + /// fail if the mapping already exists. + fn register_unique_id_with_metadata( + &mut self, + unique_type_id: UniqueTypeId, + metadata: &'ll DIType, + ) { + if self.unique_id_to_metadata.insert(unique_type_id, metadata).is_some() { + bug!( + "type metadata for unique ID '{}' is already in the `TypeMap`!", + self.get_unique_type_id_as_string(unique_type_id) + ); + } + } + + fn find_metadata_for_type(&self, type_: Ty<'tcx>) -> Option<&'ll DIType> { + self.type_to_metadata.get(&type_).cloned() + } + + fn find_metadata_for_unique_id(&self, unique_type_id: UniqueTypeId) -> Option<&'ll DIType> { + self.unique_id_to_metadata.get(&unique_type_id).cloned() + } + + /// Gets the string representation of a `UniqueTypeId`. This method will fail if + /// the ID is unknown. + fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> &str { + let UniqueTypeId(interner_key) = unique_type_id; + self.unique_id_interner.get(interner_key) + } + + /// Gets the `UniqueTypeId` for the given type. If the `UniqueTypeId` for the given + /// type has been requested before, this is just a table lookup. Otherwise, an + /// ID will be generated and stored for later lookup. + fn get_unique_type_id_of_type<'a>( + &mut self, + cx: &CodegenCx<'a, 'tcx>, + type_: Ty<'tcx>, + ) -> UniqueTypeId { + // Let's see if we already have something in the cache. + if let Some(unique_type_id) = self.type_to_unique_id.get(&type_).cloned() { + return unique_type_id; + } + // If not, generate one. + + // The hasher we are using to generate the UniqueTypeId. We want + // something that provides more than the 64 bits of the DefaultHasher. + let mut hasher = StableHasher::new(); + let mut hcx = cx.tcx.create_stable_hashing_context(); + let type_ = cx.tcx.erase_regions(&type_); + hcx.while_hashing_spans(false, |hcx| { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + type_.hash_stable(hcx, &mut hasher); + }); + }); + let unique_type_id = hasher.finish::<Fingerprint>().to_hex(); + + let key = self.unique_id_interner.intern(&unique_type_id); + self.type_to_unique_id.insert(type_, UniqueTypeId(key)); + + UniqueTypeId(key) + } + + /// Gets the `UniqueTypeId` for an enum variant. Enum variants are not really + /// types of their own, so they need special handling. We still need a + /// `UniqueTypeId` for them, since to debuginfo they *are* real types. + fn get_unique_type_id_of_enum_variant<'a>( + &mut self, + cx: &CodegenCx<'a, 'tcx>, + enum_type: Ty<'tcx>, + variant_name: &str, + ) -> UniqueTypeId { + let enum_type_id = self.get_unique_type_id_of_type(cx, enum_type); + let enum_variant_type_id = + format!("{}::{}", self.get_unique_type_id_as_string(enum_type_id), variant_name); + let interner_key = self.unique_id_interner.intern(&enum_variant_type_id); + UniqueTypeId(interner_key) + } + + /// Gets the unique type ID string for an enum variant part. + /// Variant parts are not types and shouldn't really have their own ID, + /// but it makes `set_members_of_composite_type()` simpler. + fn get_unique_type_id_str_of_enum_variant_part( + &mut self, + enum_type_id: UniqueTypeId, + ) -> String { + format!("{}_variant_part", self.get_unique_type_id_as_string(enum_type_id)) + } +} + +/// A description of some recursive type. It can either be already finished (as +/// with `FinalMetadata`) or it is not yet finished, but contains all information +/// needed to generate the missing parts of the description. See the +/// documentation section on Recursive Types at the top of this file for more +/// information. +enum RecursiveTypeDescription<'ll, 'tcx> { + UnfinishedMetadata { + unfinished_type: Ty<'tcx>, + unique_type_id: UniqueTypeId, + metadata_stub: &'ll DICompositeType, + member_holding_stub: &'ll DICompositeType, + member_description_factory: MemberDescriptionFactory<'ll, 'tcx>, + }, + FinalMetadata(&'ll DICompositeType), +} + +fn create_and_register_recursive_type_forward_declaration( + cx: &CodegenCx<'ll, 'tcx>, + unfinished_type: Ty<'tcx>, + unique_type_id: UniqueTypeId, + metadata_stub: &'ll DICompositeType, + member_holding_stub: &'ll DICompositeType, + member_description_factory: MemberDescriptionFactory<'ll, 'tcx>, +) -> RecursiveTypeDescription<'ll, 'tcx> { + // Insert the stub into the `TypeMap` in order to allow for recursive references. + let mut type_map = debug_context(cx).type_map.borrow_mut(); + type_map.register_unique_id_with_metadata(unique_type_id, metadata_stub); + type_map.register_type_with_metadata(unfinished_type, metadata_stub); + + UnfinishedMetadata { + unfinished_type, + unique_type_id, + metadata_stub, + member_holding_stub, + member_description_factory, + } +} + +impl RecursiveTypeDescription<'ll, 'tcx> { + /// Finishes up the description of the type in question (mostly by providing + /// descriptions of the fields of the given type) and returns the final type + /// metadata. + fn finalize(&self, cx: &CodegenCx<'ll, 'tcx>) -> MetadataCreationResult<'ll> { + match *self { + FinalMetadata(metadata) => MetadataCreationResult::new(metadata, false), + UnfinishedMetadata { + unfinished_type, + unique_type_id, + metadata_stub, + member_holding_stub, + ref member_description_factory, + } => { + // Make sure that we have a forward declaration of the type in + // the TypeMap so that recursive references are possible. This + // will always be the case if the RecursiveTypeDescription has + // been properly created through the + // `create_and_register_recursive_type_forward_declaration()` + // function. + { + let type_map = debug_context(cx).type_map.borrow(); + if type_map.find_metadata_for_unique_id(unique_type_id).is_none() + || type_map.find_metadata_for_type(unfinished_type).is_none() + { + bug!( + "Forward declaration of potentially recursive type \ + '{:?}' was not found in TypeMap!", + unfinished_type + ); + } + } + + // ... then create the member descriptions ... + let member_descriptions = member_description_factory.create_member_descriptions(cx); + + // ... and attach them to the stub to complete it. + set_members_of_composite_type( + cx, + unfinished_type, + member_holding_stub, + member_descriptions, + ); + MetadataCreationResult::new(metadata_stub, true) + } + } + } +} + +/// Returns from the enclosing function if the type metadata with the given +/// unique ID can be found in the type map. +macro_rules! return_if_metadata_created_in_meantime { + ($cx: expr, $unique_type_id: expr) => { + if let Some(metadata) = + debug_context($cx).type_map.borrow().find_metadata_for_unique_id($unique_type_id) + { + return MetadataCreationResult::new(metadata, true); + } + }; +} + +fn fixed_vec_metadata( + cx: &CodegenCx<'ll, 'tcx>, + unique_type_id: UniqueTypeId, + array_or_slice_type: Ty<'tcx>, + element_type: Ty<'tcx>, + span: Span, +) -> MetadataCreationResult<'ll> { + let element_type_metadata = type_metadata(cx, element_type, span); + + return_if_metadata_created_in_meantime!(cx, unique_type_id); + + let (size, align) = cx.size_and_align_of(array_or_slice_type); + + let upper_bound = match array_or_slice_type.kind { + ty::Array(_, len) => len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong, + _ => -1, + }; + + let subrange = + unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) }; + + let subscripts = create_DIArray(DIB(cx), &[subrange]); + let metadata = unsafe { + llvm::LLVMRustDIBuilderCreateArrayType( + DIB(cx), + size.bits(), + align.bits() as u32, + element_type_metadata, + subscripts, + ) + }; + + MetadataCreationResult::new(metadata, false) +} + +fn vec_slice_metadata( + cx: &CodegenCx<'ll, 'tcx>, + slice_ptr_type: Ty<'tcx>, + element_type: Ty<'tcx>, + unique_type_id: UniqueTypeId, + span: Span, +) -> MetadataCreationResult<'ll> { + let data_ptr_type = cx.tcx.mk_imm_ptr(element_type); + + let data_ptr_metadata = type_metadata(cx, data_ptr_type, span); + + return_if_metadata_created_in_meantime!(cx, unique_type_id); + + let slice_type_name = compute_debuginfo_type_name(cx.tcx, slice_ptr_type, true); + + let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type); + let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize); + + let member_descriptions = vec![ + MemberDescription { + name: "data_ptr".to_owned(), + type_metadata: data_ptr_metadata, + offset: Size::ZERO, + size: pointer_size, + align: pointer_align, + flags: DIFlags::FlagZero, + discriminant: None, + source_info: None, + }, + MemberDescription { + name: "length".to_owned(), + type_metadata: type_metadata(cx, cx.tcx.types.usize, span), + offset: pointer_size, + size: usize_size, + align: usize_align, + flags: DIFlags::FlagZero, + discriminant: None, + source_info: None, + }, + ]; + + let file_metadata = unknown_file_metadata(cx); + + let metadata = composite_type_metadata( + cx, + slice_ptr_type, + &slice_type_name[..], + unique_type_id, + member_descriptions, + NO_SCOPE_METADATA, + file_metadata, + span, + ); + MetadataCreationResult::new(metadata, false) +} + +fn subroutine_type_metadata( + cx: &CodegenCx<'ll, 'tcx>, + unique_type_id: UniqueTypeId, + signature: ty::PolyFnSig<'tcx>, + span: Span, +) -> MetadataCreationResult<'ll> { + let signature = + cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &signature); + + let signature_metadata: Vec<_> = iter::once( + // return type + match signature.output().kind { + ty::Tuple(ref tys) if tys.is_empty() => None, + _ => Some(type_metadata(cx, signature.output(), span)), + }, + ) + .chain( + // regular arguments + signature.inputs().iter().map(|argument_type| Some(type_metadata(cx, argument_type, span))), + ) + .collect(); + + return_if_metadata_created_in_meantime!(cx, unique_type_id); + + MetadataCreationResult::new( + unsafe { + llvm::LLVMRustDIBuilderCreateSubroutineType( + DIB(cx), + create_DIArray(DIB(cx), &signature_metadata[..]), + ) + }, + false, + ) +} + +// FIXME(1563): This is all a bit of a hack because 'trait pointer' is an ill- +// defined concept. For the case of an actual trait pointer (i.e., `Box<Trait>`, +// `&Trait`), `trait_object_type` should be the whole thing (e.g, `Box<Trait>`) and +// `trait_type` should be the actual trait (e.g., `Trait`). Where the trait is part +// of a DST struct, there is no `trait_object_type` and the results of this +// function will be a little bit weird. +fn trait_pointer_metadata( + cx: &CodegenCx<'ll, 'tcx>, + trait_type: Ty<'tcx>, + trait_object_type: Option<Ty<'tcx>>, + unique_type_id: UniqueTypeId, +) -> &'ll DIType { + // The implementation provided here is a stub. It makes sure that the trait + // type is assigned the correct name, size, namespace, and source location. + // However, it does not describe the trait's methods. + + let containing_scope = match trait_type.kind { + ty::Dynamic(ref data, ..) => { + data.principal_def_id().map(|did| get_namespace_for_item(cx, did)) + } + _ => { + bug!( + "debuginfo: unexpected trait-object type in \ + trait_pointer_metadata(): {:?}", + trait_type + ); + } + }; + + let trait_object_type = trait_object_type.unwrap_or(trait_type); + let trait_type_name = compute_debuginfo_type_name(cx.tcx, trait_object_type, false); + + let file_metadata = unknown_file_metadata(cx); + + let layout = cx.layout_of(cx.tcx.mk_mut_ptr(trait_type)); + + assert_eq!(abi::FAT_PTR_ADDR, 0); + assert_eq!(abi::FAT_PTR_EXTRA, 1); + + let data_ptr_field = layout.field(cx, 0); + let vtable_field = layout.field(cx, 1); + let member_descriptions = vec![ + MemberDescription { + name: "pointer".to_owned(), + type_metadata: type_metadata( + cx, + cx.tcx.mk_mut_ptr(cx.tcx.types.u8), + rustc_span::DUMMY_SP, + ), + offset: layout.fields.offset(0), + size: data_ptr_field.size, + align: data_ptr_field.align.abi, + flags: DIFlags::FlagArtificial, + discriminant: None, + source_info: None, + }, + MemberDescription { + name: "vtable".to_owned(), + type_metadata: type_metadata(cx, vtable_field.ty, rustc_span::DUMMY_SP), + offset: layout.fields.offset(1), + size: vtable_field.size, + align: vtable_field.align.abi, + flags: DIFlags::FlagArtificial, + discriminant: None, + source_info: None, + }, + ]; + + composite_type_metadata( + cx, + trait_object_type, + &trait_type_name[..], + unique_type_id, + member_descriptions, + containing_scope, + file_metadata, + rustc_span::DUMMY_SP, + ) +} + +pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Span) -> &'ll DIType { + // Get the unique type ID of this type. + let unique_type_id = { + let mut type_map = debug_context(cx).type_map.borrow_mut(); + // First, try to find the type in `TypeMap`. If we have seen it before, we + // can exit early here. + match type_map.find_metadata_for_type(t) { + Some(metadata) => { + return metadata; + } + None => { + // The Ty is not in the `TypeMap` but maybe we have already seen + // an equivalent type (e.g., only differing in region arguments). + // In order to find out, generate the unique type ID and look + // that up. + let unique_type_id = type_map.get_unique_type_id_of_type(cx, t); + match type_map.find_metadata_for_unique_id(unique_type_id) { + Some(metadata) => { + // There is already an equivalent type in the TypeMap. + // Register this Ty as an alias in the cache and + // return the cached metadata. + type_map.register_type_with_metadata(t, metadata); + return metadata; + } + None => { + // There really is no type metadata for this type, so + // proceed by creating it. + unique_type_id + } + } + } + } + }; + + debug!("type_metadata: {:?}", t); + + let ptr_metadata = |ty: Ty<'tcx>| match ty.kind { + ty::Slice(typ) => Ok(vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span)), + ty::Str => Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id, usage_site_span)), + ty::Dynamic(..) => Ok(MetadataCreationResult::new( + trait_pointer_metadata(cx, ty, Some(t), unique_type_id), + false, + )), + _ => { + let pointee_metadata = type_metadata(cx, ty, usage_site_span); + + if let Some(metadata) = + debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) + { + return Err(metadata); + } + + Ok(MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), false)) + } + }; + + let MetadataCreationResult { metadata, already_stored_in_typemap } = match t.kind { + ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => { + MetadataCreationResult::new(basic_type_metadata(cx, t), false) + } + ty::Tuple(ref elements) if elements.is_empty() => { + MetadataCreationResult::new(basic_type_metadata(cx, t), false) + } + ty::Array(typ, _) | ty::Slice(typ) => { + fixed_vec_metadata(cx, unique_type_id, t, typ, usage_site_span) + } + ty::Str => fixed_vec_metadata(cx, unique_type_id, t, cx.tcx.types.i8, usage_site_span), + ty::Dynamic(..) => { + MetadataCreationResult::new(trait_pointer_metadata(cx, t, None, unique_type_id), false) + } + ty::Foreign(..) => { + MetadataCreationResult::new(foreign_type_metadata(cx, t, unique_type_id), false) + } + ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => match ptr_metadata(ty) { + Ok(res) => res, + Err(metadata) => return metadata, + }, + ty::Adt(def, _) if def.is_box() => match ptr_metadata(t.boxed_ty()) { + Ok(res) => res, + Err(metadata) => return metadata, + }, + ty::FnDef(..) | ty::FnPtr(_) => { + if let Some(metadata) = + debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) + { + return metadata; + } + + // It's possible to create a self-referential + // type in Rust by using 'impl trait': + // + // fn foo() -> impl Copy { foo } + // + // See `TypeMap::remove_type` for more detals + // about the workaround. + + let temp_type = { + unsafe { + // The choice of type here is pretty arbitrary - + // anything reading the debuginfo for a recursive + // type is going to see *something* weird - the only + // question is what exactly it will see. + let name = "<recur_type>"; + llvm::LLVMRustDIBuilderCreateBasicType( + DIB(cx), + name.as_ptr().cast(), + name.len(), + cx.size_of(t).bits(), + DW_ATE_unsigned, + ) + } + }; + + let type_map = &debug_context(cx).type_map; + type_map.borrow_mut().register_type_with_metadata(t, temp_type); + + let fn_metadata = + subroutine_type_metadata(cx, unique_type_id, t.fn_sig(cx.tcx), usage_site_span) + .metadata; + + type_map.borrow_mut().remove_type(t); + + // This is actually a function pointer, so wrap it in pointer DI. + MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false) + } + ty::Closure(def_id, substs) => { + let upvar_tys: Vec<_> = substs.as_closure().upvar_tys().collect(); + let containing_scope = get_namespace_for_item(cx, def_id); + prepare_tuple_metadata( + cx, + t, + &upvar_tys, + unique_type_id, + usage_site_span, + Some(containing_scope), + ) + .finalize(cx) + } + ty::Generator(def_id, substs, _) => { + let upvar_tys: Vec<_> = substs + .as_generator() + .prefix_tys() + .map(|t| cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t)) + .collect(); + prepare_enum_metadata(cx, t, def_id, unique_type_id, usage_site_span, upvar_tys) + .finalize(cx) + } + ty::Adt(def, ..) => match def.adt_kind() { + AdtKind::Struct => { + prepare_struct_metadata(cx, t, unique_type_id, usage_site_span).finalize(cx) + } + AdtKind::Union => { + prepare_union_metadata(cx, t, unique_type_id, usage_site_span).finalize(cx) + } + AdtKind::Enum => { + prepare_enum_metadata(cx, t, def.did, unique_type_id, usage_site_span, vec![]) + .finalize(cx) + } + }, + ty::Tuple(ref elements) => { + let tys: Vec<_> = elements.iter().map(|k| k.expect_ty()).collect(); + prepare_tuple_metadata(cx, t, &tys, unique_type_id, usage_site_span, NO_SCOPE_METADATA) + .finalize(cx) + } + // Type parameters from polymorphized functions. + ty::Param(_) => MetadataCreationResult::new(param_type_metadata(cx, t), false), + _ => bug!("debuginfo: unexpected type in type_metadata: {:?}", t), + }; + + { + let mut type_map = debug_context(cx).type_map.borrow_mut(); + + if already_stored_in_typemap { + // Also make sure that we already have a `TypeMap` entry for the unique type ID. + let metadata_for_uid = match type_map.find_metadata_for_unique_id(unique_type_id) { + Some(metadata) => metadata, + None => { + span_bug!( + usage_site_span, + "expected type metadata for unique \ + type ID '{}' to already be in \ + the `debuginfo::TypeMap` but it \ + was not. (Ty = {})", + type_map.get_unique_type_id_as_string(unique_type_id), + t + ); + } + }; + + match type_map.find_metadata_for_type(t) { + Some(metadata) => { + if metadata != metadata_for_uid { + span_bug!( + usage_site_span, + "mismatch between `Ty` and \ + `UniqueTypeId` maps in \ + `debuginfo::TypeMap`. \ + UniqueTypeId={}, Ty={}", + type_map.get_unique_type_id_as_string(unique_type_id), + t + ); + } + } + None => { + type_map.register_type_with_metadata(t, metadata); + } + } + } else { + type_map.register_type_with_metadata(t, metadata); + type_map.register_unique_id_with_metadata(unique_type_id, metadata); + } + } + + metadata +} + +fn hex_encode(data: &[u8]) -> String { + let mut hex_string = String::with_capacity(data.len() * 2); + for byte in data.iter() { + write!(&mut hex_string, "{:02x}", byte).unwrap(); + } + hex_string +} + +pub fn file_metadata( + cx: &CodegenCx<'ll, '_>, + source_file: &SourceFile, + defining_crate: CrateNum, +) -> &'ll DIFile { + debug!("file_metadata: file_name: {}, defining_crate: {}", source_file.name, defining_crate); + + let hash = Some(&source_file.src_hash); + let file_name = Some(source_file.name.to_string()); + let directory = if defining_crate == LOCAL_CRATE { + Some(cx.sess().working_dir.0.to_string_lossy().to_string()) + } else { + // If the path comes from an upstream crate we assume it has been made + // independent of the compiler's working directory one way or another. + None + }; + file_metadata_raw(cx, file_name, directory, hash) +} + +pub fn unknown_file_metadata(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile { + file_metadata_raw(cx, None, None, None) +} + +fn file_metadata_raw( + cx: &CodegenCx<'ll, '_>, + file_name: Option<String>, + directory: Option<String>, + hash: Option<&SourceFileHash>, +) -> &'ll DIFile { + let key = (file_name, directory); + + match debug_context(cx).created_files.borrow_mut().entry(key) { + Entry::Occupied(o) => o.get(), + Entry::Vacant(v) => { + let (file_name, directory) = v.key(); + debug!("file_metadata: file_name: {:?}, directory: {:?}", file_name, directory); + + let file_name = file_name.as_deref().unwrap_or("<unknown>"); + let directory = directory.as_deref().unwrap_or(""); + + let (hash_kind, hash_value) = match hash { + Some(hash) => { + let kind = match hash.kind { + rustc_span::SourceFileHashAlgorithm::Md5 => llvm::ChecksumKind::MD5, + rustc_span::SourceFileHashAlgorithm::Sha1 => llvm::ChecksumKind::SHA1, + }; + (kind, hex_encode(hash.hash_bytes())) + } + None => (llvm::ChecksumKind::None, String::new()), + }; + + let file_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateFile( + DIB(cx), + file_name.as_ptr().cast(), + file_name.len(), + directory.as_ptr().cast(), + directory.len(), + hash_kind, + hash_value.as_ptr().cast(), + hash_value.len(), + ) + }; + + v.insert(file_metadata); + file_metadata + } + } +} + +trait MsvcBasicName { + fn msvc_basic_name(self) -> &'static str; +} + +impl MsvcBasicName for ast::IntTy { + fn msvc_basic_name(self) -> &'static str { + match self { + ast::IntTy::Isize => "ptrdiff_t", + ast::IntTy::I8 => "__int8", + ast::IntTy::I16 => "__int16", + ast::IntTy::I32 => "__int32", + ast::IntTy::I64 => "__int64", + ast::IntTy::I128 => "__int128", + } + } +} + +impl MsvcBasicName for ast::UintTy { + fn msvc_basic_name(self) -> &'static str { + match self { + ast::UintTy::Usize => "size_t", + ast::UintTy::U8 => "unsigned __int8", + ast::UintTy::U16 => "unsigned __int16", + ast::UintTy::U32 => "unsigned __int32", + ast::UintTy::U64 => "unsigned __int64", + ast::UintTy::U128 => "unsigned __int128", + } + } +} + +impl MsvcBasicName for ast::FloatTy { + fn msvc_basic_name(self) -> &'static str { + match self { + ast::FloatTy::F32 => "float", + ast::FloatTy::F64 => "double", + } + } +} + +fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { + debug!("basic_type_metadata: {:?}", t); + + // When targeting MSVC, emit MSVC style type names for compatibility with + // .natvis visualizers (and perhaps other existing native debuggers?) + let msvc_like_names = cx.tcx.sess.target.target.options.is_like_msvc; + + let (name, encoding) = match t.kind { + ty::Never => ("!", DW_ATE_unsigned), + ty::Tuple(ref elements) if elements.is_empty() => ("()", DW_ATE_unsigned), + ty::Bool => ("bool", DW_ATE_boolean), + ty::Char => ("char", DW_ATE_unsigned_char), + ty::Int(int_ty) if msvc_like_names => (int_ty.msvc_basic_name(), DW_ATE_signed), + ty::Uint(uint_ty) if msvc_like_names => (uint_ty.msvc_basic_name(), DW_ATE_unsigned), + ty::Float(float_ty) if msvc_like_names => (float_ty.msvc_basic_name(), DW_ATE_float), + ty::Int(int_ty) => (int_ty.name_str(), DW_ATE_signed), + ty::Uint(uint_ty) => (uint_ty.name_str(), DW_ATE_unsigned), + ty::Float(float_ty) => (float_ty.name_str(), DW_ATE_float), + _ => bug!("debuginfo::basic_type_metadata - `t` is invalid type"), + }; + + let ty_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateBasicType( + DIB(cx), + name.as_ptr().cast(), + name.len(), + cx.size_of(t).bits(), + encoding, + ) + }; + + if !msvc_like_names { + return ty_metadata; + } + + let typedef_name = match t.kind { + ty::Int(int_ty) => int_ty.name_str(), + ty::Uint(uint_ty) => uint_ty.name_str(), + ty::Float(float_ty) => float_ty.name_str(), + _ => return ty_metadata, + }; + + let typedef_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateTypedef( + DIB(cx), + ty_metadata, + typedef_name.as_ptr().cast(), + typedef_name.len(), + unknown_file_metadata(cx), + 0, + None, + ) + }; + + typedef_metadata +} + +fn foreign_type_metadata( + cx: &CodegenCx<'ll, 'tcx>, + t: Ty<'tcx>, + unique_type_id: UniqueTypeId, +) -> &'ll DIType { + debug!("foreign_type_metadata: {:?}", t); + + let name = compute_debuginfo_type_name(cx.tcx, t, false); + create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA, DIFlags::FlagZero) +} + +fn pointer_type_metadata( + cx: &CodegenCx<'ll, 'tcx>, + pointer_type: Ty<'tcx>, + pointee_type_metadata: &'ll DIType, +) -> &'ll DIType { + let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type); + let name = compute_debuginfo_type_name(cx.tcx, pointer_type, false); + unsafe { + llvm::LLVMRustDIBuilderCreatePointerType( + DIB(cx), + pointee_type_metadata, + pointer_size.bits(), + pointer_align.bits() as u32, + 0, // Ignore DWARF address space. + name.as_ptr().cast(), + name.len(), + ) + } +} + +fn param_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { + debug!("param_type_metadata: {:?}", t); + let name = format!("{:?}", t); + unsafe { + llvm::LLVMRustDIBuilderCreateBasicType( + DIB(cx), + name.as_ptr().cast(), + name.len(), + Size::ZERO.bits(), + DW_ATE_unsigned, + ) + } +} + +pub fn compile_unit_metadata( + tcx: TyCtxt<'_>, + codegen_unit_name: &str, + debug_context: &CrateDebugContext<'ll, '_>, +) -> &'ll DIDescriptor { + let mut name_in_debuginfo = match tcx.sess.local_crate_source_file { + Some(ref path) => path.clone(), + None => PathBuf::from(&*tcx.crate_name(LOCAL_CRATE).as_str()), + }; + + // The OSX linker has an idiosyncrasy where it will ignore some debuginfo + // if multiple object files with the same `DW_AT_name` are linked together. + // As a workaround we generate unique names for each object file. Those do + // not correspond to an actual source file but that should be harmless. + if tcx.sess.target.target.options.is_like_osx { + name_in_debuginfo.push("@"); + name_in_debuginfo.push(codegen_unit_name); + } + + debug!("compile_unit_metadata: {:?}", name_in_debuginfo); + let rustc_producer = + format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"),); + // FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice. + let producer = format!("clang LLVM ({})", rustc_producer); + + let name_in_debuginfo = name_in_debuginfo.to_string_lossy(); + let work_dir = tcx.sess.working_dir.0.to_string_lossy(); + let flags = "\0"; + let split_name = ""; + + // FIXME(#60020): + // + // This should actually be + // + // let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo); + // + // That is, we should set LLVM's emission kind to `LineTablesOnly` if + // we are compiling with "limited" debuginfo. However, some of the + // existing tools relied on slightly more debuginfo being generated than + // would be the case with `LineTablesOnly`, and we did not want to break + // these tools in a "drive-by fix", without a good idea or plan about + // what limited debuginfo should exactly look like. So for now we keep + // the emission kind as `FullDebug`. + // + // See https://github.com/rust-lang/rust/issues/60020 for details. + let kind = DebugEmissionKind::FullDebug; + assert!(tcx.sess.opts.debuginfo != DebugInfo::None); + + unsafe { + let file_metadata = llvm::LLVMRustDIBuilderCreateFile( + debug_context.builder, + name_in_debuginfo.as_ptr().cast(), + name_in_debuginfo.len(), + work_dir.as_ptr().cast(), + work_dir.len(), + llvm::ChecksumKind::None, + ptr::null(), + 0, + ); + + let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit( + debug_context.builder, + DW_LANG_RUST, + file_metadata, + producer.as_ptr().cast(), + producer.len(), + tcx.sess.opts.optimize != config::OptLevel::No, + flags.as_ptr().cast(), + 0, + split_name.as_ptr().cast(), + split_name.len(), + kind, + ); + + if tcx.sess.opts.debugging_opts.profile { + let cu_desc_metadata = + llvm::LLVMRustMetadataAsValue(debug_context.llcontext, unit_metadata); + let default_gcda_path = &tcx.output_filenames(LOCAL_CRATE).with_extension("gcda"); + let gcda_path = + tcx.sess.opts.debugging_opts.profile_emit.as_ref().unwrap_or(default_gcda_path); + + let gcov_cu_info = [ + path_to_mdstring( + debug_context.llcontext, + &tcx.output_filenames(LOCAL_CRATE).with_extension("gcno"), + ), + path_to_mdstring(debug_context.llcontext, &gcda_path), + cu_desc_metadata, + ]; + let gcov_metadata = llvm::LLVMMDNodeInContext( + debug_context.llcontext, + gcov_cu_info.as_ptr(), + gcov_cu_info.len() as c_uint, + ); + + let llvm_gcov_ident = const_cstr!("llvm.gcov"); + llvm::LLVMAddNamedMetadataOperand( + debug_context.llmod, + llvm_gcov_ident.as_ptr(), + gcov_metadata, + ); + } + + // Insert `llvm.ident` metadata on the wasm32 targets since that will + // get hooked up to the "producer" sections `processed-by` information. + if tcx.sess.opts.target_triple.triple().starts_with("wasm32") { + let name_metadata = llvm::LLVMMDStringInContext( + debug_context.llcontext, + rustc_producer.as_ptr().cast(), + rustc_producer.as_bytes().len() as c_uint, + ); + llvm::LLVMAddNamedMetadataOperand( + debug_context.llmod, + const_cstr!("llvm.ident").as_ptr(), + llvm::LLVMMDNodeInContext(debug_context.llcontext, &name_metadata, 1), + ); + } + + return unit_metadata; + }; + + fn path_to_mdstring(llcx: &'ll llvm::Context, path: &Path) -> &'ll Value { + let path_str = path_to_c_string(path); + unsafe { + llvm::LLVMMDStringInContext( + llcx, + path_str.as_ptr(), + path_str.as_bytes().len() as c_uint, + ) + } + } +} + +struct MetadataCreationResult<'ll> { + metadata: &'ll DIType, + already_stored_in_typemap: bool, +} + +impl MetadataCreationResult<'ll> { + fn new(metadata: &'ll DIType, already_stored_in_typemap: bool) -> Self { + MetadataCreationResult { metadata, already_stored_in_typemap } + } +} + +#[derive(Debug)] +struct SourceInfo<'ll> { + file: &'ll DIFile, + line: u32, +} + +/// Description of a type member, which can either be a regular field (as in +/// structs or tuples) or an enum variant. +#[derive(Debug)] +struct MemberDescription<'ll> { + name: String, + type_metadata: &'ll DIType, + offset: Size, + size: Size, + align: Align, + flags: DIFlags, + discriminant: Option<u64>, + source_info: Option<SourceInfo<'ll>>, +} + +impl<'ll> MemberDescription<'ll> { + fn into_metadata( + self, + cx: &CodegenCx<'ll, '_>, + composite_type_metadata: &'ll DIScope, + ) -> &'ll DIType { + let (file, line) = self + .source_info + .map(|info| (info.file, info.line)) + .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)); + unsafe { + llvm::LLVMRustDIBuilderCreateVariantMemberType( + DIB(cx), + composite_type_metadata, + self.name.as_ptr().cast(), + self.name.len(), + file, + line, + self.size.bits(), + self.align.bits() as u32, + self.offset.bits(), + match self.discriminant { + None => None, + Some(value) => Some(cx.const_u64(value)), + }, + self.flags, + self.type_metadata, + ) + } + } +} + +/// A factory for `MemberDescription`s. It produces a list of member descriptions +/// for some record-like type. `MemberDescriptionFactory`s are used to defer the +/// creation of type member descriptions in order to break cycles arising from +/// recursive type definitions. +enum MemberDescriptionFactory<'ll, 'tcx> { + StructMDF(StructMemberDescriptionFactory<'tcx>), + TupleMDF(TupleMemberDescriptionFactory<'tcx>), + EnumMDF(EnumMemberDescriptionFactory<'ll, 'tcx>), + UnionMDF(UnionMemberDescriptionFactory<'tcx>), + VariantMDF(VariantMemberDescriptionFactory<'ll, 'tcx>), +} + +impl MemberDescriptionFactory<'ll, 'tcx> { + fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> { + match *self { + StructMDF(ref this) => this.create_member_descriptions(cx), + TupleMDF(ref this) => this.create_member_descriptions(cx), + EnumMDF(ref this) => this.create_member_descriptions(cx), + UnionMDF(ref this) => this.create_member_descriptions(cx), + VariantMDF(ref this) => this.create_member_descriptions(cx), + } + } +} + +//=----------------------------------------------------------------------------- +// Structs +//=----------------------------------------------------------------------------- + +/// Creates `MemberDescription`s for the fields of a struct. +struct StructMemberDescriptionFactory<'tcx> { + ty: Ty<'tcx>, + variant: &'tcx ty::VariantDef, + span: Span, +} + +impl<'tcx> StructMemberDescriptionFactory<'tcx> { + fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> { + let layout = cx.layout_of(self.ty); + self.variant + .fields + .iter() + .enumerate() + .map(|(i, f)| { + let name = if self.variant.ctor_kind == CtorKind::Fn { + format!("__{}", i) + } else { + f.ident.to_string() + }; + let field = layout.field(cx, i); + MemberDescription { + name, + type_metadata: type_metadata(cx, field.ty, self.span), + offset: layout.fields.offset(i), + size: field.size, + align: field.align.abi, + flags: DIFlags::FlagZero, + discriminant: None, + source_info: None, + } + }) + .collect() + } +} + +fn prepare_struct_metadata( + cx: &CodegenCx<'ll, 'tcx>, + struct_type: Ty<'tcx>, + unique_type_id: UniqueTypeId, + span: Span, +) -> RecursiveTypeDescription<'ll, 'tcx> { + let struct_name = compute_debuginfo_type_name(cx.tcx, struct_type, false); + + let (struct_def_id, variant) = match struct_type.kind { + ty::Adt(def, _) => (def.did, def.non_enum_variant()), + _ => bug!("prepare_struct_metadata on a non-ADT"), + }; + + let containing_scope = get_namespace_for_item(cx, struct_def_id); + + let struct_metadata_stub = create_struct_stub( + cx, + struct_type, + &struct_name, + unique_type_id, + Some(containing_scope), + DIFlags::FlagZero, + ); + + create_and_register_recursive_type_forward_declaration( + cx, + struct_type, + unique_type_id, + struct_metadata_stub, + struct_metadata_stub, + StructMDF(StructMemberDescriptionFactory { ty: struct_type, variant, span }), + ) +} + +//=----------------------------------------------------------------------------- +// Tuples +//=----------------------------------------------------------------------------- + +/// Creates `MemberDescription`s for the fields of a tuple. +struct TupleMemberDescriptionFactory<'tcx> { + ty: Ty<'tcx>, + component_types: Vec<Ty<'tcx>>, + span: Span, +} + +impl<'tcx> TupleMemberDescriptionFactory<'tcx> { + fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> { + let layout = cx.layout_of(self.ty); + self.component_types + .iter() + .enumerate() + .map(|(i, &component_type)| { + let (size, align) = cx.size_and_align_of(component_type); + MemberDescription { + name: format!("__{}", i), + type_metadata: type_metadata(cx, component_type, self.span), + offset: layout.fields.offset(i), + size, + align, + flags: DIFlags::FlagZero, + discriminant: None, + source_info: None, + } + }) + .collect() + } +} + +fn prepare_tuple_metadata( + cx: &CodegenCx<'ll, 'tcx>, + tuple_type: Ty<'tcx>, + component_types: &[Ty<'tcx>], + unique_type_id: UniqueTypeId, + span: Span, + containing_scope: Option<&'ll DIScope>, +) -> RecursiveTypeDescription<'ll, 'tcx> { + let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false); + + let struct_stub = create_struct_stub( + cx, + tuple_type, + &tuple_name[..], + unique_type_id, + containing_scope, + DIFlags::FlagZero, + ); + + create_and_register_recursive_type_forward_declaration( + cx, + tuple_type, + unique_type_id, + struct_stub, + struct_stub, + TupleMDF(TupleMemberDescriptionFactory { + ty: tuple_type, + component_types: component_types.to_vec(), + span, + }), + ) +} + +//=----------------------------------------------------------------------------- +// Unions +//=----------------------------------------------------------------------------- + +struct UnionMemberDescriptionFactory<'tcx> { + layout: TyAndLayout<'tcx>, + variant: &'tcx ty::VariantDef, + span: Span, +} + +impl<'tcx> UnionMemberDescriptionFactory<'tcx> { + fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> { + self.variant + .fields + .iter() + .enumerate() + .map(|(i, f)| { + let field = self.layout.field(cx, i); + MemberDescription { + name: f.ident.to_string(), + type_metadata: type_metadata(cx, field.ty, self.span), + offset: Size::ZERO, + size: field.size, + align: field.align.abi, + flags: DIFlags::FlagZero, + discriminant: None, + source_info: None, + } + }) + .collect() + } +} + +fn prepare_union_metadata( + cx: &CodegenCx<'ll, 'tcx>, + union_type: Ty<'tcx>, + unique_type_id: UniqueTypeId, + span: Span, +) -> RecursiveTypeDescription<'ll, 'tcx> { + let union_name = compute_debuginfo_type_name(cx.tcx, union_type, false); + + let (union_def_id, variant) = match union_type.kind { + ty::Adt(def, _) => (def.did, def.non_enum_variant()), + _ => bug!("prepare_union_metadata on a non-ADT"), + }; + + let containing_scope = get_namespace_for_item(cx, union_def_id); + + let union_metadata_stub = + create_union_stub(cx, union_type, &union_name, unique_type_id, containing_scope); + + create_and_register_recursive_type_forward_declaration( + cx, + union_type, + unique_type_id, + union_metadata_stub, + union_metadata_stub, + UnionMDF(UnionMemberDescriptionFactory { layout: cx.layout_of(union_type), variant, span }), + ) +} + +//=----------------------------------------------------------------------------- +// Enums +//=----------------------------------------------------------------------------- + +/// DWARF variant support is only available starting in LLVM 8, but +/// on MSVC we have to use the fallback mode, because LLVM doesn't +/// lower variant parts to PDB. +fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool { + cx.sess().target.target.options.is_like_msvc +} + +// FIXME(eddyb) maybe precompute this? Right now it's computed once +// per generator monomorphization, but it doesn't depend on substs. +fn generator_layout_and_saved_local_names( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> (&'tcx GeneratorLayout<'tcx>, IndexVec<mir::GeneratorSavedLocal, Option<Symbol>>) { + let body = tcx.optimized_mir(def_id); + let generator_layout = body.generator_layout.as_ref().unwrap(); + let mut generator_saved_local_names = IndexVec::from_elem(None, &generator_layout.field_tys); + + let state_arg = mir::Local::new(1); + for var in &body.var_debug_info { + if var.place.local != state_arg { + continue; + } + match var.place.projection[..] { + [ + // Deref of the `Pin<&mut Self>` state argument. + mir::ProjectionElem::Field(..), + mir::ProjectionElem::Deref, + + // Field of a variant of the state. + mir::ProjectionElem::Downcast(_, variant), + mir::ProjectionElem::Field(field, _), + ] => { + let name = &mut generator_saved_local_names[ + generator_layout.variant_fields[variant][field] + ]; + if name.is_none() { + name.replace(var.name); + } + } + _ => {} + } + } + (generator_layout, generator_saved_local_names) +} + +/// Describes the members of an enum value; an enum is described as a union of +/// structs in DWARF. This `MemberDescriptionFactory` provides the description for +/// the members of this union; so for every variant of the given enum, this +/// factory will produce one `MemberDescription` (all with no name and a fixed +/// offset of zero bytes). +struct EnumMemberDescriptionFactory<'ll, 'tcx> { + enum_type: Ty<'tcx>, + layout: TyAndLayout<'tcx>, + tag_type_metadata: Option<&'ll DIType>, + containing_scope: &'ll DIScope, + span: Span, +} + +impl EnumMemberDescriptionFactory<'ll, 'tcx> { + fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> { + let generator_variant_info_data = match self.enum_type.kind { + ty::Generator(def_id, ..) => { + Some(generator_layout_and_saved_local_names(cx.tcx, def_id)) + } + _ => None, + }; + + let variant_info_for = |index: VariantIdx| match self.enum_type.kind { + ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]), + ty::Generator(def_id, _, _) => { + let (generator_layout, generator_saved_local_names) = + generator_variant_info_data.as_ref().unwrap(); + VariantInfo::Generator { + def_id, + generator_layout: *generator_layout, + generator_saved_local_names, + variant_index: index, + } + } + _ => bug!(), + }; + + // This will always find the metadata in the type map. + let fallback = use_enum_fallback(cx); + let self_metadata = if fallback { + self.containing_scope + } else { + type_metadata(cx, self.enum_type, self.span) + }; + let flags = match self.enum_type.kind { + ty::Generator(..) => DIFlags::FlagArtificial, + _ => DIFlags::FlagZero, + }; + + match self.layout.variants { + Variants::Single { index } => { + if let ty::Adt(adt, _) = &self.enum_type.kind { + if adt.variants.is_empty() { + return vec![]; + } + } + + let variant_info = variant_info_for(index); + let (variant_type_metadata, member_description_factory) = describe_enum_variant( + cx, + self.layout, + variant_info, + NoTag, + self_metadata, + self.span, + ); + + let member_descriptions = member_description_factory.create_member_descriptions(cx); + + set_members_of_composite_type( + cx, + self.enum_type, + variant_type_metadata, + member_descriptions, + ); + vec![MemberDescription { + name: if fallback { String::new() } else { variant_info.variant_name() }, + type_metadata: variant_type_metadata, + offset: Size::ZERO, + size: self.layout.size, + align: self.layout.align.abi, + flags, + discriminant: None, + source_info: variant_info.source_info(cx), + }] + } + Variants::Multiple { + tag_encoding: TagEncoding::Direct, + tag_field, + ref variants, + .. + } => { + let tag_info = if fallback { + RegularTag { + tag_field: Field::from(tag_field), + tag_type_metadata: self.tag_type_metadata.unwrap(), + } + } else { + // This doesn't matter in this case. + NoTag + }; + variants + .iter_enumerated() + .map(|(i, _)| { + let variant = self.layout.for_variant(cx, i); + let variant_info = variant_info_for(i); + let (variant_type_metadata, member_desc_factory) = describe_enum_variant( + cx, + variant, + variant_info, + tag_info, + self_metadata, + self.span, + ); + + let member_descriptions = + member_desc_factory.create_member_descriptions(cx); + + set_members_of_composite_type( + cx, + self.enum_type, + variant_type_metadata, + member_descriptions, + ); + + MemberDescription { + name: if fallback { + String::new() + } else { + variant_info.variant_name() + }, + type_metadata: variant_type_metadata, + offset: Size::ZERO, + size: self.layout.size, + align: self.layout.align.abi, + flags, + discriminant: Some( + self.layout.ty.discriminant_for_variant(cx.tcx, i).unwrap().val + as u64, + ), + source_info: variant_info.source_info(cx), + } + }) + .collect() + } + Variants::Multiple { + tag_encoding: + TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant }, + ref tag, + ref variants, + tag_field, + } => { + if fallback { + let variant = self.layout.for_variant(cx, dataful_variant); + // Create a description of the non-null variant. + let (variant_type_metadata, member_description_factory) = describe_enum_variant( + cx, + variant, + variant_info_for(dataful_variant), + OptimizedTag, + self.containing_scope, + self.span, + ); + + let variant_member_descriptions = + member_description_factory.create_member_descriptions(cx); + + set_members_of_composite_type( + cx, + self.enum_type, + variant_type_metadata, + variant_member_descriptions, + ); + + // Encode the information about the null variant in the union + // member's name. + let mut name = String::from("RUST$ENCODED$ENUM$"); + // Right now it's not even going to work for `niche_start > 0`, + // and for multiple niche variants it only supports the first. + fn compute_field_path<'a, 'tcx>( + cx: &CodegenCx<'a, 'tcx>, + name: &mut String, + layout: TyAndLayout<'tcx>, + offset: Size, + size: Size, + ) { + for i in 0..layout.fields.count() { + let field_offset = layout.fields.offset(i); + if field_offset > offset { + continue; + } + let inner_offset = offset - field_offset; + let field = layout.field(cx, i); + if inner_offset + size <= field.size { + write!(name, "{}$", i).unwrap(); + compute_field_path(cx, name, field, inner_offset, size); + } + } + } + compute_field_path( + cx, + &mut name, + self.layout, + self.layout.fields.offset(tag_field), + self.layout.field(cx, tag_field).size, + ); + let variant_info = variant_info_for(*niche_variants.start()); + variant_info.map_struct_name(|variant_name| { + name.push_str(variant_name); + }); + + // Create the (singleton) list of descriptions of union members. + vec![MemberDescription { + name, + type_metadata: variant_type_metadata, + offset: Size::ZERO, + size: variant.size, + align: variant.align.abi, + flags, + discriminant: None, + source_info: variant_info.source_info(cx), + }] + } else { + variants + .iter_enumerated() + .map(|(i, _)| { + let variant = self.layout.for_variant(cx, i); + let variant_info = variant_info_for(i); + let (variant_type_metadata, member_desc_factory) = + describe_enum_variant( + cx, + variant, + variant_info, + OptimizedTag, + self_metadata, + self.span, + ); + + let member_descriptions = + member_desc_factory.create_member_descriptions(cx); + + set_members_of_composite_type( + cx, + self.enum_type, + variant_type_metadata, + member_descriptions, + ); + + let niche_value = if i == dataful_variant { + None + } else { + let value = (i.as_u32() as u128) + .wrapping_sub(niche_variants.start().as_u32() as u128) + .wrapping_add(niche_start); + let value = truncate(value, tag.value.size(cx)); + // NOTE(eddyb) do *NOT* remove this assert, until + // we pass the full 128-bit value to LLVM, otherwise + // truncation will be silent and remain undetected. + assert_eq!(value as u64 as u128, value); + Some(value as u64) + }; + + MemberDescription { + name: variant_info.variant_name(), + type_metadata: variant_type_metadata, + offset: Size::ZERO, + size: self.layout.size, + align: self.layout.align.abi, + flags, + discriminant: niche_value, + source_info: variant_info.source_info(cx), + } + }) + .collect() + } + } + } + } +} + +// Creates `MemberDescription`s for the fields of a single enum variant. +struct VariantMemberDescriptionFactory<'ll, 'tcx> { + /// Cloned from the `layout::Struct` describing the variant. + offsets: Vec<Size>, + args: Vec<(String, Ty<'tcx>)>, + tag_type_metadata: Option<&'ll DIType>, + span: Span, +} + +impl VariantMemberDescriptionFactory<'ll, 'tcx> { + fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> { + self.args + .iter() + .enumerate() + .map(|(i, &(ref name, ty))| { + // Discriminant is always the first field of our variant + // when using the enum fallback. + let is_artificial_discr = use_enum_fallback(cx) && i == 0; + let (size, align) = cx.size_and_align_of(ty); + MemberDescription { + name: name.to_string(), + type_metadata: if is_artificial_discr { + self.tag_type_metadata.unwrap_or_else(|| type_metadata(cx, ty, self.span)) + } else { + type_metadata(cx, ty, self.span) + }, + offset: self.offsets[i], + size, + align, + flags: if is_artificial_discr { + DIFlags::FlagArtificial + } else { + DIFlags::FlagZero + }, + discriminant: None, + source_info: None, + } + }) + .collect() + } +} + +// FIXME: terminology here should be aligned with `abi::TagEncoding`. +// `OptimizedTag` is `TagEncoding::Niche`, `RegularTag` is `TagEncoding::Direct`. +// `NoTag` should be removed; users should use `Option<EnumTagInfo>` instead. +#[derive(Copy, Clone)] +enum EnumTagInfo<'ll> { + RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType }, + OptimizedTag, + NoTag, +} + +#[derive(Copy, Clone)] +enum VariantInfo<'a, 'tcx> { + Adt(&'tcx ty::VariantDef), + Generator { + def_id: DefId, + generator_layout: &'tcx GeneratorLayout<'tcx>, + generator_saved_local_names: &'a IndexVec<mir::GeneratorSavedLocal, Option<Symbol>>, + variant_index: VariantIdx, + }, +} + +impl<'tcx> VariantInfo<'_, 'tcx> { + fn map_struct_name<R>(&self, f: impl FnOnce(&str) -> R) -> R { + match self { + VariantInfo::Adt(variant) => f(&variant.ident.as_str()), + VariantInfo::Generator { variant_index, .. } => { + f(&GeneratorSubsts::variant_name(*variant_index)) + } + } + } + + fn variant_name(&self) -> String { + match self { + VariantInfo::Adt(variant) => variant.ident.to_string(), + VariantInfo::Generator { variant_index, .. } => { + // Since GDB currently prints out the raw discriminant along + // with every variant, make each variant name be just the value + // of the discriminant. The struct name for the variant includes + // the actual variant description. + format!("{}", variant_index.as_usize()) + } + } + } + + fn field_name(&self, i: usize) -> String { + let field_name = match *self { + VariantInfo::Adt(variant) if variant.ctor_kind != CtorKind::Fn => { + Some(variant.fields[i].ident.name) + } + VariantInfo::Generator { + generator_layout, + generator_saved_local_names, + variant_index, + .. + } => { + generator_saved_local_names + [generator_layout.variant_fields[variant_index][i.into()]] + } + _ => None, + }; + field_name.map(|name| name.to_string()).unwrap_or_else(|| format!("__{}", i)) + } + + fn source_info(&self, cx: &CodegenCx<'ll, 'tcx>) -> Option<SourceInfo<'ll>> { + match self { + VariantInfo::Generator { def_id, variant_index, .. } => { + let span = + cx.tcx.generator_layout(*def_id).variant_source_info[*variant_index].span; + if !span.is_dummy() { + let loc = cx.lookup_debug_loc(span.lo()); + return Some(SourceInfo { + file: file_metadata(cx, &loc.file, def_id.krate), + line: loc.line.unwrap_or(UNKNOWN_LINE_NUMBER), + }); + } + } + _ => {} + } + None + } + + #[allow(dead_code)] + fn is_artificial(&self) -> bool { + match self { + VariantInfo::Generator { .. } => true, + VariantInfo::Adt(..) => false, + } + } +} + +/// Returns a tuple of (1) `type_metadata_stub` of the variant, (2) a +/// `MemberDescriptionFactory` for producing the descriptions of the +/// fields of the variant. This is a rudimentary version of a full +/// `RecursiveTypeDescription`. +fn describe_enum_variant( + cx: &CodegenCx<'ll, 'tcx>, + layout: layout::TyAndLayout<'tcx>, + variant: VariantInfo<'_, 'tcx>, + discriminant_info: EnumTagInfo<'ll>, + containing_scope: &'ll DIScope, + span: Span, +) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) { + let metadata_stub = variant.map_struct_name(|variant_name| { + let unique_type_id = debug_context(cx) + .type_map + .borrow_mut() + .get_unique_type_id_of_enum_variant(cx, layout.ty, &variant_name); + create_struct_stub( + cx, + layout.ty, + &variant_name, + unique_type_id, + Some(containing_scope), + // FIXME(tmandry): This doesn't seem to have any effect. + if variant.is_artificial() { DIFlags::FlagArtificial } else { DIFlags::FlagZero }, + ) + }); + + // Build an array of (field name, field type) pairs to be captured in the factory closure. + let (offsets, args) = if use_enum_fallback(cx) { + // If this is not a univariant enum, there is also the discriminant field. + let (discr_offset, discr_arg) = match discriminant_info { + RegularTag { tag_field, .. } => { + // We have the layout of an enum variant, we need the layout of the outer enum + let enum_layout = cx.layout_of(layout.ty); + let offset = enum_layout.fields.offset(tag_field.as_usize()); + let args = + ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty); + (Some(offset), Some(args)) + } + _ => (None, None), + }; + ( + discr_offset + .into_iter() + .chain((0..layout.fields.count()).map(|i| layout.fields.offset(i))) + .collect(), + discr_arg + .into_iter() + .chain( + (0..layout.fields.count()) + .map(|i| (variant.field_name(i), layout.field(cx, i).ty)), + ) + .collect(), + ) + } else { + ( + (0..layout.fields.count()).map(|i| layout.fields.offset(i)).collect(), + (0..layout.fields.count()) + .map(|i| (variant.field_name(i), layout.field(cx, i).ty)) + .collect(), + ) + }; + + let member_description_factory = VariantMDF(VariantMemberDescriptionFactory { + offsets, + args, + tag_type_metadata: match discriminant_info { + RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata), + _ => None, + }, + span, + }); + + (metadata_stub, member_description_factory) +} + +fn prepare_enum_metadata( + cx: &CodegenCx<'ll, 'tcx>, + enum_type: Ty<'tcx>, + enum_def_id: DefId, + unique_type_id: UniqueTypeId, + span: Span, + outer_field_tys: Vec<Ty<'tcx>>, +) -> RecursiveTypeDescription<'ll, 'tcx> { + let tcx = cx.tcx; + let enum_name = compute_debuginfo_type_name(tcx, enum_type, false); + // FIXME(tmandry): This doesn't seem to have any effect. + let enum_flags = match enum_type.kind { + ty::Generator(..) => DIFlags::FlagArtificial, + _ => DIFlags::FlagZero, + }; + + let containing_scope = get_namespace_for_item(cx, enum_def_id); + // FIXME: This should emit actual file metadata for the enum, but we + // currently can't get the necessary information when it comes to types + // imported from other crates. Formerly we violated the ODR when performing + // LTO because we emitted debuginfo for the same type with varying file + // metadata, so as a workaround we pretend that the type comes from + // <unknown> + let file_metadata = unknown_file_metadata(cx); + + let discriminant_type_metadata = |discr: Primitive| { + let enumerators_metadata: Vec<_> = match enum_type.kind { + ty::Adt(def, _) => def + .discriminants(tcx) + .zip(&def.variants) + .map(|((_, discr), v)| { + let name = v.ident.as_str(); + let is_unsigned = match discr.ty.kind { + ty::Int(_) => false, + ty::Uint(_) => true, + _ => bug!("non integer discriminant"), + }; + unsafe { + Some(llvm::LLVMRustDIBuilderCreateEnumerator( + DIB(cx), + name.as_ptr().cast(), + name.len(), + // FIXME: what if enumeration has i128 discriminant? + discr.val as i64, + is_unsigned, + )) + } + }) + .collect(), + ty::Generator(_, substs, _) => substs + .as_generator() + .variant_range(enum_def_id, tcx) + .map(|variant_index| { + debug_assert_eq!(tcx.types.u32, substs.as_generator().discr_ty(tcx)); + let name = GeneratorSubsts::variant_name(variant_index); + unsafe { + Some(llvm::LLVMRustDIBuilderCreateEnumerator( + DIB(cx), + name.as_ptr().cast(), + name.len(), + // Generators use u32 as discriminant type, verified above. + variant_index.as_u32().into(), + true, // IsUnsigned + )) + } + }) + .collect(), + _ => bug!(), + }; + + let disr_type_key = (enum_def_id, discr); + let cached_discriminant_type_metadata = + debug_context(cx).created_enum_disr_types.borrow().get(&disr_type_key).cloned(); + match cached_discriminant_type_metadata { + Some(discriminant_type_metadata) => discriminant_type_metadata, + None => { + let (discriminant_size, discriminant_align) = (discr.size(cx), discr.align(cx)); + let discriminant_base_type_metadata = + type_metadata(cx, discr.to_ty(tcx), rustc_span::DUMMY_SP); + + let item_name; + let discriminant_name = match enum_type.kind { + ty::Adt(..) => { + item_name = tcx.item_name(enum_def_id).as_str(); + &*item_name + } + ty::Generator(..) => enum_name.as_str(), + _ => bug!(), + }; + + let discriminant_type_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateEnumerationType( + DIB(cx), + containing_scope, + discriminant_name.as_ptr().cast(), + discriminant_name.len(), + file_metadata, + UNKNOWN_LINE_NUMBER, + discriminant_size.bits(), + discriminant_align.abi.bits() as u32, + create_DIArray(DIB(cx), &enumerators_metadata), + discriminant_base_type_metadata, + true, + ) + }; + + debug_context(cx) + .created_enum_disr_types + .borrow_mut() + .insert(disr_type_key, discriminant_type_metadata); + + discriminant_type_metadata + } + } + }; + + let layout = cx.layout_of(enum_type); + + if let ( + &Abi::Scalar(_), + &Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. }, + ) = (&layout.abi, &layout.variants) + { + return FinalMetadata(discriminant_type_metadata(tag.value)); + } + + if use_enum_fallback(cx) { + let discriminant_type_metadata = match layout.variants { + Variants::Single { .. } + | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None, + Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => { + Some(discriminant_type_metadata(tag.value)) + } + }; + + let enum_metadata = { + let type_map = debug_context(cx).type_map.borrow(); + let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id); + + unsafe { + llvm::LLVMRustDIBuilderCreateUnionType( + DIB(cx), + containing_scope, + enum_name.as_ptr().cast(), + enum_name.len(), + file_metadata, + UNKNOWN_LINE_NUMBER, + layout.size.bits(), + layout.align.abi.bits() as u32, + enum_flags, + None, + 0, // RuntimeLang + unique_type_id_str.as_ptr().cast(), + unique_type_id_str.len(), + ) + } + }; + + return create_and_register_recursive_type_forward_declaration( + cx, + enum_type, + unique_type_id, + enum_metadata, + enum_metadata, + EnumMDF(EnumMemberDescriptionFactory { + enum_type, + layout, + tag_type_metadata: discriminant_type_metadata, + containing_scope, + span, + }), + ); + } + + let discriminator_name = match &enum_type.kind { + ty::Generator(..) => "__state", + _ => "", + }; + let discriminator_metadata = match layout.variants { + // A single-variant enum has no discriminant. + Variants::Single { .. } => None, + + Variants::Multiple { + tag_encoding: TagEncoding::Niche { .. }, ref tag, tag_field, .. + } => { + // Find the integer type of the correct size. + let size = tag.value.size(cx); + let align = tag.value.align(cx); + + let tag_type = match tag.value { + Int(t, _) => t, + F32 => Integer::I32, + F64 => Integer::I64, + Pointer => cx.data_layout().ptr_sized_integer(), + } + .to_ty(cx.tcx, false); + + let tag_metadata = basic_type_metadata(cx, tag_type); + unsafe { + Some(llvm::LLVMRustDIBuilderCreateMemberType( + DIB(cx), + containing_scope, + discriminator_name.as_ptr().cast(), + discriminator_name.len(), + file_metadata, + UNKNOWN_LINE_NUMBER, + size.bits(), + align.abi.bits() as u32, + layout.fields.offset(tag_field).bits(), + DIFlags::FlagArtificial, + tag_metadata, + )) + } + } + + Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, tag_field, .. } => { + let discr_type = tag.value.to_ty(cx.tcx); + let (size, align) = cx.size_and_align_of(discr_type); + + let discr_metadata = basic_type_metadata(cx, discr_type); + unsafe { + Some(llvm::LLVMRustDIBuilderCreateMemberType( + DIB(cx), + containing_scope, + discriminator_name.as_ptr().cast(), + discriminator_name.len(), + file_metadata, + UNKNOWN_LINE_NUMBER, + size.bits(), + align.bits() as u32, + layout.fields.offset(tag_field).bits(), + DIFlags::FlagArtificial, + discr_metadata, + )) + } + } + }; + + let mut outer_fields = match layout.variants { + Variants::Single { .. } => vec![], + Variants::Multiple { .. } => { + let tuple_mdf = TupleMemberDescriptionFactory { + ty: enum_type, + component_types: outer_field_tys, + span, + }; + tuple_mdf + .create_member_descriptions(cx) + .into_iter() + .map(|desc| Some(desc.into_metadata(cx, containing_scope))) + .collect() + } + }; + + let variant_part_unique_type_id_str = debug_context(cx) + .type_map + .borrow_mut() + .get_unique_type_id_str_of_enum_variant_part(unique_type_id); + let empty_array = create_DIArray(DIB(cx), &[]); + let name = ""; + let variant_part = unsafe { + llvm::LLVMRustDIBuilderCreateVariantPart( + DIB(cx), + containing_scope, + name.as_ptr().cast(), + name.len(), + file_metadata, + UNKNOWN_LINE_NUMBER, + layout.size.bits(), + layout.align.abi.bits() as u32, + enum_flags, + discriminator_metadata, + empty_array, + variant_part_unique_type_id_str.as_ptr().cast(), + variant_part_unique_type_id_str.len(), + ) + }; + outer_fields.push(Some(variant_part)); + + let struct_wrapper = { + // The variant part must be wrapped in a struct according to DWARF. + let type_array = create_DIArray(DIB(cx), &outer_fields); + + let type_map = debug_context(cx).type_map.borrow(); + let unique_type_id_str = type_map.get_unique_type_id_as_string(unique_type_id); + + unsafe { + llvm::LLVMRustDIBuilderCreateStructType( + DIB(cx), + Some(containing_scope), + enum_name.as_ptr().cast(), + enum_name.len(), + file_metadata, + UNKNOWN_LINE_NUMBER, + layout.size.bits(), + layout.align.abi.bits() as u32, + enum_flags, + None, + type_array, + 0, + None, + unique_type_id_str.as_ptr().cast(), + unique_type_id_str.len(), + ) + } + }; + + create_and_register_recursive_type_forward_declaration( + cx, + enum_type, + unique_type_id, + struct_wrapper, + variant_part, + EnumMDF(EnumMemberDescriptionFactory { + enum_type, + layout, + tag_type_metadata: None, + containing_scope, + span, + }), + ) +} + +/// Creates debug information for a composite type, that is, anything that +/// results in a LLVM struct. +/// +/// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums. +fn composite_type_metadata( + cx: &CodegenCx<'ll, 'tcx>, + composite_type: Ty<'tcx>, + composite_type_name: &str, + composite_type_unique_id: UniqueTypeId, + member_descriptions: Vec<MemberDescription<'ll>>, + containing_scope: Option<&'ll DIScope>, + + // Ignore source location information as long as it + // can't be reconstructed for non-local crates. + _file_metadata: &'ll DIFile, + _definition_span: Span, +) -> &'ll DICompositeType { + // Create the (empty) struct metadata node ... + let composite_type_metadata = create_struct_stub( + cx, + composite_type, + composite_type_name, + composite_type_unique_id, + containing_scope, + DIFlags::FlagZero, + ); + // ... and immediately create and add the member descriptions. + set_members_of_composite_type(cx, composite_type, composite_type_metadata, member_descriptions); + + composite_type_metadata +} + +fn set_members_of_composite_type( + cx: &CodegenCx<'ll, 'tcx>, + composite_type: Ty<'tcx>, + composite_type_metadata: &'ll DICompositeType, + member_descriptions: Vec<MemberDescription<'ll>>, +) { + // In some rare cases LLVM metadata uniquing would lead to an existing type + // description being used instead of a new one created in + // create_struct_stub. This would cause a hard to trace assertion in + // DICompositeType::SetTypeArray(). The following check makes sure that we + // get a better error message if this should happen again due to some + // regression. + { + let mut composite_types_completed = + debug_context(cx).composite_types_completed.borrow_mut(); + if !composite_types_completed.insert(&composite_type_metadata) { + bug!( + "debuginfo::set_members_of_composite_type() - \ + Already completed forward declaration re-encountered." + ); + } + } + + let member_metadata: Vec<_> = member_descriptions + .into_iter() + .map(|desc| Some(desc.into_metadata(cx, composite_type_metadata))) + .collect(); + + let type_params = compute_type_parameters(cx, composite_type); + unsafe { + let type_array = create_DIArray(DIB(cx), &member_metadata[..]); + llvm::LLVMRustDICompositeTypeReplaceArrays( + DIB(cx), + composite_type_metadata, + Some(type_array), + type_params, + ); + } +} + +/// Computes the type parameters for a type, if any, for the given metadata. +fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> Option<&'ll DIArray> { + if let ty::Adt(def, substs) = ty.kind { + if substs.types().next().is_some() { + let generics = cx.tcx.generics_of(def.did); + let names = get_parameter_names(cx, generics); + let template_params: Vec<_> = 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(); + + return Some(create_DIArray(DIB(cx), &template_params[..])); + } + } + return Some(create_DIArray(DIB(cx), &[])); + + 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 + } +} + +/// A convenience wrapper around `LLVMRustDIBuilderCreateStructType()`. Does not do +/// any caching, does not add any fields to the struct. This can be done later +/// with `set_members_of_composite_type()`. +fn create_struct_stub( + cx: &CodegenCx<'ll, 'tcx>, + struct_type: Ty<'tcx>, + struct_type_name: &str, + unique_type_id: UniqueTypeId, + containing_scope: Option<&'ll DIScope>, + flags: DIFlags, +) -> &'ll DICompositeType { + let (struct_size, struct_align) = cx.size_and_align_of(struct_type); + + let type_map = debug_context(cx).type_map.borrow(); + let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id); + + let metadata_stub = unsafe { + // `LLVMRustDIBuilderCreateStructType()` wants an empty array. A null + // pointer will lead to hard to trace and debug LLVM assertions + // later on in `llvm/lib/IR/Value.cpp`. + let empty_array = create_DIArray(DIB(cx), &[]); + + llvm::LLVMRustDIBuilderCreateStructType( + DIB(cx), + containing_scope, + struct_type_name.as_ptr().cast(), + struct_type_name.len(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + struct_size.bits(), + struct_align.bits() as u32, + flags, + None, + empty_array, + 0, + None, + unique_type_id.as_ptr().cast(), + unique_type_id.len(), + ) + }; + + metadata_stub +} + +fn create_union_stub( + cx: &CodegenCx<'ll, 'tcx>, + union_type: Ty<'tcx>, + union_type_name: &str, + unique_type_id: UniqueTypeId, + containing_scope: &'ll DIScope, +) -> &'ll DICompositeType { + let (union_size, union_align) = cx.size_and_align_of(union_type); + + let type_map = debug_context(cx).type_map.borrow(); + let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id); + + let metadata_stub = unsafe { + // `LLVMRustDIBuilderCreateUnionType()` wants an empty array. A null + // pointer will lead to hard to trace and debug LLVM assertions + // later on in `llvm/lib/IR/Value.cpp`. + let empty_array = create_DIArray(DIB(cx), &[]); + + llvm::LLVMRustDIBuilderCreateUnionType( + DIB(cx), + containing_scope, + union_type_name.as_ptr().cast(), + union_type_name.len(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + union_size.bits(), + union_align.bits() as u32, + DIFlags::FlagZero, + Some(empty_array), + 0, // RuntimeLang + unique_type_id.as_ptr().cast(), + unique_type_id.len(), + ) + }; + + metadata_stub +} + +/// Creates debug information for the given global variable. +/// +/// Adds the created metadata nodes directly to the crate's IR. +pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global: &'ll Value) { + if cx.dbg_cx.is_none() { + return; + } + + // Only create type information if full debuginfo is enabled + if cx.sess().opts.debuginfo != DebugInfo::Full { + return; + } + + let tcx = cx.tcx; + + // We may want to remove the namespace scope if we're in an extern block (see + // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952). + let var_scope = get_namespace_for_item(cx, def_id); + let span = tcx.def_span(def_id); + + let (file_metadata, line_number) = if !span.is_dummy() { + let loc = cx.lookup_debug_loc(span.lo()); + (file_metadata(cx, &loc.file, LOCAL_CRATE), loc.line) + } else { + (unknown_file_metadata(cx), None) + }; + + let is_local_to_unit = is_node_local_to_unit(cx, def_id); + let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, ty::ParamEnv::reveal_all()); + let type_metadata = type_metadata(cx, variable_type, span); + let var_name = tcx.item_name(def_id).as_str(); + let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name; + // When empty, linkage_name field is omitted, + // which is what we want for no_mangle statics + let linkage_name = if var_name == linkage_name { "" } else { linkage_name }; + + let global_align = cx.align_of(variable_type); + + unsafe { + llvm::LLVMRustDIBuilderCreateStaticVariable( + DIB(cx), + Some(var_scope), + var_name.as_ptr().cast(), + var_name.len(), + linkage_name.as_ptr().cast(), + linkage_name.len(), + file_metadata, + line_number.unwrap_or(UNKNOWN_LINE_NUMBER), + type_metadata, + is_local_to_unit, + global, + None, + global_align.bytes() as u32, + ); + } +} + +/// Creates debug information for the given vtable, which is for the +/// given type. +/// +/// Adds the created metadata nodes directly to the crate's IR. +pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: &'ll Value) { + if cx.dbg_cx.is_none() { + return; + } + + // Only create type information if full debuginfo is enabled + if cx.sess().opts.debuginfo != DebugInfo::Full { + return; + } + + let type_metadata = type_metadata(cx, ty, rustc_span::DUMMY_SP); + + unsafe { + // `LLVMRustDIBuilderCreateStructType()` wants an empty array. A null + // pointer will lead to hard to trace and debug LLVM assertions + // later on in `llvm/lib/IR/Value.cpp`. + let empty_array = create_DIArray(DIB(cx), &[]); + let name = "vtable"; + + // Create a new one each time. We don't want metadata caching + // here, because each vtable will refer to a unique containing + // type. + let vtable_type = llvm::LLVMRustDIBuilderCreateStructType( + DIB(cx), + NO_SCOPE_METADATA, + name.as_ptr().cast(), + name.len(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + Size::ZERO.bits(), + cx.tcx.data_layout.pointer_align.abi.bits() as u32, + DIFlags::FlagArtificial, + None, + empty_array, + 0, + Some(type_metadata), + name.as_ptr().cast(), + name.len(), + ); + + let linkage_name = ""; + llvm::LLVMRustDIBuilderCreateStaticVariable( + DIB(cx), + NO_SCOPE_METADATA, + name.as_ptr().cast(), + name.len(), + linkage_name.as_ptr().cast(), + linkage_name.len(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + vtable_type, + true, + vtable, + None, + 0, + ); + } +} + +/// Creates an "extension" of an existing `DIScope` into another file. +pub fn extend_scope_to_file( + cx: &CodegenCx<'ll, '_>, + scope_metadata: &'ll DIScope, + file: &rustc_span::SourceFile, + defining_crate: CrateNum, +) -> &'ll DILexicalBlock { + let file_metadata = file_metadata(cx, &file, defining_crate); + unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlockFile(DIB(cx), scope_metadata, file_metadata) } +} diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs new file mode 100644 index 00000000000..b414426af8c --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -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, + ) + } + } +} diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs new file mode 100644 index 00000000000..d1a55335c44 --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs @@ -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 +} diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs b/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs new file mode 100644 index 00000000000..66ae9d72c3e --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs @@ -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, + ) + } + } +} diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs new file mode 100644 index 00000000000..ee188e69be1 --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -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?")) +} |
