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