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};
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 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));
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 ) -> 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 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 if cx.sess().target.is_like_msvc {
252 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 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 fn get_containing_scope<'ll, 'tcx>(
327 cx: &CodegenCx<'ll, 'tcx>,
328 instance: Instance<'tcx>,
329 ) -> (&'ll DIScope, bool) {
330 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 if let ty::Adt(def, ..) = impl_self_ty.kind()
345 && !def.is_box()
346 {
347 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 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 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, 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, DIFlags::FlagZero,
471 align.bits() as u32,
472 )
473 },
474 }
475 }
476
477 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 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 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 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 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 if self.sess().fewer_names() {
595 return;
596 }
597
598 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 if llvm::get_value_name(value).is_empty() {
611 llvm::set_value_name(value, name.as_bytes());
612 }
613 }
614
615 fn with_move_annotation<R>(
624 &mut self,
625 instance: ty::Instance<'tcx>,
626 f: impl FnOnce(&mut Self) -> R,
627 ) -> R {
628 let saved_loc = self.get_dbg_loc();
630
631 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 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 self.set_dbg_loc(inlined_loc);
652
653 let result = f(self);
655
656 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
667struct DebugLoc {
672 file: Arc<SourceFile>,
674 line: u32,
676 col: u32,
678}
679
680impl<'ll> CodegenCx<'ll, '_> {
681 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 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 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 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 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}