Skip to main content

rustc_codegen_llvm/debuginfo/
mod.rs

1#![doc = "# Debug Info Module\n\nThis module serves the purpose of generating debug symbols. We use LLVM\'s\n[source level debugging](https://llvm.org/docs/SourceLevelDebugging.html)\nfeatures for generating the debug information. The general principle is\nthis:\n\nGiven the right metadata in the LLVM IR, the LLVM code generator is able to\ncreate DWARF debug symbols for the given code. The\n[metadata](https://llvm.org/docs/LangRef.html#metadata-type) is structured\nmuch like DWARF *debugging information entries* (DIE), representing type\ninformation such as datatype layout, function signatures, block layout,\nvariable location and scope information, etc. It is the purpose of this\nmodule to generate correct metadata and insert it into the LLVM IR.\n\nAs the exact format of metadata trees may change between different LLVM\nversions, we now use LLVM\n[DIBuilder](https://llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html)\nto create metadata where possible. This will hopefully ease the adaptation of\nthis module to future LLVM versions.\n\nThe public API of the module is a set of functions that will insert the\ncorrect metadata into the LLVM IR when called with the right parameters.\nThe module is thus driven from an outside client with functions like\n`debuginfo::create_local_var_metadata(bx: block, local: &ast::local)`.\n\nInternally the module will try to reuse already created metadata by\nutilizing a cache. The way to get a shared metadata node when needed is\nthus to just call the corresponding function in this module:\n```ignore (illustrative)\nlet file_metadata = file_metadata(cx, file);\n```\nThe function will take care of probing the cache for an existing node for\nthat exact file path.\n\nAll private state used by the module is stored within either the\nCodegenUnitDebugContext struct (owned by the CodegenCx) or the\nFunctionDebugContext (owned by the FunctionCx).\n\nThis file consists of three conceptual sections:\n1. The public interface of the module\n2. Module-internal metadata creation functions\n3. Minor utility functions\n\n\n## Recursive Types\n\nSome kinds of types, such as structs and enums can be recursive. That means\nthat the type definition of some type X refers to some other type which in\nturn (transitively) refers to X. This introduces cycles into the type\nreferral graph. A naive algorithm doing an on-demand, depth-first traversal\nof this graph when describing types, can get trapped in an endless loop\nwhen it reaches such a cycle.\n\nFor example, the following simple type for a singly-linked list...\n\n```\nstruct List {\n    value: i32,\n    tail: Option<Box<List>>,\n}\n```\n\nwill generate the following callstack with a naive DFS algorithm:\n\n```ignore (illustrative)\ndescribe(t = List)\n  describe(t = i32)\n  describe(t = Option<Box<List>>)\n    describe(t = Box<List>)\n      describe(t = List) // at the beginning again...\n      ...\n```\n\nTo break cycles like these, we use \"stubs\". That is, when\nthe algorithm encounters a possibly recursive type (any struct or enum), it\nimmediately creates a type description node and inserts it into the cache\n*before* describing the members of the type. This type description is just\na stub (as type members are not described and added to it yet) but it\nallows the algorithm to already refer to the type. After the stub is\ninserted into the cache, the algorithm continues as before. If it now\nencounters a recursive reference, it will hit the cache and does not try to\ndescribe the type anew. This behavior is encapsulated in the\n`type_map::build_type_with_children()` function.\n\n\n## Source Locations and Line Information\n\nIn addition to data type descriptions the debugging information must also\nallow mapping machine code locations back to source code locations in order\nto be useful. This functionality is also handled in this module. The\nfollowing functions allow controlling source mappings:\n\n+ `set_source_location()`\n+ `clear_source_location()`\n+ `start_emitting_source_locations()`\n\n`set_source_location()` allows setting the current source location. All IR\ninstructions created after a call to this function will be linked to the\ngiven source location, until another location is specified with\n`set_source_location()` or the source location is cleared with\n`clear_source_location()`. In the latter case, subsequent IR instructions\nwill not be linked to any source location. As you can see, this is a\nstateful API (mimicking the one in LLVM), so be careful with source\nlocations set by previous calls. It\'s probably best to not rely on any\nspecific state being present at a given point in code.\n\nOne topic that deserves some extra attention is *function prologues*. At\nthe beginning of a function\'s machine code there are typically a few\ninstructions for loading argument values into allocas and checking if\nthere\'s enough stack space for the function to execute. This *prologue* is\nnot visible in the source code and LLVM puts a special PROLOGUE END marker\ninto the line table at the first non-prologue instruction of the function.\nIn order to find out where the prologue ends, LLVM looks for the first\ninstruction in the function body that is linked to a source location. So,\nwhen generating prologue instructions we have to make sure that we don\'t\nemit source location information until the \'real\' function body begins. For\nthis reason, source location emission is disabled by default for any new\nfunction being codegened and is only activated after a call to the third\nfunction from the list above, `start_emitting_source_locations()`. This\nfunction should be called right before regularly starting to codegen the\ntop-level block of the given function.\n\nThere is one exception to the above rule: `llvm.dbg.declare` instruction\nmust be linked to the source location of the variable being declared. For\nfunction parameters these `llvm.dbg.declare` instructions typically occur\nin the middle of the prologue, however, they are ignored by LLVM\'s prologue\ndetection. The `create_argument_metadata()` and related functions take care\nof linking the `llvm.dbg.declare` instructions to the correct source\nlocations even while source location emission is still disabled, so there\nis no need to do anything special with source location handling here.\n"include_str!("doc.md")]
2
3use std::cell::{OnceCell, RefCell};
4use std::ops::Range;
5use std::sync::Arc;
6use std::{iter, ptr};
7
8use libc::c_uint;
9use metadata::create_subroutine_type;
10use rustc_abi::Size;
11use rustc_codegen_ssa::debuginfo::type_names;
12use rustc_codegen_ssa::mir::debuginfo::VariableKind;
13use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
14use rustc_codegen_ssa::traits::*;
15use rustc_data_structures::unord::UnordMap;
16use rustc_hir::def_id::{DefId, DefIdMap};
17use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
18use rustc_middle::ty::{self, GenericArgsRef, Instance, Ty, TypeVisitableExt, Unnormalized};
19use rustc_session::Session;
20use rustc_session::config::{self, DebugInfo};
21use rustc_span::{
22    BytePos, Pos, SourceFile, SourceFileAndLine, SourceFileHash, Span, StableSourceFileId, Symbol,
23};
24use rustc_target::callconv::FnAbi;
25use rustc_target::spec::DebuginfoKind;
26use smallvec::SmallVec;
27use tracing::debug;
28
29pub(crate) use self::di_builder::DIBuilderExt;
30pub(crate) use self::metadata::build_global_var_di_node;
31use self::metadata::{
32    UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER, file_metadata, spanned_type_di_node, type_di_node,
33};
34use self::namespace::mangled_name_of_instance;
35use self::utils::{DIB, create_DIArray, is_node_local_to_unit};
36use crate::builder::Builder;
37use crate::common::{AsCCharPtr, CodegenCx};
38use crate::debuginfo::di_builder::DIBuilderBox;
39use crate::llvm::debuginfo::{
40    DIArray, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope,
41    DITemplateTypeParameter, DIType, DIVariable,
42};
43use crate::llvm::{self, Value};
44
45mod di_builder;
46mod dwarf_const;
47mod gdb;
48pub(crate) mod metadata;
49mod namespace;
50mod utils;
51
52/// A context object for maintaining all state needed by the debuginfo module.
53pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> {
54    llmod: &'ll llvm::Module,
55    builder: DIBuilderBox<'ll>,
56    created_files: RefCell<UnordMap<Option<(StableSourceFileId, SourceFileHash)>, &'ll DIFile>>,
57
58    type_map: metadata::TypeMap<'ll, 'tcx>,
59    adt_stack: RefCell<Vec<(DefId, GenericArgsRef<'tcx>)>>,
60    namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
61    recursion_marker_type: OnceCell<&'ll DIType>,
62}
63
64impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
65    pub(crate) fn new(llmod: &'ll llvm::Module) -> Self {
66        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_llvm/src/debuginfo/mod.rs:66",
                        "rustc_codegen_llvm::debuginfo", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_llvm/src/debuginfo/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(66u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_llvm::debuginfo"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("CodegenUnitDebugContext::new")
                                            as &dyn Value))])
            });
    } else { ; }
};debug!("CodegenUnitDebugContext::new");
67        let builder = DIBuilderBox::new(llmod);
68        // DIBuilder inherits context from the module, so we'd better use the same one
69        CodegenUnitDebugContext {
70            llmod,
71            builder,
72            created_files: Default::default(),
73            type_map: Default::default(),
74            adt_stack: Default::default(),
75            namespace_map: RefCell::new(Default::default()),
76            recursion_marker_type: OnceCell::new(),
77        }
78    }
79
80    pub(crate) fn finalize(&self, sess: &Session) {
81        unsafe { llvm::LLVMDIBuilderFinalize(self.builder.as_ref()) };
82
83        match sess.target.debuginfo_kind {
84            DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym => {
85                // Debuginfo generation in LLVM by default uses a higher
86                // version of dwarf than macOS currently understands. We can
87                // instruct LLVM to emit an older version of dwarf, however,
88                // for macOS to understand. For more info see #11352
89                // This can be overridden using --llvm-opts -dwarf-version,N.
90                // Android has the same issue (#22398)
91                llvm::add_module_flag_u32(
92                    self.llmod,
93                    // In the case where multiple CGUs with different dwarf version
94                    // values are being merged together, such as with cross-crate
95                    // LTO, then we want to use the highest version of dwarf
96                    // we can. This matches Clang's behavior as well.
97                    llvm::ModuleFlagMergeBehavior::Max,
98                    "Dwarf Version",
99                    sess.dwarf_version(),
100                );
101            }
102            DebuginfoKind::Pdb => {
103                // Indicate that we want CodeView debug information
104                llvm::add_module_flag_u32(
105                    self.llmod,
106                    llvm::ModuleFlagMergeBehavior::Warning,
107                    "CodeView",
108                    1,
109                );
110            }
111        }
112
113        // Prevent bitcode readers from deleting the debug info.
114        llvm::add_module_flag_u32(
115            self.llmod,
116            llvm::ModuleFlagMergeBehavior::Warning,
117            "Debug Info Version",
118            unsafe { llvm::LLVMRustDebugMetadataVersion() },
119        );
120    }
121}
122
123/// Creates any deferred debug metadata nodes
124pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
125    if let Some(dbg_cx) = &cx.dbg_cx {
126        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_llvm/src/debuginfo/mod.rs:126",
                        "rustc_codegen_llvm::debuginfo", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_llvm/src/debuginfo/mod.rs"),
                        ::tracing_core::__macro_support::Option::Some(126u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_llvm::debuginfo"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("finalize")
                                            as &dyn Value))])
            });
    } else { ; }
};debug!("finalize");
127
128        if gdb::needs_gdb_debug_scripts_section(cx) {
129            // Add a .debug_gdb_scripts section to this compile-unit. This will
130            // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
131            // which activates the Rust pretty printers for binary this section is
132            // contained in.
133            gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
134        }
135
136        dbg_cx.finalize(cx.sess());
137    }
138}
139
140impl<'ll> Builder<'_, 'll, '_> {
141    pub(crate) fn get_dbg_loc(&self) -> Option<&'ll DILocation> {
142        unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) }
143    }
144}
145
146impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
147    // FIXME(eddyb) find a common convention for all of the debuginfo-related
148    // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
149    fn dbg_var_addr(
150        &mut self,
151        dbg_var: &'ll DIVariable,
152        dbg_loc: &'ll DILocation,
153        variable_alloca: Self::Value,
154        direct_offset: Size,
155        indirect_offsets: &[Size],
156        fragment: &Option<Range<Size>>,
157    ) {
158        use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst};
159
160        // Convert the direct and indirect offsets and fragment byte range to address ops.
161        let mut addr_ops = SmallVec::<[u64; 8]>::new();
162
163        if direct_offset.bytes() > 0 {
164            addr_ops.push(DW_OP_plus_uconst);
165            addr_ops.push(direct_offset.bytes());
166        }
167        for &offset in indirect_offsets {
168            addr_ops.push(DW_OP_deref);
169            if offset.bytes() > 0 {
170                addr_ops.push(DW_OP_plus_uconst);
171                addr_ops.push(offset.bytes());
172            }
173        }
174        if let Some(fragment) = fragment {
175            // `DW_OP_LLVM_fragment` takes as arguments the fragment's
176            // offset and size, both of them in bits.
177            addr_ops.push(DW_OP_LLVM_fragment);
178            addr_ops.push(fragment.start.bits());
179            addr_ops.push((fragment.end - fragment.start).bits());
180        }
181
182        let di_builder = DIB(self.cx());
183        let addr_expr = di_builder.create_expression(&addr_ops);
184        unsafe {
185            llvm::LLVMDIBuilderInsertDeclareRecordAtEnd(
186                di_builder,
187                variable_alloca,
188                dbg_var,
189                addr_expr,
190                dbg_loc,
191                self.llbb(),
192            )
193        };
194    }
195
196    fn dbg_var_value(
197        &mut self,
198        dbg_var: &'ll DIVariable,
199        dbg_loc: &'ll DILocation,
200        value: Self::Value,
201        direct_offset: Size,
202        indirect_offsets: &[Size],
203        fragment: &Option<Range<Size>>,
204    ) {
205        use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst, DW_OP_stack_value};
206
207        // Convert the direct and indirect offsets and fragment byte range to address ops.
208        let mut addr_ops = SmallVec::<[u64; 8]>::new();
209
210        if direct_offset.bytes() > 0 {
211            addr_ops.push(DW_OP_plus_uconst);
212            addr_ops.push(direct_offset.bytes() as u64);
213            addr_ops.push(DW_OP_stack_value);
214        }
215        for &offset in indirect_offsets {
216            addr_ops.push(DW_OP_deref);
217            if offset.bytes() > 0 {
218                addr_ops.push(DW_OP_plus_uconst);
219                addr_ops.push(offset.bytes() as u64);
220            }
221        }
222        if let Some(fragment) = fragment {
223            // `DW_OP_LLVM_fragment` takes as arguments the fragment's
224            // offset and size, both of them in bits.
225            addr_ops.push(DW_OP_LLVM_fragment);
226            addr_ops.push(fragment.start.bits() as u64);
227            addr_ops.push((fragment.end - fragment.start).bits() as u64);
228        }
229
230        let di_builder = DIB(self.cx());
231        let addr_expr = unsafe {
232            llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len())
233        };
234        unsafe {
235            llvm::LLVMDIBuilderInsertDbgValueRecordAtEnd(
236                di_builder,
237                value,
238                dbg_var,
239                addr_expr,
240                dbg_loc,
241                self.llbb(),
242            );
243        }
244    }
245
246    fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) {
247        unsafe {
248            llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc);
249        }
250    }
251
252    fn clear_dbg_loc(&mut self) {
253        unsafe {
254            llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, ptr::null());
255        }
256    }
257
258    fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
259        gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
260    }
261
262    fn set_var_name(&mut self, value: &'ll Value, name: &str) {
263        // Avoid wasting time if LLVM value names aren't even enabled.
264        if self.sess().fewer_names() {
265            return;
266        }
267
268        // Only function parameters and instructions are local to a function,
269        // don't change the name of anything else (e.g. globals).
270        let param_or_inst = unsafe {
271            llvm::LLVMIsAArgument(value).is_some() || llvm::LLVMIsAInstruction(value).is_some()
272        };
273        if !param_or_inst {
274            return;
275        }
276
277        // Avoid replacing the name if it already exists.
278        // While we could combine the names somehow, it'd
279        // get noisy quick, and the usefulness is dubious.
280        if llvm::get_value_name(value).is_empty() {
281            llvm::set_value_name(value, name.as_bytes());
282        }
283    }
284
285    /// Annotate move/copy operations with debug info for profiling.
286    ///
287    /// This creates a temporary debug scope that makes the move/copy appear as an inlined call to
288    /// `compiler_move<T, SIZE>()` or `compiler_copy<T, SIZE>()`. The provided closure is executed
289    /// with this temporary debug location active.
290    ///
291    /// The `instance` parameter should be the monomorphized instance of the `compiler_move` or
292    /// `compiler_copy` function with the actual type and size.
293    fn with_move_annotation<R>(
294        &mut self,
295        instance: ty::Instance<'tcx>,
296        f: impl FnOnce(&mut Self) -> R,
297    ) -> R {
298        // Save the current debug location
299        let saved_loc = self.get_dbg_loc();
300
301        // Create a DIScope for the compiler_move/compiler_copy function
302        // We use the function's FnAbi for debug info generation
303        let fn_abi = self
304            .cx()
305            .tcx
306            .fn_abi_of_instance(
307                self.cx().typing_env().as_query_input((instance, ty::List::empty())),
308            )
309            .unwrap();
310
311        let di_scope = self.cx().dbg_scope_fn(instance, fn_abi, None);
312
313        // Create an inlined debug location:
314        // - scope: the compiler_move/compiler_copy function
315        // - inlined_at: the current location (where the move/copy actually occurs)
316        // - span: use the function's definition span
317        let fn_span = self.cx().tcx.def_span(instance.def_id());
318        let inlined_loc = self.cx().dbg_loc(di_scope, saved_loc, fn_span);
319
320        // Set the temporary debug location
321        self.set_dbg_loc(inlined_loc);
322
323        // Execute the closure (which will generate the memcpy)
324        let result = f(self);
325
326        // Restore the original debug location
327        if let Some(loc) = saved_loc {
328            self.set_dbg_loc(loc);
329        } else {
330            self.clear_dbg_loc();
331        }
332
333        result
334    }
335}
336
337/// A source code location used to generate debug information.
338// FIXME(eddyb) rename this to better indicate it's a duplicate of
339// `rustc_span::Loc` rather than `DILocation`, perhaps by making
340// `lookup_char_pos` return the right information instead.
341struct DebugLoc {
342    /// Information about the original source file.
343    file: Arc<SourceFile>,
344    /// The (1-based) line number.
345    line: u32,
346    /// The (1-based) column number.
347    col: u32,
348}
349
350impl<'ll> CodegenCx<'ll, '_> {
351    /// Looks up debug source information about a `BytePos`.
352    // FIXME(eddyb) rename this to better indicate it's a duplicate of
353    // `lookup_char_pos` rather than `dbg_loc`, perhaps by making
354    // `lookup_char_pos` return the right information instead.
355    fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
356        let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
357            Ok(SourceFileAndLine { sf: file, line }) => {
358                let line_pos = file.lines()[line];
359
360                // Use 1-based indexing.
361                let line = (line + 1) as u32;
362                let col = (file.relative_position(pos) - line_pos).to_u32() + 1;
363
364                (file, line, col)
365            }
366            Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER),
367        };
368
369        // For MSVC, omit the column number.
370        // Otherwise, emit it. This mimics clang behaviour.
371        // See discussion in https://github.com/rust-lang/rust/issues/42921
372        if self.sess().target.is_like_msvc {
373            DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER }
374        } else {
375            DebugLoc { file, line, col }
376        }
377    }
378
379    fn create_template_type_parameter(
380        &self,
381        name: &str,
382        actual_type_metadata: &'ll DIType,
383    ) -> &'ll DITemplateTypeParameter {
384        unsafe {
385            llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
386                DIB(self),
387                None,
388                name.as_c_char_ptr(),
389                name.len(),
390                actual_type_metadata,
391            )
392        }
393    }
394}
395
396impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
397    fn dbg_create_lexical_block(&self, pos: BytePos, parent_scope: &'ll DIScope) -> &'ll DIScope {
398        let loc = self.lookup_debug_loc(pos);
399        let file_metadata = file_metadata(self, &loc.file);
400        unsafe {
401            llvm::LLVMDIBuilderCreateLexicalBlock(
402                DIB(self),
403                parent_scope,
404                file_metadata,
405                loc.line,
406                loc.col,
407            )
408        }
409    }
410
411    fn dbg_location_clone_with_discriminator(
412        &self,
413        loc: &'ll DILocation,
414        discriminator: u32,
415    ) -> Option<&'ll DILocation> {
416        unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, discriminator) }
417    }
418
419    fn dbg_scope_fn(
420        &self,
421        instance: Instance<'tcx>,
422        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
423        maybe_definition_llfn: Option<&'ll Value>,
424    ) -> &'ll DIScope {
425        let tcx = self.tcx;
426
427        let def_id = instance.def_id();
428        let (containing_scope, is_method) = get_containing_scope(self, instance);
429        let span = tcx.def_span(def_id);
430        let loc = self.lookup_debug_loc(span.lo());
431        let file_metadata = file_metadata(self, &loc.file);
432
433        let function_type_metadata =
434            create_subroutine_type(self, &get_function_signature(self, fn_abi));
435
436        let mut name = String::with_capacity(64);
437        type_names::push_item_name(tcx, def_id, false, &mut name);
438
439        // Find the enclosing function, in case this is a closure.
440        let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
441
442        // We look up the generics of the enclosing function and truncate the args
443        // to their length in order to cut off extra stuff that might be in there for
444        // closures or coroutines.
445        let generics = tcx.generics_of(enclosing_fn_def_id);
446        let args = instance.args.truncate_to(tcx, generics);
447
448        type_names::push_generic_args(
449            tcx,
450            tcx.normalize_erasing_regions(self.typing_env(), Unnormalized::new_wip(args)),
451            &mut name,
452        );
453
454        let template_parameters = get_template_parameters(self, generics, args);
455
456        let linkage_name = &mangled_name_of_instance(self, instance).name;
457        // Omit the linkage_name if it is the same as subprogram name.
458        let linkage_name = if &name == linkage_name { "" } else { linkage_name };
459
460        // FIXME(eddyb) does this need to be separate from `loc.line` for some reason?
461        let scope_line = loc.line;
462
463        let mut flags = DIFlags::FlagPrototyped;
464
465        if fn_abi.ret.layout.is_uninhabited() {
466            flags |= DIFlags::FlagNoReturn;
467        }
468
469        let mut spflags = DISPFlags::SPFlagDefinition;
470        if is_node_local_to_unit(self, def_id) {
471            spflags |= DISPFlags::SPFlagLocalToUnit;
472        }
473        if self.sess().opts.optimize != config::OptLevel::No {
474            spflags |= DISPFlags::SPFlagOptimized;
475        }
476        if let Some((id, _)) = tcx.entry_fn(()) {
477            if id == def_id {
478                spflags |= DISPFlags::SPFlagMainSubprogram;
479            }
480        }
481
482        // When we're adding a method to a type DIE, we only want a DW_AT_declaration there, because
483        // LLVM LTO can't unify type definitions when a child DIE is a full subprogram definition.
484        // When we use this `decl` below, the subprogram definition gets created at the CU level
485        // with a DW_AT_specification pointing back to the type's declaration.
486        let decl = is_method.then(|| unsafe {
487            llvm::LLVMRustDIBuilderCreateMethod(
488                DIB(self),
489                containing_scope,
490                name.as_c_char_ptr(),
491                name.len(),
492                linkage_name.as_c_char_ptr(),
493                linkage_name.len(),
494                file_metadata,
495                loc.line,
496                function_type_metadata,
497                flags,
498                spflags & !DISPFlags::SPFlagDefinition,
499                template_parameters,
500            )
501        });
502
503        return unsafe {
504            llvm::LLVMRustDIBuilderCreateFunction(
505                DIB(self),
506                containing_scope,
507                name.as_c_char_ptr(),
508                name.len(),
509                linkage_name.as_c_char_ptr(),
510                linkage_name.len(),
511                file_metadata,
512                loc.line,
513                function_type_metadata,
514                scope_line,
515                flags,
516                spflags,
517                maybe_definition_llfn,
518                template_parameters,
519                decl,
520            )
521        };
522
523        fn get_function_signature<'ll, 'tcx>(
524            cx: &CodegenCx<'ll, 'tcx>,
525            fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
526        ) -> Vec<Option<&'ll llvm::Metadata>> {
527            if cx.sess().opts.debuginfo != DebugInfo::Full {
528                return ::alloc::vec::Vec::new()vec![];
529            }
530
531            let mut signature = Vec::with_capacity(fn_abi.args.len() + 1);
532
533            // Return type -- llvm::DIBuilder wants this at index 0
534            signature.push(if fn_abi.ret.is_ignore() {
535                None
536            } else {
537                Some(type_di_node(cx, fn_abi.ret.layout.ty))
538            });
539
540            // Arguments types
541            if cx.sess().target.is_like_msvc {
542                // FIXME(#42800):
543                // There is a bug in MSDIA that leads to a crash when it encounters
544                // a fixed-size array of `u8` or something zero-sized in a
545                // function-type (see #40477).
546                // As a workaround, we replace those fixed-size arrays with a
547                // pointer-type. So a function `fn foo(a: u8, b: [u8; 4])` would
548                // appear as `fn foo(a: u8, b: *const u8)` in debuginfo,
549                // and a function `fn bar(x: [(); 7])` as `fn bar(x: *const ())`.
550                // This transformed type is wrong, but these function types are
551                // already inaccurate due to ABI adjustments (see #42800).
552                signature.extend(fn_abi.args.iter().map(|arg| {
553                    let t = arg.layout.ty;
554                    let t = match t.kind() {
555                        ty::Array(ct, _)
556                            if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() =>
557                        {
558                            Ty::new_imm_ptr(cx.tcx, *ct)
559                        }
560                        _ => t,
561                    };
562                    Some(type_di_node(cx, t))
563                }));
564            } else {
565                signature
566                    .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty))));
567            }
568
569            signature
570        }
571
572        fn get_template_parameters<'ll, 'tcx>(
573            cx: &CodegenCx<'ll, 'tcx>,
574            generics: &ty::Generics,
575            args: GenericArgsRef<'tcx>,
576        ) -> &'ll DIArray {
577            if args.types().next().is_none() {
578                return create_DIArray(DIB(cx), &[]);
579            }
580
581            // Again, only create type information if full debuginfo is enabled
582            let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
583                let names = get_parameter_names(cx, generics);
584                iter::zip(args, names)
585                    .filter_map(|(kind, name)| {
586                        kind.as_type().map(|ty| {
587                            let actual_type = cx.tcx.normalize_erasing_regions(
588                                cx.typing_env(),
589                                Unnormalized::new_wip(ty),
590                            );
591                            let actual_type_metadata = type_di_node(cx, actual_type);
592                            Some(cx.create_template_type_parameter(
593                                name.as_str(),
594                                actual_type_metadata,
595                            ))
596                        })
597                    })
598                    .collect()
599            } else {
600                ::alloc::vec::Vec::new()vec![]
601            };
602
603            create_DIArray(DIB(cx), &template_params)
604        }
605
606        fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
607            let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
608                get_parameter_names(cx, cx.tcx.generics_of(def_id))
609            });
610            names.extend(generics.own_params.iter().map(|param| param.name));
611            names
612        }
613
614        /// Returns a scope, plus `true` if that's a type scope for "class" methods,
615        /// otherwise `false` for plain namespace scopes.
616        fn get_containing_scope<'ll, 'tcx>(
617            cx: &CodegenCx<'ll, 'tcx>,
618            instance: Instance<'tcx>,
619        ) -> (&'ll DIScope, bool) {
620            // First, let's see if this is a method within an inherent impl. Because
621            // if yes, we want to make the result subroutine DIE a child of the
622            // subroutine's self-type.
623            // For trait method impls we still use the "parallel namespace"
624            // strategy
625            if let Some(imp_def_id) = cx.tcx.inherent_impl_of_assoc(instance.def_id()) {
626                let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
627                    instance.args,
628                    cx.typing_env(),
629                    cx.tcx.type_of(imp_def_id),
630                );
631
632                // Only "class" methods are generally understood by LLVM,
633                // so avoid methods on other types (e.g., `<*mut T>::null`).
634                if let ty::Adt(def, ..) = impl_self_ty.kind()
635                    && !def.is_box()
636                {
637                    // Again, only create type information if full debuginfo is enabled
638                    if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() {
639                        return (type_di_node(cx, impl_self_ty), true);
640                    } else {
641                        return (namespace::item_namespace(cx, def.did()), false);
642                    }
643                }
644            }
645
646            let scope = namespace::item_namespace(
647                cx,
648                DefId {
649                    krate: instance.def_id().krate,
650                    index: cx
651                        .tcx
652                        .def_key(instance.def_id())
653                        .parent
654                        .expect("get_containing_scope: missing parent?"),
655                },
656            );
657            (scope, false)
658        }
659    }
660
661    fn dbg_loc(
662        &self,
663        scope: &'ll DIScope,
664        inlined_at: Option<&'ll DILocation>,
665        span: Span,
666    ) -> &'ll DILocation {
667        // When emitting debugging information, DWARF (i.e. everything but MSVC)
668        // treats line 0 as a magic value meaning that the code could not be
669        // attributed to any line in the source. That's also exactly what dummy
670        // spans are. Make that equivalence here, rather than passing dummy spans
671        // to lookup_debug_loc, which will return line 1 for them.
672        let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc {
673            (0, 0)
674        } else {
675            let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
676            (line, col)
677        };
678
679        unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) }
680    }
681
682    fn create_vtable_debuginfo(
683        &self,
684        ty: Ty<'tcx>,
685        trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
686        vtable: Self::Value,
687    ) {
688        metadata::create_vtable_di_node(self, ty, trait_ref, vtable)
689    }
690
691    fn extend_scope_to_file(
692        &self,
693        scope_metadata: &'ll DIScope,
694        file: &rustc_span::SourceFile,
695    ) -> &'ll DILexicalBlock {
696        metadata::extend_scope_to_file(self, scope_metadata, file)
697    }
698
699    fn debuginfo_finalize(&self) {
700        finalize(self)
701    }
702
703    // FIXME(eddyb) find a common convention for all of the debuginfo-related
704    // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
705    fn create_dbg_var(
706        &self,
707        variable_name: Symbol,
708        variable_type: Ty<'tcx>,
709        scope_metadata: &'ll DIScope,
710        variable_kind: VariableKind,
711        span: Span,
712    ) -> &'ll DIVariable {
713        let loc = self.lookup_debug_loc(span.lo());
714        let file_metadata = file_metadata(self, &loc.file);
715
716        let type_metadata = spanned_type_di_node(self, variable_type, span);
717
718        let align = self.align_of(variable_type);
719
720        let name = variable_name.as_str();
721
722        match variable_kind {
723            ArgumentVariable(arg_index) => unsafe {
724                llvm::LLVMDIBuilderCreateParameterVariable(
725                    DIB(self),
726                    scope_metadata,
727                    name.as_ptr(),
728                    name.len(),
729                    arg_index as c_uint,
730                    file_metadata,
731                    loc.line,
732                    type_metadata,
733                    llvm::Bool::TRUE, // (preserve descriptor during optimizations)
734                    DIFlags::FlagZero,
735                )
736            },
737            LocalVariable => unsafe {
738                llvm::LLVMDIBuilderCreateAutoVariable(
739                    DIB(self),
740                    scope_metadata,
741                    name.as_ptr(),
742                    name.len(),
743                    file_metadata,
744                    loc.line,
745                    type_metadata,
746                    llvm::Bool::TRUE, // (preserve descriptor during optimizations)
747                    DIFlags::FlagZero,
748                    align.bits() as u32,
749                )
750            },
751        }
752    }
753}