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 adaption 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 to map 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 to control source mappings:\n\n+ `set_source_location()`\n+ `clear_source_location()`\n+ `start_emitting_source_locations()`\n\n`set_source_location()` allows to set 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 later case, subsequent IR instruction\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::{DebugScope, FunctionDebugContext, VariableKind};
14use rustc_codegen_ssa::traits::*;
15use rustc_data_structures::unord::UnordMap;
16use rustc_hir::def_id::{DefId, DefIdMap};
17use rustc_index::IndexVec;
18use rustc_middle::mir;
19use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf};
20use rustc_middle::ty::{self, GenericArgsRef, Instance, Ty, TypeVisitableExt};
21use rustc_session::Session;
22use rustc_session::config::{self, DebugInfo};
23use rustc_span::{
24 BytePos, Pos, SourceFile, SourceFileAndLine, SourceFileHash, Span, StableSourceFileId, Symbol,
25};
26use rustc_target::callconv::FnAbi;
27use rustc_target::spec::DebuginfoKind;
28use smallvec::SmallVec;
29use tracing::debug;
30
31use self::create_scope_map::compute_mir_scopes;
32pub(crate) use self::di_builder::DIBuilderExt;
33pub(crate) use self::metadata::build_global_var_di_node;
34use self::metadata::{
35 UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER, file_metadata, spanned_type_di_node, type_di_node,
36};
37use self::namespace::mangled_name_of_instance;
38use self::utils::{DIB, create_DIArray, is_node_local_to_unit};
39use crate::builder::Builder;
40use crate::common::{AsCCharPtr, CodegenCx};
41use crate::debuginfo::di_builder::DIBuilderBox;
42use crate::llvm::debuginfo::{
43 DIArray, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope,
44 DITemplateTypeParameter, DIType, DIVariable,
45};
46use crate::llvm::{self, Value};
47
48mod create_scope_map;
49mod di_builder;
50mod dwarf_const;
51mod gdb;
52pub(crate) mod metadata;
53mod namespace;
54mod utils;
55
56pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> {
58 llmod: &'ll llvm::Module,
59 builder: DIBuilderBox<'ll>,
60 created_files: RefCell<UnordMap<Option<(StableSourceFileId, SourceFileHash)>, &'ll DIFile>>,
61
62 type_map: metadata::TypeMap<'ll, 'tcx>,
63 adt_stack: RefCell<Vec<(DefId, GenericArgsRef<'tcx>)>>,
64 namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
65 recursion_marker_type: OnceCell<&'ll DIType>,
66}
67
68impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
69 pub(crate) fn new(llmod: &'ll llvm::Module) -> Self {
70 {
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:70",
"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(70u32),
::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");
71 let builder = DIBuilderBox::new(llmod);
72 CodegenUnitDebugContext {
74 llmod,
75 builder,
76 created_files: Default::default(),
77 type_map: Default::default(),
78 adt_stack: Default::default(),
79 namespace_map: RefCell::new(Default::default()),
80 recursion_marker_type: OnceCell::new(),
81 }
82 }
83
84 pub(crate) fn finalize(&self, sess: &Session) {
85 unsafe { llvm::LLVMDIBuilderFinalize(self.builder.as_ref()) };
86
87 match sess.target.debuginfo_kind {
88 DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym => {
89 llvm::add_module_flag_u32(
96 self.llmod,
97 llvm::ModuleFlagMergeBehavior::Max,
102 "Dwarf Version",
103 sess.dwarf_version(),
104 );
105 }
106 DebuginfoKind::Pdb => {
107 llvm::add_module_flag_u32(
109 self.llmod,
110 llvm::ModuleFlagMergeBehavior::Warning,
111 "CodeView",
112 1,
113 );
114 }
115 }
116
117 llvm::add_module_flag_u32(
119 self.llmod,
120 llvm::ModuleFlagMergeBehavior::Warning,
121 "Debug Info Version",
122 unsafe { llvm::LLVMRustDebugMetadataVersion() },
123 );
124 }
125}
126
127pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
129 if let Some(dbg_cx) = &cx.dbg_cx {
130 {
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:130",
"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(130u32),
::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");
131
132 if gdb::needs_gdb_debug_scripts_section(cx) {
133 gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
138 }
139
140 dbg_cx.finalize(cx.sess());
141 }
142}
143
144impl<'ll> Builder<'_, 'll, '_> {
145 pub(crate) fn get_dbg_loc(&self) -> Option<&'ll DILocation> {
146 unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) }
147 }
148}
149
150impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
151 fn dbg_var_addr(
154 &mut self,
155 dbg_var: &'ll DIVariable,
156 dbg_loc: &'ll DILocation,
157 variable_alloca: Self::Value,
158 direct_offset: Size,
159 indirect_offsets: &[Size],
160 fragment: &Option<Range<Size>>,
161 ) {
162 use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst};
163
164 let mut addr_ops = SmallVec::<[u64; 8]>::new();
166
167 if direct_offset.bytes() > 0 {
168 addr_ops.push(DW_OP_plus_uconst);
169 addr_ops.push(direct_offset.bytes());
170 }
171 for &offset in indirect_offsets {
172 addr_ops.push(DW_OP_deref);
173 if offset.bytes() > 0 {
174 addr_ops.push(DW_OP_plus_uconst);
175 addr_ops.push(offset.bytes());
176 }
177 }
178 if let Some(fragment) = fragment {
179 addr_ops.push(DW_OP_LLVM_fragment);
182 addr_ops.push(fragment.start.bits());
183 addr_ops.push((fragment.end - fragment.start).bits());
184 }
185
186 let di_builder = DIB(self.cx());
187 let addr_expr = di_builder.create_expression(&addr_ops);
188 unsafe {
189 llvm::LLVMDIBuilderInsertDeclareRecordAtEnd(
190 di_builder,
191 variable_alloca,
192 dbg_var,
193 addr_expr,
194 dbg_loc,
195 self.llbb(),
196 )
197 };
198 }
199
200 fn dbg_var_value(
201 &mut self,
202 dbg_var: &'ll DIVariable,
203 dbg_loc: &'ll DILocation,
204 value: Self::Value,
205 direct_offset: Size,
206 indirect_offsets: &[Size],
207 fragment: &Option<Range<Size>>,
208 ) {
209 use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst, DW_OP_stack_value};
210
211 let mut addr_ops = SmallVec::<[u64; 8]>::new();
213
214 if direct_offset.bytes() > 0 {
215 addr_ops.push(DW_OP_plus_uconst);
216 addr_ops.push(direct_offset.bytes() as u64);
217 addr_ops.push(DW_OP_stack_value);
218 }
219 for &offset in indirect_offsets {
220 addr_ops.push(DW_OP_deref);
221 if offset.bytes() > 0 {
222 addr_ops.push(DW_OP_plus_uconst);
223 addr_ops.push(offset.bytes() as u64);
224 }
225 }
226 if let Some(fragment) = fragment {
227 addr_ops.push(DW_OP_LLVM_fragment);
230 addr_ops.push(fragment.start.bits() as u64);
231 addr_ops.push((fragment.end - fragment.start).bits() as u64);
232 }
233
234 let di_builder = DIB(self.cx());
235 let addr_expr = unsafe {
236 llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len())
237 };
238 unsafe {
239 llvm::LLVMDIBuilderInsertDbgValueRecordAtEnd(
240 di_builder,
241 value,
242 dbg_var,
243 addr_expr,
244 dbg_loc,
245 self.llbb(),
246 );
247 }
248 }
249
250 fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) {
251 unsafe {
252 llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc);
253 }
254 }
255
256 fn clear_dbg_loc(&mut self) {
257 unsafe {
258 llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, ptr::null());
259 }
260 }
261
262 fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
263 gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
264 }
265
266 fn set_var_name(&mut self, value: &'ll Value, name: &str) {
267 if self.sess().fewer_names() {
269 return;
270 }
271
272 let param_or_inst = unsafe {
275 llvm::LLVMIsAArgument(value).is_some() || llvm::LLVMIsAInstruction(value).is_some()
276 };
277 if !param_or_inst {
278 return;
279 }
280
281 if llvm::get_value_name(value).is_empty() {
285 llvm::set_value_name(value, name.as_bytes());
286 }
287 }
288
289 fn with_move_annotation<R>(
298 &mut self,
299 instance: ty::Instance<'tcx>,
300 f: impl FnOnce(&mut Self) -> R,
301 ) -> R {
302 let saved_loc = self.get_dbg_loc();
304
305 let fn_abi = self
308 .cx()
309 .tcx
310 .fn_abi_of_instance(
311 self.cx().typing_env().as_query_input((instance, ty::List::empty())),
312 )
313 .unwrap();
314
315 let di_scope = self.cx().dbg_scope_fn(instance, fn_abi, None);
316
317 let fn_span = self.cx().tcx.def_span(instance.def_id());
322 let inlined_loc = self.cx().dbg_loc(di_scope, saved_loc, fn_span);
323
324 self.set_dbg_loc(inlined_loc);
326
327 let result = f(self);
329
330 if let Some(loc) = saved_loc {
332 self.set_dbg_loc(loc);
333 } else {
334 self.clear_dbg_loc();
335 }
336
337 result
338 }
339}
340
341struct DebugLoc {
346 file: Arc<SourceFile>,
348 line: u32,
350 col: u32,
352}
353
354impl<'ll> CodegenCx<'ll, '_> {
355 fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
360 let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
361 Ok(SourceFileAndLine { sf: file, line }) => {
362 let line_pos = file.lines()[line];
363
364 let line = (line + 1) as u32;
366 let col = (file.relative_position(pos) - line_pos).to_u32() + 1;
367
368 (file, line, col)
369 }
370 Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER),
371 };
372
373 if self.sess().target.is_like_msvc {
377 DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER }
378 } else {
379 DebugLoc { file, line, col }
380 }
381 }
382
383 fn create_template_type_parameter(
384 &self,
385 name: &str,
386 actual_type_metadata: &'ll DIType,
387 ) -> &'ll DITemplateTypeParameter {
388 unsafe {
389 llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
390 DIB(self),
391 None,
392 name.as_c_char_ptr(),
393 name.len(),
394 actual_type_metadata,
395 )
396 }
397 }
398}
399
400impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
401 fn create_function_debug_context(
402 &self,
403 instance: Instance<'tcx>,
404 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
405 llfn: &'ll Value,
406 mir: &mir::Body<'tcx>,
407 ) -> Option<FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>> {
408 if self.sess().opts.debuginfo == DebugInfo::None {
409 return None;
410 }
411
412 let empty_scope = DebugScope {
414 dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
415 inlined_at: None,
416 file_start_pos: BytePos(0),
417 file_end_pos: BytePos(0),
418 };
419 let mut fn_debug_context = FunctionDebugContext {
420 scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes),
421 inlined_function_scopes: Default::default(),
422 };
423
424 compute_mir_scopes(self, instance, mir, &mut fn_debug_context);
426
427 Some(fn_debug_context)
428 }
429
430 fn dbg_scope_fn(
431 &self,
432 instance: Instance<'tcx>,
433 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
434 maybe_definition_llfn: Option<&'ll Value>,
435 ) -> &'ll DIScope {
436 let tcx = self.tcx;
437
438 let def_id = instance.def_id();
439 let (containing_scope, is_method) = get_containing_scope(self, instance);
440 let span = tcx.def_span(def_id);
441 let loc = self.lookup_debug_loc(span.lo());
442 let file_metadata = file_metadata(self, &loc.file);
443
444 let function_type_metadata =
445 create_subroutine_type(self, &get_function_signature(self, fn_abi));
446
447 let mut name = String::with_capacity(64);
448 type_names::push_item_name(tcx, def_id, false, &mut name);
449
450 let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
452
453 let generics = tcx.generics_of(enclosing_fn_def_id);
457 let args = instance.args.truncate_to(tcx, generics);
458
459 type_names::push_generic_args(
460 tcx,
461 tcx.normalize_erasing_regions(self.typing_env(), args),
462 &mut name,
463 );
464
465 let template_parameters = get_template_parameters(self, generics, args);
466
467 let linkage_name = &mangled_name_of_instance(self, instance).name;
468 let linkage_name = if &name == linkage_name { "" } else { linkage_name };
470
471 let scope_line = loc.line;
473
474 let mut flags = DIFlags::FlagPrototyped;
475
476 if fn_abi.ret.layout.is_uninhabited() {
477 flags |= DIFlags::FlagNoReturn;
478 }
479
480 let mut spflags = DISPFlags::SPFlagDefinition;
481 if is_node_local_to_unit(self, def_id) {
482 spflags |= DISPFlags::SPFlagLocalToUnit;
483 }
484 if self.sess().opts.optimize != config::OptLevel::No {
485 spflags |= DISPFlags::SPFlagOptimized;
486 }
487 if let Some((id, _)) = tcx.entry_fn(()) {
488 if id == def_id {
489 spflags |= DISPFlags::SPFlagMainSubprogram;
490 }
491 }
492
493 let decl = is_method.then(|| unsafe {
498 llvm::LLVMRustDIBuilderCreateMethod(
499 DIB(self),
500 containing_scope,
501 name.as_c_char_ptr(),
502 name.len(),
503 linkage_name.as_c_char_ptr(),
504 linkage_name.len(),
505 file_metadata,
506 loc.line,
507 function_type_metadata,
508 flags,
509 spflags & !DISPFlags::SPFlagDefinition,
510 template_parameters,
511 )
512 });
513
514 return unsafe {
515 llvm::LLVMRustDIBuilderCreateFunction(
516 DIB(self),
517 containing_scope,
518 name.as_c_char_ptr(),
519 name.len(),
520 linkage_name.as_c_char_ptr(),
521 linkage_name.len(),
522 file_metadata,
523 loc.line,
524 function_type_metadata,
525 scope_line,
526 flags,
527 spflags,
528 maybe_definition_llfn,
529 template_parameters,
530 decl,
531 )
532 };
533
534 fn get_function_signature<'ll, 'tcx>(
535 cx: &CodegenCx<'ll, 'tcx>,
536 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
537 ) -> Vec<Option<&'ll llvm::Metadata>> {
538 if cx.sess().opts.debuginfo != DebugInfo::Full {
539 return ::alloc::vec::Vec::new()vec![];
540 }
541
542 let mut signature = Vec::with_capacity(fn_abi.args.len() + 1);
543
544 signature.push(if fn_abi.ret.is_ignore() {
546 None
547 } else {
548 Some(type_di_node(cx, fn_abi.ret.layout.ty))
549 });
550
551 if cx.sess().target.is_like_msvc {
553 signature.extend(fn_abi.args.iter().map(|arg| {
564 let t = arg.layout.ty;
565 let t = match t.kind() {
566 ty::Array(ct, _)
567 if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() =>
568 {
569 Ty::new_imm_ptr(cx.tcx, *ct)
570 }
571 _ => t,
572 };
573 Some(type_di_node(cx, t))
574 }));
575 } else {
576 signature
577 .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty))));
578 }
579
580 signature
581 }
582
583 fn get_template_parameters<'ll, 'tcx>(
584 cx: &CodegenCx<'ll, 'tcx>,
585 generics: &ty::Generics,
586 args: GenericArgsRef<'tcx>,
587 ) -> &'ll DIArray {
588 if args.types().next().is_none() {
589 return create_DIArray(DIB(cx), &[]);
590 }
591
592 let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
594 let names = get_parameter_names(cx, generics);
595 iter::zip(args, names)
596 .filter_map(|(kind, name)| {
597 kind.as_type().map(|ty| {
598 let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
599 let actual_type_metadata = type_di_node(cx, actual_type);
600 Some(cx.create_template_type_parameter(
601 name.as_str(),
602 actual_type_metadata,
603 ))
604 })
605 })
606 .collect()
607 } else {
608 ::alloc::vec::Vec::new()vec![]
609 };
610
611 create_DIArray(DIB(cx), &template_params)
612 }
613
614 fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
615 let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
616 get_parameter_names(cx, cx.tcx.generics_of(def_id))
617 });
618 names.extend(generics.own_params.iter().map(|param| param.name));
619 names
620 }
621
622 fn get_containing_scope<'ll, 'tcx>(
625 cx: &CodegenCx<'ll, 'tcx>,
626 instance: Instance<'tcx>,
627 ) -> (&'ll DIScope, bool) {
628 if let Some(imp_def_id) = cx.tcx.inherent_impl_of_assoc(instance.def_id()) {
634 let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
635 instance.args,
636 cx.typing_env(),
637 cx.tcx.type_of(imp_def_id),
638 );
639
640 if let ty::Adt(def, ..) = impl_self_ty.kind()
643 && !def.is_box()
644 {
645 if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() {
647 return (type_di_node(cx, impl_self_ty), true);
648 } else {
649 return (namespace::item_namespace(cx, def.did()), false);
650 }
651 }
652 }
653
654 let scope = namespace::item_namespace(
655 cx,
656 DefId {
657 krate: instance.def_id().krate,
658 index: cx
659 .tcx
660 .def_key(instance.def_id())
661 .parent
662 .expect("get_containing_scope: missing parent?"),
663 },
664 );
665 (scope, false)
666 }
667 }
668
669 fn dbg_loc(
670 &self,
671 scope: &'ll DIScope,
672 inlined_at: Option<&'ll DILocation>,
673 span: Span,
674 ) -> &'ll DILocation {
675 let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc {
681 (0, 0)
682 } else {
683 let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
684 (line, col)
685 };
686
687 unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) }
688 }
689
690 fn create_vtable_debuginfo(
691 &self,
692 ty: Ty<'tcx>,
693 trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
694 vtable: Self::Value,
695 ) {
696 metadata::create_vtable_di_node(self, ty, trait_ref, vtable)
697 }
698
699 fn extend_scope_to_file(
700 &self,
701 scope_metadata: &'ll DIScope,
702 file: &rustc_span::SourceFile,
703 ) -> &'ll DILexicalBlock {
704 metadata::extend_scope_to_file(self, scope_metadata, file)
705 }
706
707 fn debuginfo_finalize(&self) {
708 finalize(self)
709 }
710
711 fn create_dbg_var(
714 &self,
715 variable_name: Symbol,
716 variable_type: Ty<'tcx>,
717 scope_metadata: &'ll DIScope,
718 variable_kind: VariableKind,
719 span: Span,
720 ) -> &'ll DIVariable {
721 let loc = self.lookup_debug_loc(span.lo());
722 let file_metadata = file_metadata(self, &loc.file);
723
724 let type_metadata = spanned_type_di_node(self, variable_type, span);
725
726 let align = self.align_of(variable_type);
727
728 let name = variable_name.as_str();
729
730 match variable_kind {
731 ArgumentVariable(arg_index) => unsafe {
732 llvm::LLVMDIBuilderCreateParameterVariable(
733 DIB(self),
734 scope_metadata,
735 name.as_ptr(),
736 name.len(),
737 arg_index as c_uint,
738 file_metadata,
739 loc.line,
740 type_metadata,
741 llvm::Bool::TRUE, DIFlags::FlagZero,
743 )
744 },
745 LocalVariable => unsafe {
746 llvm::LLVMDIBuilderCreateAutoVariable(
747 DIB(self),
748 scope_metadata,
749 name.as_ptr(),
750 name.len(),
751 file_metadata,
752 loc.line,
753 type_metadata,
754 llvm::Bool::TRUE, DIFlags::FlagZero,
756 align.bits() as u32,
757 )
758 },
759 }
760 }
761}