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.types().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| {
302 let actual_type = cx.tcx.normalize_erasing_regions(
303 cx.typing_env(),
304 Unnormalized::new_wip(ty),
305 );
306 let actual_type_metadata = type_di_node(cx, actual_type);
307 Some(cx.create_template_type_parameter(
308 name.as_str(),
309 actual_type_metadata,
310 ))
311 })
312 })
313 .collect()
314 } else {
315 ::alloc::vec::Vec::new()vec![]
316 };
317
318 create_DIArray(DIB(cx), &template_params)
319 }
320
321 fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
322 let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
323 get_parameter_names(cx, cx.tcx.generics_of(def_id))
324 });
325 names.extend(generics.own_params.iter().map(|param| param.name));
326 names
327 }
328
329 fn get_containing_scope<'ll, 'tcx>(
332 cx: &CodegenCx<'ll, 'tcx>,
333 instance: Instance<'tcx>,
334 ) -> (&'ll DIScope, bool) {
335 if let Some(imp_def_id) = cx.tcx.inherent_impl_of_assoc(instance.def_id()) {
341 let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
342 instance.args,
343 cx.typing_env(),
344 cx.tcx.type_of(imp_def_id),
345 );
346
347 if let ty::Adt(def, ..) = impl_self_ty.kind()
350 && !def.is_box()
351 {
352 if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() {
354 return (type_di_node(cx, impl_self_ty), true);
355 } else {
356 return (namespace::item_namespace(cx, def.did()), false);
357 }
358 }
359 }
360
361 let scope = namespace::item_namespace(
362 cx,
363 DefId {
364 krate: instance.def_id().krate,
365 index: cx
366 .tcx
367 .def_key(instance.def_id())
368 .parent
369 .expect("get_containing_scope: missing parent?"),
370 },
371 );
372 (scope, false)
373 }
374 }
375
376 fn dbg_create_lexical_block(
377 &mut self,
378 pos: BytePos,
379 parent_scope: &'ll DIScope,
380 ) -> &'ll DIScope {
381 let loc = self.lookup_debug_loc(pos);
382 let file_metadata = file_metadata(self, &loc.file);
383 unsafe {
384 llvm::LLVMDIBuilderCreateLexicalBlock(
385 DIB(self),
386 parent_scope,
387 file_metadata,
388 loc.line,
389 loc.col,
390 )
391 }
392 }
393
394 fn dbg_location_clone_with_discriminator(
395 &mut self,
396 loc: &'ll DILocation,
397 discriminator: u32,
398 ) -> Option<&'ll DILocation> {
399 unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, discriminator) }
400 }
401
402 fn dbg_loc(
403 &mut self,
404 scope: &'ll DIScope,
405 inlined_at: Option<&'ll DILocation>,
406 span: Span,
407 ) -> &'ll DILocation {
408 let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc {
414 (0, 0)
415 } else {
416 let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
417 (line, col)
418 };
419
420 unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) }
421 }
422
423 fn extend_scope_to_file(
424 &mut self,
425 scope_metadata: &'ll DIScope,
426 file: &rustc_span::SourceFile,
427 ) -> &'ll DILexicalBlock {
428 metadata::extend_scope_to_file(self, scope_metadata, file)
429 }
430
431 fn create_dbg_var(
434 &mut self,
435 variable_name: Symbol,
436 variable_type: Ty<'tcx>,
437 scope_metadata: &'ll DIScope,
438 variable_kind: VariableKind,
439 span: Span,
440 ) -> &'ll DIVariable {
441 let loc = self.lookup_debug_loc(span.lo());
442 let file_metadata = file_metadata(self, &loc.file);
443
444 let type_metadata = spanned_type_di_node(self, variable_type, span);
445
446 let align = self.align_of(variable_type);
447
448 let name = variable_name.as_str();
449
450 match variable_kind {
451 ArgumentVariable(arg_index) => unsafe {
452 llvm::LLVMDIBuilderCreateParameterVariable(
453 DIB(self),
454 scope_metadata,
455 name.as_ptr(),
456 name.len(),
457 arg_index as c_uint,
458 file_metadata,
459 loc.line,
460 type_metadata,
461 llvm::Bool::TRUE, DIFlags::FlagZero,
463 )
464 },
465 LocalVariable => unsafe {
466 llvm::LLVMDIBuilderCreateAutoVariable(
467 DIB(self),
468 scope_metadata,
469 name.as_ptr(),
470 name.len(),
471 file_metadata,
472 loc.line,
473 type_metadata,
474 llvm::Bool::TRUE, DIFlags::FlagZero,
476 align.bits() as u32,
477 )
478 },
479 }
480 }
481
482 fn dbg_var_addr(
485 &mut self,
486 dbg_var: &'ll DIVariable,
487 dbg_loc: &'ll DILocation,
488 variable_alloca: Self::Value,
489 direct_offset: Size,
490 indirect_offsets: &[Size],
491 fragment: &Option<Range<Size>>,
492 ) {
493 use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst};
494
495 let mut addr_ops = SmallVec::<[u64; 8]>::new();
497
498 if direct_offset.bytes() > 0 {
499 addr_ops.push(DW_OP_plus_uconst);
500 addr_ops.push(direct_offset.bytes());
501 }
502 for &offset in indirect_offsets {
503 addr_ops.push(DW_OP_deref);
504 if offset.bytes() > 0 {
505 addr_ops.push(DW_OP_plus_uconst);
506 addr_ops.push(offset.bytes());
507 }
508 }
509 if let Some(fragment) = fragment {
510 addr_ops.push(DW_OP_LLVM_fragment);
513 addr_ops.push(fragment.start.bits());
514 addr_ops.push((fragment.end - fragment.start).bits());
515 }
516
517 let di_builder = DIB(self.cx());
518 let addr_expr = di_builder.create_expression(&addr_ops);
519 unsafe {
520 llvm::LLVMDIBuilderInsertDeclareRecordAtEnd(
521 di_builder,
522 variable_alloca,
523 dbg_var,
524 addr_expr,
525 dbg_loc,
526 self.llbb(),
527 )
528 };
529 }
530
531 fn dbg_var_value(
532 &mut self,
533 dbg_var: &'ll DIVariable,
534 dbg_loc: &'ll DILocation,
535 value: Self::Value,
536 direct_offset: Size,
537 indirect_offsets: &[Size],
538 fragment: &Option<Range<Size>>,
539 ) {
540 use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst, DW_OP_stack_value};
541
542 let mut addr_ops = SmallVec::<[u64; 8]>::new();
544
545 if direct_offset.bytes() > 0 {
546 addr_ops.push(DW_OP_plus_uconst);
547 addr_ops.push(direct_offset.bytes() as u64);
548 addr_ops.push(DW_OP_stack_value);
549 }
550 for &offset in indirect_offsets {
551 addr_ops.push(DW_OP_deref);
552 if offset.bytes() > 0 {
553 addr_ops.push(DW_OP_plus_uconst);
554 addr_ops.push(offset.bytes() as u64);
555 }
556 }
557 if let Some(fragment) = fragment {
558 addr_ops.push(DW_OP_LLVM_fragment);
561 addr_ops.push(fragment.start.bits() as u64);
562 addr_ops.push((fragment.end - fragment.start).bits() as u64);
563 }
564
565 let di_builder = DIB(self.cx());
566 let addr_expr = unsafe {
567 llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len())
568 };
569 unsafe {
570 llvm::LLVMDIBuilderInsertDbgValueRecordAtEnd(
571 di_builder,
572 value,
573 dbg_var,
574 addr_expr,
575 dbg_loc,
576 self.llbb(),
577 );
578 }
579 }
580
581 fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) {
582 unsafe {
583 llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc);
584 }
585 }
586
587 fn clear_dbg_loc(&mut self) {
588 unsafe {
589 llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, ptr::null());
590 }
591 }
592
593 fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
594 gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
595 }
596
597 fn set_var_name(&mut self, value: &'ll Value, name: &str) {
598 if self.sess().fewer_names() {
600 return;
601 }
602
603 let param_or_inst = unsafe {
606 llvm::LLVMIsAArgument(value).is_some() || llvm::LLVMIsAInstruction(value).is_some()
607 };
608 if !param_or_inst {
609 return;
610 }
611
612 if llvm::get_value_name(value).is_empty() {
616 llvm::set_value_name(value, name.as_bytes());
617 }
618 }
619
620 fn with_move_annotation<R>(
629 &mut self,
630 instance: ty::Instance<'tcx>,
631 f: impl FnOnce(&mut Self) -> R,
632 ) -> R {
633 let saved_loc = self.get_dbg_loc();
635
636 let fn_abi = self
639 .cx()
640 .tcx
641 .fn_abi_of_instance(
642 self.cx().typing_env().as_query_input((instance, ty::List::empty())),
643 )
644 .unwrap();
645
646 let di_scope = self.dbg_scope_fn(instance, fn_abi, None);
647
648 let fn_span = self.cx().tcx.def_span(instance.def_id());
653 let inlined_loc = self.dbg_loc(di_scope, saved_loc, fn_span);
654
655 self.set_dbg_loc(inlined_loc);
657
658 let result = f(self);
660
661 if let Some(loc) = saved_loc {
663 self.set_dbg_loc(loc);
664 } else {
665 self.clear_dbg_loc();
666 }
667
668 result
669 }
670}
671
672struct DebugLoc {
677 file: Arc<SourceFile>,
679 line: u32,
681 col: u32,
683}
684
685impl<'ll> CodegenCx<'ll, '_> {
686 fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
691 let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
692 Ok(SourceFileAndLine { sf: file, line }) => {
693 let line_pos = file.lines()[line];
694
695 let line = (line + 1) as u32;
697 let col = (file.relative_position(pos) - line_pos).to_u32() + 1;
698
699 (file, line, col)
700 }
701 Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER),
702 };
703
704 if self.sess().target.is_like_msvc {
708 DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER }
709 } else {
710 DebugLoc { file, line, col }
711 }
712 }
713
714 fn create_template_type_parameter(
715 &self,
716 name: &str,
717 actual_type_metadata: &'ll DIType,
718 ) -> &'ll DITemplateTypeParameter {
719 unsafe {
720 llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
721 DIB(self),
722 None,
723 name.as_c_char_ptr(),
724 name.len(),
725 actual_type_metadata,
726 )
727 }
728 }
729
730 pub(crate) fn debuginfo_finalize(&self) {
732 if let Some(dbg_cx) = &self.dbg_cx {
733 {
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:733",
"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(733u32),
::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");
734
735 if gdb::needs_gdb_debug_scripts_section(self) {
736 gdb::get_or_insert_gdb_debug_scripts_section_global(self);
741 }
742
743 dbg_cx.finalize();
744 }
745 }
746}
747
748impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
749 fn create_vtable_debuginfo(
750 &self,
751 ty: Ty<'tcx>,
752 trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
753 vtable: Self::Value,
754 ) {
755 metadata::create_vtable_di_node(self, ty, trait_ref, vtable)
756 }
757}