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 adaption 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 to map 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 to control source mappings:\n\n+ `set_source_location()`\n+ `clear_source_location()`\n+ `start_emitting_source_locations()`\n\n`set_source_location()` allows to set 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 later case, subsequent IR instruction\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::{DebugScope, FunctionDebugContext, VariableKind};
14use rustc_codegen_ssa::traits::*;
15use rustc_data_structures::unord::UnordMap;
16use rustc_hir::def_id::{DefId, DefIdMap};
17use rustc_index::IndexVec;
18use rustc_middle::mir;
19use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
20use rustc_middle::ty::{self, GenericArgsRef, Instance, Ty, TypeVisitableExt};
21use rustc_session::Session;
22use rustc_session::config::{self, DebugInfo};
23use rustc_span::{
24    BytePos, Pos, SourceFile, SourceFileAndLine, SourceFileHash, Span, StableSourceFileId, Symbol,
25};
26use rustc_target::callconv::FnAbi;
27use rustc_target::spec::DebuginfoKind;
28use smallvec::SmallVec;
29use tracing::debug;
30
31use self::create_scope_map::compute_mir_scopes;
32pub(crate) use self::di_builder::DIBuilderExt;
33pub(crate) use self::metadata::build_global_var_di_node;
34use self::metadata::{
35    UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER, file_metadata, spanned_type_di_node, type_di_node,
36};
37use self::namespace::mangled_name_of_instance;
38use self::utils::{DIB, create_DIArray, is_node_local_to_unit};
39use crate::builder::Builder;
40use crate::common::{AsCCharPtr, CodegenCx};
41use crate::debuginfo::di_builder::DIBuilderBox;
42use crate::llvm::debuginfo::{
43    DIArray, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope,
44    DITemplateTypeParameter, DIType, DIVariable,
45};
46use crate::llvm::{self, Value};
47
48mod create_scope_map;
49mod di_builder;
50mod dwarf_const;
51mod gdb;
52pub(crate) mod metadata;
53mod namespace;
54mod utils;
55
56/// A context object for maintaining all state needed by the debuginfo module.
57pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> {
58    llmod: &'ll llvm::Module,
59    builder: DIBuilderBox<'ll>,
60    created_files: RefCell<UnordMap<Option<(StableSourceFileId, SourceFileHash)>, &'ll DIFile>>,
61
62    type_map: metadata::TypeMap<'ll, 'tcx>,
63    adt_stack: RefCell<Vec<(DefId, GenericArgsRef<'tcx>)>>,
64    namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
65    recursion_marker_type: OnceCell<&'ll DIType>,
66}
67
68impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
69    pub(crate) fn new(llmod: &'ll llvm::Module) -> Self {
70        {
    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:70",
                        "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(70u32),
                        ::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");
71        let builder = DIBuilderBox::new(llmod);
72        // DIBuilder inherits context from the module, so we'd better use the same one
73        CodegenUnitDebugContext {
74            llmod,
75            builder,
76            created_files: Default::default(),
77            type_map: Default::default(),
78            adt_stack: Default::default(),
79            namespace_map: RefCell::new(Default::default()),
80            recursion_marker_type: OnceCell::new(),
81        }
82    }
83
84    pub(crate) fn finalize(&self, sess: &Session) {
85        unsafe { llvm::LLVMDIBuilderFinalize(self.builder.as_ref()) };
86
87        match sess.target.debuginfo_kind {
88            DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym => {
89                // Debuginfo generation in LLVM by default uses a higher
90                // version of dwarf than macOS currently understands. We can
91                // instruct LLVM to emit an older version of dwarf, however,
92                // for macOS to understand. For more info see #11352
93                // This can be overridden using --llvm-opts -dwarf-version,N.
94                // Android has the same issue (#22398)
95                llvm::add_module_flag_u32(
96                    self.llmod,
97                    // In the case where multiple CGUs with different dwarf version
98                    // values are being merged together, such as with cross-crate
99                    // LTO, then we want to use the highest version of dwarf
100                    // we can. This matches Clang's behavior as well.
101                    llvm::ModuleFlagMergeBehavior::Max,
102                    "Dwarf Version",
103                    sess.dwarf_version(),
104                );
105            }
106            DebuginfoKind::Pdb => {
107                // Indicate that we want CodeView debug information
108                llvm::add_module_flag_u32(
109                    self.llmod,
110                    llvm::ModuleFlagMergeBehavior::Warning,
111                    "CodeView",
112                    1,
113                );
114            }
115        }
116
117        // Prevent bitcode readers from deleting the debug info.
118        llvm::add_module_flag_u32(
119            self.llmod,
120            llvm::ModuleFlagMergeBehavior::Warning,
121            "Debug Info Version",
122            unsafe { llvm::LLVMRustDebugMetadataVersion() },
123        );
124    }
125}
126
127/// Creates any deferred debug metadata nodes
128pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
129    if let Some(dbg_cx) = &cx.dbg_cx {
130        {
    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:130",
                        "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(130u32),
                        ::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");
131
132        if gdb::needs_gdb_debug_scripts_section(cx) {
133            // Add a .debug_gdb_scripts section to this compile-unit. This will
134            // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
135            // which activates the Rust pretty printers for binary this section is
136            // contained in.
137            gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
138        }
139
140        dbg_cx.finalize(cx.sess());
141    }
142}
143
144impl<'ll> Builder<'_, 'll, '_> {
145    pub(crate) fn get_dbg_loc(&self) -> Option<&'ll DILocation> {
146        unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) }
147    }
148}
149
150impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
151    // FIXME(eddyb) find a common convention for all of the debuginfo-related
152    // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
153    fn dbg_var_addr(
154        &mut self,
155        dbg_var: &'ll DIVariable,
156        dbg_loc: &'ll DILocation,
157        variable_alloca: Self::Value,
158        direct_offset: Size,
159        indirect_offsets: &[Size],
160        fragment: &Option<Range<Size>>,
161    ) {
162        use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst};
163
164        // Convert the direct and indirect offsets and fragment byte range to address ops.
165        let mut addr_ops = SmallVec::<[u64; 8]>::new();
166
167        if direct_offset.bytes() > 0 {
168            addr_ops.push(DW_OP_plus_uconst);
169            addr_ops.push(direct_offset.bytes());
170        }
171        for &offset in indirect_offsets {
172            addr_ops.push(DW_OP_deref);
173            if offset.bytes() > 0 {
174                addr_ops.push(DW_OP_plus_uconst);
175                addr_ops.push(offset.bytes());
176            }
177        }
178        if let Some(fragment) = fragment {
179            // `DW_OP_LLVM_fragment` takes as arguments the fragment's
180            // offset and size, both of them in bits.
181            addr_ops.push(DW_OP_LLVM_fragment);
182            addr_ops.push(fragment.start.bits());
183            addr_ops.push((fragment.end - fragment.start).bits());
184        }
185
186        let di_builder = DIB(self.cx());
187        let addr_expr = di_builder.create_expression(&addr_ops);
188        unsafe {
189            llvm::LLVMDIBuilderInsertDeclareRecordAtEnd(
190                di_builder,
191                variable_alloca,
192                dbg_var,
193                addr_expr,
194                dbg_loc,
195                self.llbb(),
196            )
197        };
198    }
199
200    fn dbg_var_value(
201        &mut self,
202        dbg_var: &'ll DIVariable,
203        dbg_loc: &'ll DILocation,
204        value: Self::Value,
205        direct_offset: Size,
206        indirect_offsets: &[Size],
207        fragment: &Option<Range<Size>>,
208    ) {
209        use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst, DW_OP_stack_value};
210
211        // Convert the direct and indirect offsets and fragment byte range to address ops.
212        let mut addr_ops = SmallVec::<[u64; 8]>::new();
213
214        if direct_offset.bytes() > 0 {
215            addr_ops.push(DW_OP_plus_uconst);
216            addr_ops.push(direct_offset.bytes() as u64);
217            addr_ops.push(DW_OP_stack_value);
218        }
219        for &offset in indirect_offsets {
220            addr_ops.push(DW_OP_deref);
221            if offset.bytes() > 0 {
222                addr_ops.push(DW_OP_plus_uconst);
223                addr_ops.push(offset.bytes() as u64);
224            }
225        }
226        if let Some(fragment) = fragment {
227            // `DW_OP_LLVM_fragment` takes as arguments the fragment's
228            // offset and size, both of them in bits.
229            addr_ops.push(DW_OP_LLVM_fragment);
230            addr_ops.push(fragment.start.bits() as u64);
231            addr_ops.push((fragment.end - fragment.start).bits() as u64);
232        }
233
234        let di_builder = DIB(self.cx());
235        let addr_expr = unsafe {
236            llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len())
237        };
238        unsafe {
239            llvm::LLVMDIBuilderInsertDbgValueRecordAtEnd(
240                di_builder,
241                value,
242                dbg_var,
243                addr_expr,
244                dbg_loc,
245                self.llbb(),
246            );
247        }
248    }
249
250    fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) {
251        unsafe {
252            llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc);
253        }
254    }
255
256    fn clear_dbg_loc(&mut self) {
257        unsafe {
258            llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, ptr::null());
259        }
260    }
261
262    fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
263        gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
264    }
265
266    fn set_var_name(&mut self, value: &'ll Value, name: &str) {
267        // Avoid wasting time if LLVM value names aren't even enabled.
268        if self.sess().fewer_names() {
269            return;
270        }
271
272        // Only function parameters and instructions are local to a function,
273        // don't change the name of anything else (e.g. globals).
274        let param_or_inst = unsafe {
275            llvm::LLVMIsAArgument(value).is_some() || llvm::LLVMIsAInstruction(value).is_some()
276        };
277        if !param_or_inst {
278            return;
279        }
280
281        // Avoid replacing the name if it already exists.
282        // While we could combine the names somehow, it'd
283        // get noisy quick, and the usefulness is dubious.
284        if llvm::get_value_name(value).is_empty() {
285            llvm::set_value_name(value, name.as_bytes());
286        }
287    }
288
289    /// Annotate move/copy operations with debug info for profiling.
290    ///
291    /// This creates a temporary debug scope that makes the move/copy appear as an inlined call to
292    /// `compiler_move<T, SIZE>()` or `compiler_copy<T, SIZE>()`. The provided closure is executed
293    /// with this temporary debug location active.
294    ///
295    /// The `instance` parameter should be the monomorphized instance of the `compiler_move` or
296    /// `compiler_copy` function with the actual type and size.
297    fn with_move_annotation<R>(
298        &mut self,
299        instance: ty::Instance<'tcx>,
300        f: impl FnOnce(&mut Self) -> R,
301    ) -> R {
302        // Save the current debug location
303        let saved_loc = self.get_dbg_loc();
304
305        // Create a DIScope for the compiler_move/compiler_copy function
306        // We use the function's FnAbi for debug info generation
307        let fn_abi = self
308            .cx()
309            .tcx
310            .fn_abi_of_instance(
311                self.cx().typing_env().as_query_input((instance, ty::List::empty())),
312            )
313            .unwrap();
314
315        let di_scope = self.cx().dbg_scope_fn(instance, fn_abi, None);
316
317        // Create an inlined debug location:
318        // - scope: the compiler_move/compiler_copy function
319        // - inlined_at: the current location (where the move/copy actually occurs)
320        // - span: use the function's definition span
321        let fn_span = self.cx().tcx.def_span(instance.def_id());
322        let inlined_loc = self.cx().dbg_loc(di_scope, saved_loc, fn_span);
323
324        // Set the temporary debug location
325        self.set_dbg_loc(inlined_loc);
326
327        // Execute the closure (which will generate the memcpy)
328        let result = f(self);
329
330        // Restore the original debug location
331        if let Some(loc) = saved_loc {
332            self.set_dbg_loc(loc);
333        } else {
334            self.clear_dbg_loc();
335        }
336
337        result
338    }
339}
340
341/// A source code location used to generate debug information.
342// FIXME(eddyb) rename this to better indicate it's a duplicate of
343// `rustc_span::Loc` rather than `DILocation`, perhaps by making
344// `lookup_char_pos` return the right information instead.
345struct DebugLoc {
346    /// Information about the original source file.
347    file: Arc<SourceFile>,
348    /// The (1-based) line number.
349    line: u32,
350    /// The (1-based) column number.
351    col: u32,
352}
353
354impl<'ll> CodegenCx<'ll, '_> {
355    /// Looks up debug source information about a `BytePos`.
356    // FIXME(eddyb) rename this to better indicate it's a duplicate of
357    // `lookup_char_pos` rather than `dbg_loc`, perhaps by making
358    // `lookup_char_pos` return the right information instead.
359    fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
360        let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
361            Ok(SourceFileAndLine { sf: file, line }) => {
362                let line_pos = file.lines()[line];
363
364                // Use 1-based indexing.
365                let line = (line + 1) as u32;
366                let col = (file.relative_position(pos) - line_pos).to_u32() + 1;
367
368                (file, line, col)
369            }
370            Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER),
371        };
372
373        // For MSVC, omit the column number.
374        // Otherwise, emit it. This mimics clang behaviour.
375        // See discussion in https://github.com/rust-lang/rust/issues/42921
376        if self.sess().target.is_like_msvc {
377            DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER }
378        } else {
379            DebugLoc { file, line, col }
380        }
381    }
382
383    fn create_template_type_parameter(
384        &self,
385        name: &str,
386        actual_type_metadata: &'ll DIType,
387    ) -> &'ll DITemplateTypeParameter {
388        unsafe {
389            llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
390                DIB(self),
391                None,
392                name.as_c_char_ptr(),
393                name.len(),
394                actual_type_metadata,
395            )
396        }
397    }
398}
399
400impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
401    fn create_function_debug_context(
402        &self,
403        instance: Instance<'tcx>,
404        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
405        llfn: &'ll Value,
406        mir: &mir::Body<'tcx>,
407    ) -> Option<FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>> {
408        if self.sess().opts.debuginfo == DebugInfo::None {
409            return None;
410        }
411
412        // Initialize fn debug context (including scopes).
413        let empty_scope = DebugScope {
414            dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
415            inlined_at: None,
416            file_start_pos: BytePos(0),
417            file_end_pos: BytePos(0),
418        };
419        let mut fn_debug_context = FunctionDebugContext {
420            scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes),
421            inlined_function_scopes: Default::default(),
422        };
423
424        // Fill in all the scopes, with the information from the MIR body.
425        compute_mir_scopes(self, instance, mir, &mut fn_debug_context);
426
427        Some(fn_debug_context)
428    }
429
430    fn dbg_scope_fn(
431        &self,
432        instance: Instance<'tcx>,
433        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
434        maybe_definition_llfn: Option<&'ll Value>,
435    ) -> &'ll DIScope {
436        let tcx = self.tcx;
437
438        let def_id = instance.def_id();
439        let (containing_scope, is_method) = get_containing_scope(self, instance);
440        let span = tcx.def_span(def_id);
441        let loc = self.lookup_debug_loc(span.lo());
442        let file_metadata = file_metadata(self, &loc.file);
443
444        let function_type_metadata =
445            create_subroutine_type(self, &get_function_signature(self, fn_abi));
446
447        let mut name = String::with_capacity(64);
448        type_names::push_item_name(tcx, def_id, false, &mut name);
449
450        // Find the enclosing function, in case this is a closure.
451        let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
452
453        // We look up the generics of the enclosing function and truncate the args
454        // to their length in order to cut off extra stuff that might be in there for
455        // closures or coroutines.
456        let generics = tcx.generics_of(enclosing_fn_def_id);
457        let args = instance.args.truncate_to(tcx, generics);
458
459        type_names::push_generic_args(
460            tcx,
461            tcx.normalize_erasing_regions(self.typing_env(), args),
462            &mut name,
463        );
464
465        let template_parameters = get_template_parameters(self, generics, args);
466
467        let linkage_name = &mangled_name_of_instance(self, instance).name;
468        // Omit the linkage_name if it is the same as subprogram name.
469        let linkage_name = if &name == linkage_name { "" } else { linkage_name };
470
471        // FIXME(eddyb) does this need to be separate from `loc.line` for some reason?
472        let scope_line = loc.line;
473
474        let mut flags = DIFlags::FlagPrototyped;
475
476        if fn_abi.ret.layout.is_uninhabited() {
477            flags |= DIFlags::FlagNoReturn;
478        }
479
480        let mut spflags = DISPFlags::SPFlagDefinition;
481        if is_node_local_to_unit(self, def_id) {
482            spflags |= DISPFlags::SPFlagLocalToUnit;
483        }
484        if self.sess().opts.optimize != config::OptLevel::No {
485            spflags |= DISPFlags::SPFlagOptimized;
486        }
487        if let Some((id, _)) = tcx.entry_fn(()) {
488            if id == def_id {
489                spflags |= DISPFlags::SPFlagMainSubprogram;
490            }
491        }
492
493        // When we're adding a method to a type DIE, we only want a DW_AT_declaration there, because
494        // LLVM LTO can't unify type definitions when a child DIE is a full subprogram definition.
495        // When we use this `decl` below, the subprogram definition gets created at the CU level
496        // with a DW_AT_specification pointing back to the type's declaration.
497        let decl = is_method.then(|| unsafe {
498            llvm::LLVMRustDIBuilderCreateMethod(
499                DIB(self),
500                containing_scope,
501                name.as_c_char_ptr(),
502                name.len(),
503                linkage_name.as_c_char_ptr(),
504                linkage_name.len(),
505                file_metadata,
506                loc.line,
507                function_type_metadata,
508                flags,
509                spflags & !DISPFlags::SPFlagDefinition,
510                template_parameters,
511            )
512        });
513
514        return unsafe {
515            llvm::LLVMRustDIBuilderCreateFunction(
516                DIB(self),
517                containing_scope,
518                name.as_c_char_ptr(),
519                name.len(),
520                linkage_name.as_c_char_ptr(),
521                linkage_name.len(),
522                file_metadata,
523                loc.line,
524                function_type_metadata,
525                scope_line,
526                flags,
527                spflags,
528                maybe_definition_llfn,
529                template_parameters,
530                decl,
531            )
532        };
533
534        fn get_function_signature<'ll, 'tcx>(
535            cx: &CodegenCx<'ll, 'tcx>,
536            fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
537        ) -> Vec<Option<&'ll llvm::Metadata>> {
538            if cx.sess().opts.debuginfo != DebugInfo::Full {
539                return ::alloc::vec::Vec::new()vec![];
540            }
541
542            let mut signature = Vec::with_capacity(fn_abi.args.len() + 1);
543
544            // Return type -- llvm::DIBuilder wants this at index 0
545            signature.push(if fn_abi.ret.is_ignore() {
546                None
547            } else {
548                Some(type_di_node(cx, fn_abi.ret.layout.ty))
549            });
550
551            // Arguments types
552            if cx.sess().target.is_like_msvc {
553                // FIXME(#42800):
554                // There is a bug in MSDIA that leads to a crash when it encounters
555                // a fixed-size array of `u8` or something zero-sized in a
556                // function-type (see #40477).
557                // As a workaround, we replace those fixed-size arrays with a
558                // pointer-type. So a function `fn foo(a: u8, b: [u8; 4])` would
559                // appear as `fn foo(a: u8, b: *const u8)` in debuginfo,
560                // and a function `fn bar(x: [(); 7])` as `fn bar(x: *const ())`.
561                // This transformed type is wrong, but these function types are
562                // already inaccurate due to ABI adjustments (see #42800).
563                signature.extend(fn_abi.args.iter().map(|arg| {
564                    let t = arg.layout.ty;
565                    let t = match t.kind() {
566                        ty::Array(ct, _)
567                            if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() =>
568                        {
569                            Ty::new_imm_ptr(cx.tcx, *ct)
570                        }
571                        _ => t,
572                    };
573                    Some(type_di_node(cx, t))
574                }));
575            } else {
576                signature
577                    .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty))));
578            }
579
580            signature
581        }
582
583        fn get_template_parameters<'ll, 'tcx>(
584            cx: &CodegenCx<'ll, 'tcx>,
585            generics: &ty::Generics,
586            args: GenericArgsRef<'tcx>,
587        ) -> &'ll DIArray {
588            if args.types().next().is_none() {
589                return create_DIArray(DIB(cx), &[]);
590            }
591
592            // Again, only create type information if full debuginfo is enabled
593            let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
594                let names = get_parameter_names(cx, generics);
595                iter::zip(args, names)
596                    .filter_map(|(kind, name)| {
597                        kind.as_type().map(|ty| {
598                            let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
599                            let actual_type_metadata = type_di_node(cx, actual_type);
600                            Some(cx.create_template_type_parameter(
601                                name.as_str(),
602                                actual_type_metadata,
603                            ))
604                        })
605                    })
606                    .collect()
607            } else {
608                ::alloc::vec::Vec::new()vec![]
609            };
610
611            create_DIArray(DIB(cx), &template_params)
612        }
613
614        fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
615            let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
616                get_parameter_names(cx, cx.tcx.generics_of(def_id))
617            });
618            names.extend(generics.own_params.iter().map(|param| param.name));
619            names
620        }
621
622        /// Returns a scope, plus `true` if that's a type scope for "class" methods,
623        /// otherwise `false` for plain namespace scopes.
624        fn get_containing_scope<'ll, 'tcx>(
625            cx: &CodegenCx<'ll, 'tcx>,
626            instance: Instance<'tcx>,
627        ) -> (&'ll DIScope, bool) {
628            // First, let's see if this is a method within an inherent impl. Because
629            // if yes, we want to make the result subroutine DIE a child of the
630            // subroutine's self-type.
631            // For trait method impls we still use the "parallel namespace"
632            // strategy
633            if let Some(imp_def_id) = cx.tcx.inherent_impl_of_assoc(instance.def_id()) {
634                let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
635                    instance.args,
636                    cx.typing_env(),
637                    cx.tcx.type_of(imp_def_id),
638                );
639
640                // Only "class" methods are generally understood by LLVM,
641                // so avoid methods on other types (e.g., `<*mut T>::null`).
642                if let ty::Adt(def, ..) = impl_self_ty.kind()
643                    && !def.is_box()
644                {
645                    // Again, only create type information if full debuginfo is enabled
646                    if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() {
647                        return (type_di_node(cx, impl_self_ty), true);
648                    } else {
649                        return (namespace::item_namespace(cx, def.did()), false);
650                    }
651                }
652            }
653
654            let scope = namespace::item_namespace(
655                cx,
656                DefId {
657                    krate: instance.def_id().krate,
658                    index: cx
659                        .tcx
660                        .def_key(instance.def_id())
661                        .parent
662                        .expect("get_containing_scope: missing parent?"),
663                },
664            );
665            (scope, false)
666        }
667    }
668
669    fn dbg_loc(
670        &self,
671        scope: &'ll DIScope,
672        inlined_at: Option<&'ll DILocation>,
673        span: Span,
674    ) -> &'ll DILocation {
675        // When emitting debugging information, DWARF (i.e. everything but MSVC)
676        // treats line 0 as a magic value meaning that the code could not be
677        // attributed to any line in the source. That's also exactly what dummy
678        // spans are. Make that equivalence here, rather than passing dummy spans
679        // to lookup_debug_loc, which will return line 1 for them.
680        let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc {
681            (0, 0)
682        } else {
683            let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
684            (line, col)
685        };
686
687        unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) }
688    }
689
690    fn create_vtable_debuginfo(
691        &self,
692        ty: Ty<'tcx>,
693        trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
694        vtable: Self::Value,
695    ) {
696        metadata::create_vtable_di_node(self, ty, trait_ref, vtable)
697    }
698
699    fn extend_scope_to_file(
700        &self,
701        scope_metadata: &'ll DIScope,
702        file: &rustc_span::SourceFile,
703    ) -> &'ll DILexicalBlock {
704        metadata::extend_scope_to_file(self, scope_metadata, file)
705    }
706
707    fn debuginfo_finalize(&self) {
708        finalize(self)
709    }
710
711    // FIXME(eddyb) find a common convention for all of the debuginfo-related
712    // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
713    fn create_dbg_var(
714        &self,
715        variable_name: Symbol,
716        variable_type: Ty<'tcx>,
717        scope_metadata: &'ll DIScope,
718        variable_kind: VariableKind,
719        span: Span,
720    ) -> &'ll DIVariable {
721        let loc = self.lookup_debug_loc(span.lo());
722        let file_metadata = file_metadata(self, &loc.file);
723
724        let type_metadata = spanned_type_di_node(self, variable_type, span);
725
726        let align = self.align_of(variable_type);
727
728        let name = variable_name.as_str();
729
730        match variable_kind {
731            ArgumentVariable(arg_index) => unsafe {
732                llvm::LLVMDIBuilderCreateParameterVariable(
733                    DIB(self),
734                    scope_metadata,
735                    name.as_ptr(),
736                    name.len(),
737                    arg_index as c_uint,
738                    file_metadata,
739                    loc.line,
740                    type_metadata,
741                    llvm::Bool::TRUE, // (preserve descriptor during optimizations)
742                    DIFlags::FlagZero,
743                )
744            },
745            LocalVariable => unsafe {
746                llvm::LLVMDIBuilderCreateAutoVariable(
747                    DIB(self),
748                    scope_metadata,
749                    name.as_ptr(),
750                    name.len(),
751                    file_metadata,
752                    loc.line,
753                    type_metadata,
754                    llvm::Bool::TRUE, // (preserve descriptor during optimizations)
755                    DIFlags::FlagZero,
756                    align.bits() as u32,
757                )
758            },
759        }
760    }
761}