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 llmod: &'ll llvm::Module,
55 builder: DIBuilderBox<'ll>,
56 created_files: RefCell<UnordMap<Option<(StableSourceFileId, SourceFileHash)>, &'ll DIFile>>,
57
58 type_map: metadata::TypeMap<'ll, 'tcx>,
59 adt_stack: RefCell<Vec<(DefId, GenericArgsRef<'tcx>)>>,
60 namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
61 recursion_marker_type: OnceCell<&'ll DIType>,
62}
63
64impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
65 pub(crate) fn new(llmod: &'ll llvm::Module) -> Self {
66 {
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:66",
"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(66u32),
::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");
67 let builder = DIBuilderBox::new(llmod);
68 CodegenUnitDebugContext {
70 llmod,
71 builder,
72 created_files: Default::default(),
73 type_map: Default::default(),
74 adt_stack: Default::default(),
75 namespace_map: RefCell::new(Default::default()),
76 recursion_marker_type: OnceCell::new(),
77 }
78 }
79
80 pub(crate) fn finalize(&self, sess: &Session) {
81 unsafe { llvm::LLVMDIBuilderFinalize(self.builder.as_ref()) };
82
83 match sess.target.debuginfo_kind {
84 DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym => {
85 llvm::add_module_flag_u32(
92 self.llmod,
93 llvm::ModuleFlagMergeBehavior::Max,
98 "Dwarf Version",
99 sess.dwarf_version(),
100 );
101 }
102 DebuginfoKind::Pdb => {
103 llvm::add_module_flag_u32(
105 self.llmod,
106 llvm::ModuleFlagMergeBehavior::Warning,
107 "CodeView",
108 1,
109 );
110 }
111 }
112
113 llvm::add_module_flag_u32(
115 self.llmod,
116 llvm::ModuleFlagMergeBehavior::Warning,
117 "Debug Info Version",
118 unsafe { llvm::LLVMRustDebugMetadataVersion() },
119 );
120 }
121}
122
123pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
125 if let Some(dbg_cx) = &cx.dbg_cx {
126 {
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:126",
"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(126u32),
::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");
127
128 if gdb::needs_gdb_debug_scripts_section(cx) {
129 gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
134 }
135
136 dbg_cx.finalize(cx.sess());
137 }
138}
139
140impl<'ll> Builder<'_, 'll, '_> {
141 pub(crate) fn get_dbg_loc(&self) -> Option<&'ll DILocation> {
142 unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) }
143 }
144}
145
146impl<'ll, 'tcx> DebugInfoBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
147 fn dbg_var_addr(
150 &mut self,
151 dbg_var: &'ll DIVariable,
152 dbg_loc: &'ll DILocation,
153 variable_alloca: Self::Value,
154 direct_offset: Size,
155 indirect_offsets: &[Size],
156 fragment: &Option<Range<Size>>,
157 ) {
158 use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst};
159
160 let mut addr_ops = SmallVec::<[u64; 8]>::new();
162
163 if direct_offset.bytes() > 0 {
164 addr_ops.push(DW_OP_plus_uconst);
165 addr_ops.push(direct_offset.bytes());
166 }
167 for &offset in indirect_offsets {
168 addr_ops.push(DW_OP_deref);
169 if offset.bytes() > 0 {
170 addr_ops.push(DW_OP_plus_uconst);
171 addr_ops.push(offset.bytes());
172 }
173 }
174 if let Some(fragment) = fragment {
175 addr_ops.push(DW_OP_LLVM_fragment);
178 addr_ops.push(fragment.start.bits());
179 addr_ops.push((fragment.end - fragment.start).bits());
180 }
181
182 let di_builder = DIB(self.cx());
183 let addr_expr = di_builder.create_expression(&addr_ops);
184 unsafe {
185 llvm::LLVMDIBuilderInsertDeclareRecordAtEnd(
186 di_builder,
187 variable_alloca,
188 dbg_var,
189 addr_expr,
190 dbg_loc,
191 self.llbb(),
192 )
193 };
194 }
195
196 fn dbg_var_value(
197 &mut self,
198 dbg_var: &'ll DIVariable,
199 dbg_loc: &'ll DILocation,
200 value: Self::Value,
201 direct_offset: Size,
202 indirect_offsets: &[Size],
203 fragment: &Option<Range<Size>>,
204 ) {
205 use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst, DW_OP_stack_value};
206
207 let mut addr_ops = SmallVec::<[u64; 8]>::new();
209
210 if direct_offset.bytes() > 0 {
211 addr_ops.push(DW_OP_plus_uconst);
212 addr_ops.push(direct_offset.bytes() as u64);
213 addr_ops.push(DW_OP_stack_value);
214 }
215 for &offset in indirect_offsets {
216 addr_ops.push(DW_OP_deref);
217 if offset.bytes() > 0 {
218 addr_ops.push(DW_OP_plus_uconst);
219 addr_ops.push(offset.bytes() as u64);
220 }
221 }
222 if let Some(fragment) = fragment {
223 addr_ops.push(DW_OP_LLVM_fragment);
226 addr_ops.push(fragment.start.bits() as u64);
227 addr_ops.push((fragment.end - fragment.start).bits() as u64);
228 }
229
230 let di_builder = DIB(self.cx());
231 let addr_expr = unsafe {
232 llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len())
233 };
234 unsafe {
235 llvm::LLVMDIBuilderInsertDbgValueRecordAtEnd(
236 di_builder,
237 value,
238 dbg_var,
239 addr_expr,
240 dbg_loc,
241 self.llbb(),
242 );
243 }
244 }
245
246 fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) {
247 unsafe {
248 llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc);
249 }
250 }
251
252 fn clear_dbg_loc(&mut self) {
253 unsafe {
254 llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, ptr::null());
255 }
256 }
257
258 fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
259 gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
260 }
261
262 fn set_var_name(&mut self, value: &'ll Value, name: &str) {
263 if self.sess().fewer_names() {
265 return;
266 }
267
268 let param_or_inst = unsafe {
271 llvm::LLVMIsAArgument(value).is_some() || llvm::LLVMIsAInstruction(value).is_some()
272 };
273 if !param_or_inst {
274 return;
275 }
276
277 if llvm::get_value_name(value).is_empty() {
281 llvm::set_value_name(value, name.as_bytes());
282 }
283 }
284
285 fn with_move_annotation<R>(
294 &mut self,
295 instance: ty::Instance<'tcx>,
296 f: impl FnOnce(&mut Self) -> R,
297 ) -> R {
298 let saved_loc = self.get_dbg_loc();
300
301 let fn_abi = self
304 .cx()
305 .tcx
306 .fn_abi_of_instance(
307 self.cx().typing_env().as_query_input((instance, ty::List::empty())),
308 )
309 .unwrap();
310
311 let di_scope = self.cx().dbg_scope_fn(instance, fn_abi, None);
312
313 let fn_span = self.cx().tcx.def_span(instance.def_id());
318 let inlined_loc = self.cx().dbg_loc(di_scope, saved_loc, fn_span);
319
320 self.set_dbg_loc(inlined_loc);
322
323 let result = f(self);
325
326 if let Some(loc) = saved_loc {
328 self.set_dbg_loc(loc);
329 } else {
330 self.clear_dbg_loc();
331 }
332
333 result
334 }
335}
336
337struct DebugLoc {
342 file: Arc<SourceFile>,
344 line: u32,
346 col: u32,
348}
349
350impl<'ll> CodegenCx<'ll, '_> {
351 fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
356 let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
357 Ok(SourceFileAndLine { sf: file, line }) => {
358 let line_pos = file.lines()[line];
359
360 let line = (line + 1) as u32;
362 let col = (file.relative_position(pos) - line_pos).to_u32() + 1;
363
364 (file, line, col)
365 }
366 Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER),
367 };
368
369 if self.sess().target.is_like_msvc {
373 DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER }
374 } else {
375 DebugLoc { file, line, col }
376 }
377 }
378
379 fn create_template_type_parameter(
380 &self,
381 name: &str,
382 actual_type_metadata: &'ll DIType,
383 ) -> &'ll DITemplateTypeParameter {
384 unsafe {
385 llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
386 DIB(self),
387 None,
388 name.as_c_char_ptr(),
389 name.len(),
390 actual_type_metadata,
391 )
392 }
393 }
394}
395
396impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
397 fn dbg_create_lexical_block(&self, pos: BytePos, parent_scope: &'ll DIScope) -> &'ll DIScope {
398 let loc = self.lookup_debug_loc(pos);
399 let file_metadata = file_metadata(self, &loc.file);
400 unsafe {
401 llvm::LLVMDIBuilderCreateLexicalBlock(
402 DIB(self),
403 parent_scope,
404 file_metadata,
405 loc.line,
406 loc.col,
407 )
408 }
409 }
410
411 fn dbg_location_clone_with_discriminator(
412 &self,
413 loc: &'ll DILocation,
414 discriminator: u32,
415 ) -> Option<&'ll DILocation> {
416 unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, discriminator) }
417 }
418
419 fn dbg_scope_fn(
420 &self,
421 instance: Instance<'tcx>,
422 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
423 maybe_definition_llfn: Option<&'ll Value>,
424 ) -> &'ll DIScope {
425 let tcx = self.tcx;
426
427 let def_id = instance.def_id();
428 let (containing_scope, is_method) = get_containing_scope(self, instance);
429 let span = tcx.def_span(def_id);
430 let loc = self.lookup_debug_loc(span.lo());
431 let file_metadata = file_metadata(self, &loc.file);
432
433 let function_type_metadata =
434 create_subroutine_type(self, &get_function_signature(self, fn_abi));
435
436 let mut name = String::with_capacity(64);
437 type_names::push_item_name(tcx, def_id, false, &mut name);
438
439 let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
441
442 let generics = tcx.generics_of(enclosing_fn_def_id);
446 let args = instance.args.truncate_to(tcx, generics);
447
448 type_names::push_generic_args(
449 tcx,
450 tcx.normalize_erasing_regions(self.typing_env(), Unnormalized::new_wip(args)),
451 &mut name,
452 );
453
454 let template_parameters = get_template_parameters(self, generics, args);
455
456 let linkage_name = &mangled_name_of_instance(self, instance).name;
457 let linkage_name = if &name == linkage_name { "" } else { linkage_name };
459
460 let scope_line = loc.line;
462
463 let mut flags = DIFlags::FlagPrototyped;
464
465 if fn_abi.ret.layout.is_uninhabited() {
466 flags |= DIFlags::FlagNoReturn;
467 }
468
469 let mut spflags = DISPFlags::SPFlagDefinition;
470 if is_node_local_to_unit(self, def_id) {
471 spflags |= DISPFlags::SPFlagLocalToUnit;
472 }
473 if self.sess().opts.optimize != config::OptLevel::No {
474 spflags |= DISPFlags::SPFlagOptimized;
475 }
476 if let Some((id, _)) = tcx.entry_fn(()) {
477 if id == def_id {
478 spflags |= DISPFlags::SPFlagMainSubprogram;
479 }
480 }
481
482 let decl = is_method.then(|| unsafe {
487 llvm::LLVMRustDIBuilderCreateMethod(
488 DIB(self),
489 containing_scope,
490 name.as_c_char_ptr(),
491 name.len(),
492 linkage_name.as_c_char_ptr(),
493 linkage_name.len(),
494 file_metadata,
495 loc.line,
496 function_type_metadata,
497 flags,
498 spflags & !DISPFlags::SPFlagDefinition,
499 template_parameters,
500 )
501 });
502
503 return unsafe {
504 llvm::LLVMRustDIBuilderCreateFunction(
505 DIB(self),
506 containing_scope,
507 name.as_c_char_ptr(),
508 name.len(),
509 linkage_name.as_c_char_ptr(),
510 linkage_name.len(),
511 file_metadata,
512 loc.line,
513 function_type_metadata,
514 scope_line,
515 flags,
516 spflags,
517 maybe_definition_llfn,
518 template_parameters,
519 decl,
520 )
521 };
522
523 fn get_function_signature<'ll, 'tcx>(
524 cx: &CodegenCx<'ll, 'tcx>,
525 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
526 ) -> Vec<Option<&'ll llvm::Metadata>> {
527 if cx.sess().opts.debuginfo != DebugInfo::Full {
528 return ::alloc::vec::Vec::new()vec![];
529 }
530
531 let mut signature = Vec::with_capacity(fn_abi.args.len() + 1);
532
533 signature.push(if fn_abi.ret.is_ignore() {
535 None
536 } else {
537 Some(type_di_node(cx, fn_abi.ret.layout.ty))
538 });
539
540 if cx.sess().target.is_like_msvc {
542 signature.extend(fn_abi.args.iter().map(|arg| {
553 let t = arg.layout.ty;
554 let t = match t.kind() {
555 ty::Array(ct, _)
556 if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() =>
557 {
558 Ty::new_imm_ptr(cx.tcx, *ct)
559 }
560 _ => t,
561 };
562 Some(type_di_node(cx, t))
563 }));
564 } else {
565 signature
566 .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty))));
567 }
568
569 signature
570 }
571
572 fn get_template_parameters<'ll, 'tcx>(
573 cx: &CodegenCx<'ll, 'tcx>,
574 generics: &ty::Generics,
575 args: GenericArgsRef<'tcx>,
576 ) -> &'ll DIArray {
577 if args.types().next().is_none() {
578 return create_DIArray(DIB(cx), &[]);
579 }
580
581 let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
583 let names = get_parameter_names(cx, generics);
584 iter::zip(args, names)
585 .filter_map(|(kind, name)| {
586 kind.as_type().map(|ty| {
587 let actual_type = cx.tcx.normalize_erasing_regions(
588 cx.typing_env(),
589 Unnormalized::new_wip(ty),
590 );
591 let actual_type_metadata = type_di_node(cx, actual_type);
592 Some(cx.create_template_type_parameter(
593 name.as_str(),
594 actual_type_metadata,
595 ))
596 })
597 })
598 .collect()
599 } else {
600 ::alloc::vec::Vec::new()vec![]
601 };
602
603 create_DIArray(DIB(cx), &template_params)
604 }
605
606 fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
607 let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
608 get_parameter_names(cx, cx.tcx.generics_of(def_id))
609 });
610 names.extend(generics.own_params.iter().map(|param| param.name));
611 names
612 }
613
614 fn get_containing_scope<'ll, 'tcx>(
617 cx: &CodegenCx<'ll, 'tcx>,
618 instance: Instance<'tcx>,
619 ) -> (&'ll DIScope, bool) {
620 if let Some(imp_def_id) = cx.tcx.inherent_impl_of_assoc(instance.def_id()) {
626 let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
627 instance.args,
628 cx.typing_env(),
629 cx.tcx.type_of(imp_def_id),
630 );
631
632 if let ty::Adt(def, ..) = impl_self_ty.kind()
635 && !def.is_box()
636 {
637 if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() {
639 return (type_di_node(cx, impl_self_ty), true);
640 } else {
641 return (namespace::item_namespace(cx, def.did()), false);
642 }
643 }
644 }
645
646 let scope = namespace::item_namespace(
647 cx,
648 DefId {
649 krate: instance.def_id().krate,
650 index: cx
651 .tcx
652 .def_key(instance.def_id())
653 .parent
654 .expect("get_containing_scope: missing parent?"),
655 },
656 );
657 (scope, false)
658 }
659 }
660
661 fn dbg_loc(
662 &self,
663 scope: &'ll DIScope,
664 inlined_at: Option<&'ll DILocation>,
665 span: Span,
666 ) -> &'ll DILocation {
667 let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc {
673 (0, 0)
674 } else {
675 let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
676 (line, col)
677 };
678
679 unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) }
680 }
681
682 fn create_vtable_debuginfo(
683 &self,
684 ty: Ty<'tcx>,
685 trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
686 vtable: Self::Value,
687 ) {
688 metadata::create_vtable_di_node(self, ty, trait_ref, vtable)
689 }
690
691 fn extend_scope_to_file(
692 &self,
693 scope_metadata: &'ll DIScope,
694 file: &rustc_span::SourceFile,
695 ) -> &'ll DILexicalBlock {
696 metadata::extend_scope_to_file(self, scope_metadata, file)
697 }
698
699 fn debuginfo_finalize(&self) {
700 finalize(self)
701 }
702
703 fn create_dbg_var(
706 &self,
707 variable_name: Symbol,
708 variable_type: Ty<'tcx>,
709 scope_metadata: &'ll DIScope,
710 variable_kind: VariableKind,
711 span: Span,
712 ) -> &'ll DIVariable {
713 let loc = self.lookup_debug_loc(span.lo());
714 let file_metadata = file_metadata(self, &loc.file);
715
716 let type_metadata = spanned_type_di_node(self, variable_type, span);
717
718 let align = self.align_of(variable_type);
719
720 let name = variable_name.as_str();
721
722 match variable_kind {
723 ArgumentVariable(arg_index) => unsafe {
724 llvm::LLVMDIBuilderCreateParameterVariable(
725 DIB(self),
726 scope_metadata,
727 name.as_ptr(),
728 name.len(),
729 arg_index as c_uint,
730 file_metadata,
731 loc.line,
732 type_metadata,
733 llvm::Bool::TRUE, DIFlags::FlagZero,
735 )
736 },
737 LocalVariable => unsafe {
738 llvm::LLVMDIBuilderCreateAutoVariable(
739 DIB(self),
740 scope_metadata,
741 name.as_ptr(),
742 name.len(),
743 file_metadata,
744 loc.line,
745 type_metadata,
746 llvm::Bool::TRUE, DIFlags::FlagZero,
748 align.bits() as u32,
749 )
750 },
751 }
752 }
753}