1#\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
52pub(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 llvm::add_module_flag_u32(
76 llmod,
77 llvm::ModuleFlagMergeBehavior::Max,
82 "Dwarf Version",
83 sess.dwarf_version(),
84 );
85 }
86 DebuginfoKind::Pdb => {
87 llvm::add_module_flag_u32(
89 llmod,
90 llvm::ModuleFlagMergeBehavior::Warning,
91 "CodeView",
92 1,
93 );
94 }
95 }
96
97 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 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 let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
151
152 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 let linkage_name = if &name == linkage_name { "" } else { linkage_name };
169
170 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 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 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 if cx.sess().target.is_like_msvc {
253 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 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 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 fn get_containing_scope<'ll, 'tcx>(
333 cx: &CodegenCx<'ll, 'tcx>,
334 instance: Instance<'tcx>,
335 ) -> (&'ll DIScope, bool) {
336 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 if let ty::Adt(def, ..) = impl_self_ty.kind()
351 && !def.is_box()
352 {
353 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 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 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, 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, DIFlags::FlagZero,
477 align.bits() as u32,
478 )
479 },
480 }
481 }
482
483 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 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 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 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 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 if self.sess().fewer_names() {
601 return;
602 }
603
604 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 if llvm::get_value_name(value).is_empty() {
617 llvm::set_value_name(value, name.as_bytes());
618 }
619 }
620
621 fn with_move_annotation<R>(
630 &mut self,
631 instance: ty::Instance<'tcx>,
632 f: impl FnOnce(&mut Self) -> R,
633 ) -> R {
634 let saved_loc = self.get_dbg_loc();
636
637 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 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 self.set_dbg_loc(inlined_loc);
658
659 let result = f(self);
661
662 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
673struct DebugLoc {
678 file: Arc<SourceFile>,
680 line: u32,
682 col: u32,
684}
685
686impl<'ll> CodegenCx<'ll, '_> {
687 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 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 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 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 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}