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};
                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");
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));
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        ) -> Vec<Option<&'ll llvm::Metadata>> {
237            if cx.sess().opts.debuginfo != DebugInfo::Full {
238                return ::alloc::vec::Vec::new()vec![];
239            }
240
241            let mut signature = Vec::with_capacity(fn_abi.args.len() + 1);
242
243            // Return type -- llvm::DIBuilder wants this at index 0
244            signature.push(if fn_abi.ret.is_ignore() {
245                None
246            } else {
247                Some(type_di_node(cx, fn_abi.ret.layout.ty))
248            });
249
250            // Arguments types
251            if cx.sess().target.is_like_msvc {
252                // FIXME(#42800):
253                // There is a bug in MSDIA that leads to a crash when it encounters
254                // a fixed-size array of `u8` or something zero-sized in a
255                // function-type (see #40477).
256                // As a workaround, we replace those fixed-size arrays with a
257                // pointer-type. So a function `fn foo(a: u8, b: [u8; 4])` would
258                // appear as `fn foo(a: u8, b: *const u8)` in debuginfo,
259                // and a function `fn bar(x: [(); 7])` as `fn bar(x: *const ())`.
260                // This transformed type is wrong, but these function types are
261                // already inaccurate due to ABI adjustments (see #42800).
262                signature.extend(fn_abi.args.iter().map(|arg| {
263                    let t = arg.layout.ty;
264                    let t = match t.kind() {
265                        ty::Array(ct, _)
266                            if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() =>
267                        {
268                            Ty::new_imm_ptr(cx.tcx, *ct)
269                        }
270                        _ => t,
271                    };
272                    Some(type_di_node(cx, t))
273                }));
274            } else {
275                signature
276                    .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty))));
277            }
278
279            signature
280        }
281
282        fn get_template_parameters<'ll, 'tcx>(
283            cx: &CodegenCx<'ll, 'tcx>,
284            generics: &ty::Generics,
285            args: GenericArgsRef<'tcx>,
286        ) -> &'ll DIArray {
287            if args.types().next().is_none() {
288                return create_DIArray(DIB(cx), &[]);
289            }
290
291            // Again, only create type information if full debuginfo is enabled
292            let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
293                let names = get_parameter_names(cx, generics);
294                iter::zip(args, names)
295                    .filter_map(|(kind, name)| {
296                        kind.as_type().map(|ty| {
297                            let actual_type = cx.tcx.normalize_erasing_regions(
298                                cx.typing_env(),
299                                Unnormalized::new_wip(ty),
300                            );
301                            let actual_type_metadata = type_di_node(cx, actual_type);
302                            Some(cx.create_template_type_parameter(
303                                name.as_str(),
304                                actual_type_metadata,
305                            ))
306                        })
307                    })
308                    .collect()
309            } else {
310                ::alloc::vec::Vec::new()vec![]
311            };
312
313            create_DIArray(DIB(cx), &template_params)
314        }
315
316        fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
317            let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
318                get_parameter_names(cx, cx.tcx.generics_of(def_id))
319            });
320            names.extend(generics.own_params.iter().map(|param| param.name));
321            names
322        }
323
324        /// Returns a scope, plus `true` if that's a type scope for "class" methods,
325        /// otherwise `false` for plain namespace scopes.
326        fn get_containing_scope<'ll, 'tcx>(
327            cx: &CodegenCx<'ll, 'tcx>,
328            instance: Instance<'tcx>,
329        ) -> (&'ll DIScope, bool) {
330            // First, let's see if this is a method within an inherent impl. Because
331            // if yes, we want to make the result subroutine DIE a child of the
332            // subroutine's self-type.
333            // For trait method impls we still use the "parallel namespace"
334            // strategy
335            if let Some(imp_def_id) = cx.tcx.inherent_impl_of_assoc(instance.def_id()) {
336                let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
337                    instance.args,
338                    cx.typing_env(),
339                    cx.tcx.type_of(imp_def_id),
340                );
341
342                // Only "class" methods are generally understood by LLVM,
343                // so avoid methods on other types (e.g., `<*mut T>::null`).
344                if let ty::Adt(def, ..) = impl_self_ty.kind()
345                    && !def.is_box()
346                {
347                    // Again, only create type information if full debuginfo is enabled
348                    if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() {
349                        return (type_di_node(cx, impl_self_ty), true);
350                    } else {
351                        return (namespace::item_namespace(cx, def.did()), false);
352                    }
353                }
354            }
355
356            let scope = namespace::item_namespace(
357                cx,
358                DefId {
359                    krate: instance.def_id().krate,
360                    index: cx
361                        .tcx
362                        .def_key(instance.def_id())
363                        .parent
364                        .expect("get_containing_scope: missing parent?"),
365                },
366            );
367            (scope, false)
368        }
369    }
370
371    fn dbg_create_lexical_block(
372        &mut self,
373        pos: BytePos,
374        parent_scope: &'ll DIScope,
375    ) -> &'ll DIScope {
376        let loc = self.lookup_debug_loc(pos);
377        let file_metadata = file_metadata(self, &loc.file);
378        unsafe {
379            llvm::LLVMDIBuilderCreateLexicalBlock(
380                DIB(self),
381                parent_scope,
382                file_metadata,
383                loc.line,
384                loc.col,
385            )
386        }
387    }
388
389    fn dbg_location_clone_with_discriminator(
390        &mut self,
391        loc: &'ll DILocation,
392        discriminator: u32,
393    ) -> Option<&'ll DILocation> {
394        unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, discriminator) }
395    }
396
397    fn dbg_loc(
398        &mut self,
399        scope: &'ll DIScope,
400        inlined_at: Option<&'ll DILocation>,
401        span: Span,
402    ) -> &'ll DILocation {
403        // When emitting debugging information, DWARF (i.e. everything but MSVC)
404        // treats line 0 as a magic value meaning that the code could not be
405        // attributed to any line in the source. That's also exactly what dummy
406        // spans are. Make that equivalence here, rather than passing dummy spans
407        // to lookup_debug_loc, which will return line 1 for them.
408        let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc {
409            (0, 0)
410        } else {
411            let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
412            (line, col)
413        };
414
415        unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) }
416    }
417
418    fn extend_scope_to_file(
419        &mut self,
420        scope_metadata: &'ll DIScope,
421        file: &rustc_span::SourceFile,
422    ) -> &'ll DILexicalBlock {
423        metadata::extend_scope_to_file(self, scope_metadata, file)
424    }
425
426    // FIXME(eddyb) find a common convention for all of the debuginfo-related
427    // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
428    fn create_dbg_var(
429        &mut self,
430        variable_name: Symbol,
431        variable_type: Ty<'tcx>,
432        scope_metadata: &'ll DIScope,
433        variable_kind: VariableKind,
434        span: Span,
435    ) -> &'ll DIVariable {
436        let loc = self.lookup_debug_loc(span.lo());
437        let file_metadata = file_metadata(self, &loc.file);
438
439        let type_metadata = spanned_type_di_node(self, variable_type, span);
440
441        let align = self.align_of(variable_type);
442
443        let name = variable_name.as_str();
444
445        match variable_kind {
446            ArgumentVariable(arg_index) => unsafe {
447                llvm::LLVMDIBuilderCreateParameterVariable(
448                    DIB(self),
449                    scope_metadata,
450                    name.as_ptr(),
451                    name.len(),
452                    arg_index as c_uint,
453                    file_metadata,
454                    loc.line,
455                    type_metadata,
456                    llvm::Bool::TRUE, // (preserve descriptor during optimizations)
457                    DIFlags::FlagZero,
458                )
459            },
460            LocalVariable => unsafe {
461                llvm::LLVMDIBuilderCreateAutoVariable(
462                    DIB(self),
463                    scope_metadata,
464                    name.as_ptr(),
465                    name.len(),
466                    file_metadata,
467                    loc.line,
468                    type_metadata,
469                    llvm::Bool::TRUE, // (preserve descriptor during optimizations)
470                    DIFlags::FlagZero,
471                    align.bits() as u32,
472                )
473            },
474        }
475    }
476
477    // FIXME(eddyb) find a common convention for all of the debuginfo-related
478    // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
479    fn dbg_var_addr(
480        &mut self,
481        dbg_var: &'ll DIVariable,
482        dbg_loc: &'ll DILocation,
483        variable_alloca: Self::Value,
484        direct_offset: Size,
485        indirect_offsets: &[Size],
486        fragment: &Option<Range<Size>>,
487    ) {
488        use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst};
489
490        // Convert the direct and indirect offsets and fragment byte range to address ops.
491        let mut addr_ops = SmallVec::<[u64; 8]>::new();
492
493        if direct_offset.bytes() > 0 {
494            addr_ops.push(DW_OP_plus_uconst);
495            addr_ops.push(direct_offset.bytes());
496        }
497        for &offset in indirect_offsets {
498            addr_ops.push(DW_OP_deref);
499            if offset.bytes() > 0 {
500                addr_ops.push(DW_OP_plus_uconst);
501                addr_ops.push(offset.bytes());
502            }
503        }
504        if let Some(fragment) = fragment {
505            // `DW_OP_LLVM_fragment` takes as arguments the fragment's
506            // offset and size, both of them in bits.
507            addr_ops.push(DW_OP_LLVM_fragment);
508            addr_ops.push(fragment.start.bits());
509            addr_ops.push((fragment.end - fragment.start).bits());
510        }
511
512        let di_builder = DIB(self.cx());
513        let addr_expr = di_builder.create_expression(&addr_ops);
514        unsafe {
515            llvm::LLVMDIBuilderInsertDeclareRecordAtEnd(
516                di_builder,
517                variable_alloca,
518                dbg_var,
519                addr_expr,
520                dbg_loc,
521                self.llbb(),
522            )
523        };
524    }
525
526    fn dbg_var_value(
527        &mut self,
528        dbg_var: &'ll DIVariable,
529        dbg_loc: &'ll DILocation,
530        value: Self::Value,
531        direct_offset: Size,
532        indirect_offsets: &[Size],
533        fragment: &Option<Range<Size>>,
534    ) {
535        use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst, DW_OP_stack_value};
536
537        // Convert the direct and indirect offsets and fragment byte range to address ops.
538        let mut addr_ops = SmallVec::<[u64; 8]>::new();
539
540        if direct_offset.bytes() > 0 {
541            addr_ops.push(DW_OP_plus_uconst);
542            addr_ops.push(direct_offset.bytes() as u64);
543            addr_ops.push(DW_OP_stack_value);
544        }
545        for &offset in indirect_offsets {
546            addr_ops.push(DW_OP_deref);
547            if offset.bytes() > 0 {
548                addr_ops.push(DW_OP_plus_uconst);
549                addr_ops.push(offset.bytes() as u64);
550            }
551        }
552        if let Some(fragment) = fragment {
553            // `DW_OP_LLVM_fragment` takes as arguments the fragment's
554            // offset and size, both of them in bits.
555            addr_ops.push(DW_OP_LLVM_fragment);
556            addr_ops.push(fragment.start.bits() as u64);
557            addr_ops.push((fragment.end - fragment.start).bits() as u64);
558        }
559
560        let di_builder = DIB(self.cx());
561        let addr_expr = unsafe {
562            llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len())
563        };
564        unsafe {
565            llvm::LLVMDIBuilderInsertDbgValueRecordAtEnd(
566                di_builder,
567                value,
568                dbg_var,
569                addr_expr,
570                dbg_loc,
571                self.llbb(),
572            );
573        }
574    }
575
576    fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) {
577        unsafe {
578            llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc);
579        }
580    }
581
582    fn clear_dbg_loc(&mut self) {
583        unsafe {
584            llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, ptr::null());
585        }
586    }
587
588    fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
589        gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
590    }
591
592    fn set_var_name(&mut self, value: &'ll Value, name: &str) {
593        // Avoid wasting time if LLVM value names aren't even enabled.
594        if self.sess().fewer_names() {
595            return;
596        }
597
598        // Only function parameters and instructions are local to a function,
599        // don't change the name of anything else (e.g. globals).
600        let param_or_inst = unsafe {
601            llvm::LLVMIsAArgument(value).is_some() || llvm::LLVMIsAInstruction(value).is_some()
602        };
603        if !param_or_inst {
604            return;
605        }
606
607        // Avoid replacing the name if it already exists.
608        // While we could combine the names somehow, it'd
609        // get noisy quick, and the usefulness is dubious.
610        if llvm::get_value_name(value).is_empty() {
611            llvm::set_value_name(value, name.as_bytes());
612        }
613    }
614
615    /// Annotate move/copy operations with debug info for profiling.
616    ///
617    /// This creates a temporary debug scope that makes the move/copy appear as an inlined call to
618    /// `compiler_move<T, SIZE>()` or `compiler_copy<T, SIZE>()`. The provided closure is executed
619    /// with this temporary debug location active.
620    ///
621    /// The `instance` parameter should be the monomorphized instance of the `compiler_move` or
622    /// `compiler_copy` function with the actual type and size.
623    fn with_move_annotation<R>(
624        &mut self,
625        instance: ty::Instance<'tcx>,
626        f: impl FnOnce(&mut Self) -> R,
627    ) -> R {
628        // Save the current debug location
629        let saved_loc = self.get_dbg_loc();
630
631        // Create a DIScope for the compiler_move/compiler_copy function
632        // We use the function's FnAbi for debug info generation
633        let fn_abi = self
634            .cx()
635            .tcx
636            .fn_abi_of_instance(
637                self.cx().typing_env().as_query_input((instance, ty::List::empty())),
638            )
639            .unwrap();
640
641        let di_scope = self.dbg_scope_fn(instance, fn_abi, None);
642
643        // Create an inlined debug location:
644        // - scope: the compiler_move/compiler_copy function
645        // - inlined_at: the current location (where the move/copy actually occurs)
646        // - span: use the function's definition span
647        let fn_span = self.cx().tcx.def_span(instance.def_id());
648        let inlined_loc = self.dbg_loc(di_scope, saved_loc, fn_span);
649
650        // Set the temporary debug location
651        self.set_dbg_loc(inlined_loc);
652
653        // Execute the closure (which will generate the memcpy)
654        let result = f(self);
655
656        // Restore the original debug location
657        if let Some(loc) = saved_loc {
658            self.set_dbg_loc(loc);
659        } else {
660            self.clear_dbg_loc();
661        }
662
663        result
664    }
665}
666
667/// A source code location used to generate debug information.
668// FIXME(eddyb) rename this to better indicate it's a duplicate of
669// `rustc_span::Loc` rather than `DILocation`, perhaps by making
670// `lookup_char_pos` return the right information instead.
671struct DebugLoc {
672    /// Information about the original source file.
673    file: Arc<SourceFile>,
674    /// The (1-based) line number.
675    line: u32,
676    /// The (1-based) column number.
677    col: u32,
678}
679
680impl<'ll> CodegenCx<'ll, '_> {
681    /// Looks up debug source information about a `BytePos`.
682    // FIXME(eddyb) rename this to better indicate it's a duplicate of
683    // `lookup_char_pos` rather than `dbg_loc`, perhaps by making
684    // `lookup_char_pos` return the right information instead.
685    fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
686        let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
687            Ok(SourceFileAndLine { sf: file, line }) => {
688                let line_pos = file.lines()[line];
689
690                // Use 1-based indexing.
691                let line = (line + 1) as u32;
692                let col = (file.relative_position(pos) - line_pos).to_u32() + 1;
693
694                (file, line, col)
695            }
696            Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER),
697        };
698
699        // For MSVC, omit the column number.
700        // Otherwise, emit it. This mimics clang behaviour.
701        // See discussion in https://github.com/rust-lang/rust/issues/42921
702        if self.sess().target.is_like_msvc {
703            DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER }
704        } else {
705            DebugLoc { file, line, col }
706        }
707    }
708
709    fn create_template_type_parameter(
710        &self,
711        name: &str,
712        actual_type_metadata: &'ll DIType,
713    ) -> &'ll DITemplateTypeParameter {
714        unsafe {
715            llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
716                DIB(self),
717                None,
718                name.as_c_char_ptr(),
719                name.len(),
720                actual_type_metadata,
721            )
722        }
723    }
724
725    /// Creates any deferred debug metadata nodes
726    pub(crate) fn debuginfo_finalize(&self) {
727        if let Some(dbg_cx) = &self.dbg_cx {
728            {
    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:728",
                        "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(728u32),
                        ::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");
729
730            if gdb::needs_gdb_debug_scripts_section(self) {
731                // Add a .debug_gdb_scripts section to this compile-unit. This will
732                // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
733                // which activates the Rust pretty printers for binary this section is
734                // contained in.
735                gdb::get_or_insert_gdb_debug_scripts_section_global(self);
736            }
737
738            dbg_cx.finalize();
739        }
740    }
741}
742
743impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
744    fn create_vtable_debuginfo(
745        &self,
746        ty: Ty<'tcx>,
747        trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
748        vtable: Self::Value,
749    ) {
750        metadata::create_vtable_di_node(self, ty, trait_ref, vtable)
751    }
752}