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::{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, Unnormalized};
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(), Unnormalized::new_wip(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(
599 cx.typing_env(),
600 Unnormalized::new_wip(ty),
601 );
602 let actual_type_metadata = type_di_node(cx, actual_type);
603 Some(cx.create_template_type_parameter(
604 name.as_str(),
605 actual_type_metadata,
606 ))
607 })
608 })
609 .collect()
610 } else {
611 ::alloc::vec::Vec::new()vec![]
612 };
613
614 create_DIArray(DIB(cx), &template_params)
615 }
616
617 fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
618 let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
619 get_parameter_names(cx, cx.tcx.generics_of(def_id))
620 });
621 names.extend(generics.own_params.iter().map(|param| param.name));
622 names
623 }
624
625 fn get_containing_scope<'ll, 'tcx>(
628 cx: &CodegenCx<'ll, 'tcx>,
629 instance: Instance<'tcx>,
630 ) -> (&'ll DIScope, bool) {
631 if let Some(imp_def_id) = cx.tcx.inherent_impl_of_assoc(instance.def_id()) {
637 let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
638 instance.args,
639 cx.typing_env(),
640 cx.tcx.type_of(imp_def_id),
641 );
642
643 if let ty::Adt(def, ..) = impl_self_ty.kind()
646 && !def.is_box()
647 {
648 if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() {
650 return (type_di_node(cx, impl_self_ty), true);
651 } else {
652 return (namespace::item_namespace(cx, def.did()), false);
653 }
654 }
655 }
656
657 let scope = namespace::item_namespace(
658 cx,
659 DefId {
660 krate: instance.def_id().krate,
661 index: cx
662 .tcx
663 .def_key(instance.def_id())
664 .parent
665 .expect("get_containing_scope: missing parent?"),
666 },
667 );
668 (scope, false)
669 }
670 }
671
672 fn dbg_loc(
673 &self,
674 scope: &'ll DIScope,
675 inlined_at: Option<&'ll DILocation>,
676 span: Span,
677 ) -> &'ll DILocation {
678 let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc {
684 (0, 0)
685 } else {
686 let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
687 (line, col)
688 };
689
690 unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) }
691 }
692
693 fn create_vtable_debuginfo(
694 &self,
695 ty: Ty<'tcx>,
696 trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
697 vtable: Self::Value,
698 ) {
699 metadata::create_vtable_di_node(self, ty, trait_ref, vtable)
700 }
701
702 fn extend_scope_to_file(
703 &self,
704 scope_metadata: &'ll DIScope,
705 file: &rustc_span::SourceFile,
706 ) -> &'ll DILexicalBlock {
707 metadata::extend_scope_to_file(self, scope_metadata, file)
708 }
709
710 fn debuginfo_finalize(&self) {
711 finalize(self)
712 }
713
714 fn create_dbg_var(
717 &self,
718 variable_name: Symbol,
719 variable_type: Ty<'tcx>,
720 scope_metadata: &'ll DIScope,
721 variable_kind: VariableKind,
722 span: Span,
723 ) -> &'ll DIVariable {
724 let loc = self.lookup_debug_loc(span.lo());
725 let file_metadata = file_metadata(self, &loc.file);
726
727 let type_metadata = spanned_type_di_node(self, variable_type, span);
728
729 let align = self.align_of(variable_type);
730
731 let name = variable_name.as_str();
732
733 match variable_kind {
734 ArgumentVariable(arg_index) => unsafe {
735 llvm::LLVMDIBuilderCreateParameterVariable(
736 DIB(self),
737 scope_metadata,
738 name.as_ptr(),
739 name.len(),
740 arg_index as c_uint,
741 file_metadata,
742 loc.line,
743 type_metadata,
744 llvm::Bool::TRUE, DIFlags::FlagZero,
746 )
747 },
748 LocalVariable => unsafe {
749 llvm::LLVMDIBuilderCreateAutoVariable(
750 DIB(self),
751 scope_metadata,
752 name.as_ptr(),
753 name.len(),
754 file_metadata,
755 loc.line,
756 type_metadata,
757 llvm::Bool::TRUE, DIFlags::FlagZero,
759 align.bits() as u32,
760 )
761 },
762 }
763 }
764}