rustc_codegen_llvm/debuginfo/
mod.rs1#![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> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
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
289struct DebugLoc {
294 file: Arc<SourceFile>,
296 line: u32,
298 col: u32,
300}
301
302impl<'ll> CodegenCx<'ll, '_> {
303 fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
308 let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
309 Ok(SourceFileAndLine { sf: file, line }) => {
310 let line_pos = file.lines()[line];
311
312 let line = (line + 1) as u32;
314 let col = (file.relative_position(pos) - line_pos).to_u32() + 1;
315
316 (file, line, col)
317 }
318 Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER),
319 };
320
321 if self.sess().target.is_like_msvc {
325 DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER }
326 } else {
327 DebugLoc { file, line, col }
328 }
329 }
330
331 fn create_template_type_parameter(
332 &self,
333 name: &str,
334 actual_type_metadata: &'ll DIType,
335 ) -> &'ll DITemplateTypeParameter {
336 unsafe {
337 llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
338 DIB(self),
339 None,
340 name.as_c_char_ptr(),
341 name.len(),
342 actual_type_metadata,
343 )
344 }
345 }
346}
347
348impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
349 fn create_function_debug_context(
350 &self,
351 instance: Instance<'tcx>,
352 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
353 llfn: &'ll Value,
354 mir: &mir::Body<'tcx>,
355 ) -> Option<FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>> {
356 if self.sess().opts.debuginfo == DebugInfo::None {
357 return None;
358 }
359
360 let empty_scope = DebugScope {
362 dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
363 inlined_at: None,
364 file_start_pos: BytePos(0),
365 file_end_pos: BytePos(0),
366 };
367 let mut fn_debug_context = FunctionDebugContext {
368 scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes),
369 inlined_function_scopes: Default::default(),
370 };
371
372 compute_mir_scopes(self, instance, mir, &mut fn_debug_context);
374
375 Some(fn_debug_context)
376 }
377
378 fn dbg_scope_fn(
379 &self,
380 instance: Instance<'tcx>,
381 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
382 maybe_definition_llfn: Option<&'ll Value>,
383 ) -> &'ll DIScope {
384 let tcx = self.tcx;
385
386 let def_id = instance.def_id();
387 let (containing_scope, is_method) = get_containing_scope(self, instance);
388 let span = tcx.def_span(def_id);
389 let loc = self.lookup_debug_loc(span.lo());
390 let file_metadata = file_metadata(self, &loc.file);
391
392 let function_type_metadata =
393 create_subroutine_type(self, &get_function_signature(self, fn_abi));
394
395 let mut name = String::with_capacity(64);
396 type_names::push_item_name(tcx, def_id, false, &mut name);
397
398 let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
400
401 let generics = tcx.generics_of(enclosing_fn_def_id);
405 let args = instance.args.truncate_to(tcx, generics);
406
407 type_names::push_generic_params(
408 tcx,
409 tcx.normalize_erasing_regions(self.typing_env(), args),
410 &mut name,
411 );
412
413 let template_parameters = get_template_parameters(self, generics, args);
414
415 let linkage_name = &mangled_name_of_instance(self, instance).name;
416 let linkage_name = if &name == linkage_name { "" } else { linkage_name };
418
419 let scope_line = loc.line;
421
422 let mut flags = DIFlags::FlagPrototyped;
423
424 if fn_abi.ret.layout.is_uninhabited() {
425 flags |= DIFlags::FlagNoReturn;
426 }
427
428 let mut spflags = DISPFlags::SPFlagDefinition;
429 if is_node_local_to_unit(self, def_id) {
430 spflags |= DISPFlags::SPFlagLocalToUnit;
431 }
432 if self.sess().opts.optimize != config::OptLevel::No {
433 spflags |= DISPFlags::SPFlagOptimized;
434 }
435 if let Some((id, _)) = tcx.entry_fn(()) {
436 if id == def_id {
437 spflags |= DISPFlags::SPFlagMainSubprogram;
438 }
439 }
440
441 let decl = is_method.then(|| unsafe {
446 llvm::LLVMRustDIBuilderCreateMethod(
447 DIB(self),
448 containing_scope,
449 name.as_c_char_ptr(),
450 name.len(),
451 linkage_name.as_c_char_ptr(),
452 linkage_name.len(),
453 file_metadata,
454 loc.line,
455 function_type_metadata,
456 flags,
457 spflags & !DISPFlags::SPFlagDefinition,
458 template_parameters,
459 )
460 });
461
462 return unsafe {
463 llvm::LLVMRustDIBuilderCreateFunction(
464 DIB(self),
465 containing_scope,
466 name.as_c_char_ptr(),
467 name.len(),
468 linkage_name.as_c_char_ptr(),
469 linkage_name.len(),
470 file_metadata,
471 loc.line,
472 function_type_metadata,
473 scope_line,
474 flags,
475 spflags,
476 maybe_definition_llfn,
477 template_parameters,
478 decl,
479 )
480 };
481
482 fn get_function_signature<'ll, 'tcx>(
483 cx: &CodegenCx<'ll, 'tcx>,
484 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
485 ) -> Vec<Option<&'ll llvm::Metadata>> {
486 if cx.sess().opts.debuginfo != DebugInfo::Full {
487 return vec![];
488 }
489
490 let mut signature = Vec::with_capacity(fn_abi.args.len() + 1);
491
492 signature.push(if fn_abi.ret.is_ignore() {
494 None
495 } else {
496 Some(type_di_node(cx, fn_abi.ret.layout.ty))
497 });
498
499 if cx.sess().target.is_like_msvc {
501 signature.extend(fn_abi.args.iter().map(|arg| {
512 let t = arg.layout.ty;
513 let t = match t.kind() {
514 ty::Array(ct, _)
515 if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() =>
516 {
517 Ty::new_imm_ptr(cx.tcx, *ct)
518 }
519 _ => t,
520 };
521 Some(type_di_node(cx, t))
522 }));
523 } else {
524 signature
525 .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty))));
526 }
527
528 signature
529 }
530
531 fn get_template_parameters<'ll, 'tcx>(
532 cx: &CodegenCx<'ll, 'tcx>,
533 generics: &ty::Generics,
534 args: GenericArgsRef<'tcx>,
535 ) -> &'ll DIArray {
536 if args.types().next().is_none() {
537 return create_DIArray(DIB(cx), &[]);
538 }
539
540 let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
542 let names = get_parameter_names(cx, generics);
543 iter::zip(args, names)
544 .filter_map(|(kind, name)| {
545 kind.as_type().map(|ty| {
546 let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
547 let actual_type_metadata = type_di_node(cx, actual_type);
548 Some(cx.create_template_type_parameter(
549 name.as_str(),
550 actual_type_metadata,
551 ))
552 })
553 })
554 .collect()
555 } else {
556 vec![]
557 };
558
559 create_DIArray(DIB(cx), &template_params)
560 }
561
562 fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
563 let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
564 get_parameter_names(cx, cx.tcx.generics_of(def_id))
565 });
566 names.extend(generics.own_params.iter().map(|param| param.name));
567 names
568 }
569
570 fn get_containing_scope<'ll, 'tcx>(
573 cx: &CodegenCx<'ll, 'tcx>,
574 instance: Instance<'tcx>,
575 ) -> (&'ll DIScope, bool) {
576 if let Some(imp_def_id) = cx.tcx.inherent_impl_of_assoc(instance.def_id()) {
582 let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
583 instance.args,
584 cx.typing_env(),
585 cx.tcx.type_of(imp_def_id),
586 );
587
588 if let ty::Adt(def, ..) = impl_self_ty.kind()
591 && !def.is_box()
592 {
593 if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() {
595 return (type_di_node(cx, impl_self_ty), true);
596 } else {
597 return (namespace::item_namespace(cx, def.did()), false);
598 }
599 }
600 }
601
602 let scope = namespace::item_namespace(
603 cx,
604 DefId {
605 krate: instance.def_id().krate,
606 index: cx
607 .tcx
608 .def_key(instance.def_id())
609 .parent
610 .expect("get_containing_scope: missing parent?"),
611 },
612 );
613 (scope, false)
614 }
615 }
616
617 fn dbg_loc(
618 &self,
619 scope: &'ll DIScope,
620 inlined_at: Option<&'ll DILocation>,
621 span: Span,
622 ) -> &'ll DILocation {
623 let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc {
629 (0, 0)
630 } else {
631 let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
632 (line, col)
633 };
634
635 unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) }
636 }
637
638 fn create_vtable_debuginfo(
639 &self,
640 ty: Ty<'tcx>,
641 trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
642 vtable: Self::Value,
643 ) {
644 metadata::create_vtable_di_node(self, ty, trait_ref, vtable)
645 }
646
647 fn extend_scope_to_file(
648 &self,
649 scope_metadata: &'ll DIScope,
650 file: &rustc_span::SourceFile,
651 ) -> &'ll DILexicalBlock {
652 metadata::extend_scope_to_file(self, scope_metadata, file)
653 }
654
655 fn debuginfo_finalize(&self) {
656 finalize(self)
657 }
658
659 fn create_dbg_var(
662 &self,
663 variable_name: Symbol,
664 variable_type: Ty<'tcx>,
665 scope_metadata: &'ll DIScope,
666 variable_kind: VariableKind,
667 span: Span,
668 ) -> &'ll DIVariable {
669 let loc = self.lookup_debug_loc(span.lo());
670 let file_metadata = file_metadata(self, &loc.file);
671
672 let type_metadata = spanned_type_di_node(self, variable_type, span);
673
674 let align = self.align_of(variable_type);
675
676 let name = variable_name.as_str();
677
678 match variable_kind {
679 ArgumentVariable(arg_index) => unsafe {
680 llvm::LLVMDIBuilderCreateParameterVariable(
681 DIB(self),
682 scope_metadata,
683 name.as_ptr(),
684 name.len(),
685 arg_index as c_uint,
686 file_metadata,
687 loc.line,
688 type_metadata,
689 llvm::Bool::TRUE, DIFlags::FlagZero,
691 )
692 },
693 LocalVariable => unsafe {
694 llvm::LLVMDIBuilderCreateAutoVariable(
695 DIB(self),
696 scope_metadata,
697 name.as_ptr(),
698 name.len(),
699 file_metadata,
700 loc.line,
701 type_metadata,
702 llvm::Bool::TRUE, DIFlags::FlagZero,
704 align.bits() as u32,
705 )
706 },
707 }
708 }
709}