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