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::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::llvm::debuginfo::{
39 DIArray, DIBuilderBox, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope,
40 DITemplateTypeParameter, DIType, DIVariable,
41};
42use crate::llvm::{self, Value};
43
44mod create_scope_map;
45mod dwarf_const;
46mod gdb;
47pub(crate) mod metadata;
48mod namespace;
49mod utils;
50
51use self::create_scope_map::compute_mir_scopes;
52pub(crate) use self::metadata::build_global_var_di_node;
53
54pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> {
56 llmod: &'ll llvm::Module,
57 builder: DIBuilderBox<'ll>,
58 created_files: RefCell<UnordMap<Option<(StableSourceFileId, SourceFileHash)>, &'ll DIFile>>,
59
60 type_map: metadata::TypeMap<'ll, 'tcx>,
61 adt_stack: RefCell<Vec<(DefId, GenericArgsRef<'tcx>)>>,
62 namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
63 recursion_marker_type: OnceCell<&'ll DIType>,
64}
65
66impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
67 pub(crate) fn new(llmod: &'ll llvm::Module) -> Self {
68 debug!("CodegenUnitDebugContext::new");
69 let builder = DIBuilderBox::new(llmod);
70 CodegenUnitDebugContext {
72 llmod,
73 builder,
74 created_files: Default::default(),
75 type_map: Default::default(),
76 adt_stack: Default::default(),
77 namespace_map: RefCell::new(Default::default()),
78 recursion_marker_type: OnceCell::new(),
79 }
80 }
81
82 pub(crate) fn finalize(&self, sess: &Session) {
83 unsafe { llvm::LLVMDIBuilderFinalize(self.builder.as_ref()) };
84
85 match sess.target.debuginfo_kind {
86 DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym => {
87 llvm::add_module_flag_u32(
94 self.llmod,
95 llvm::ModuleFlagMergeBehavior::Max,
100 "Dwarf Version",
101 sess.dwarf_version(),
102 );
103 }
104 DebuginfoKind::Pdb => {
105 llvm::add_module_flag_u32(
107 self.llmod,
108 llvm::ModuleFlagMergeBehavior::Warning,
109 "CodeView",
110 1,
111 );
112 }
113 }
114
115 llvm::add_module_flag_u32(
117 self.llmod,
118 llvm::ModuleFlagMergeBehavior::Warning,
119 "Debug Info Version",
120 unsafe { llvm::LLVMRustDebugMetadataVersion() },
121 );
122 }
123}
124
125pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
127 if let Some(dbg_cx) = &cx.dbg_cx {
128 debug!("finalize");
129
130 if gdb::needs_gdb_debug_scripts_section(cx) {
131 gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
136 }
137
138 dbg_cx.finalize(cx.sess());
139 }
140}
141
142impl<'ll> Builder<'_, 'll, '_> {
143 pub(crate) fn get_dbg_loc(&self) -> Option<&'ll DILocation> {
144 unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) }
145 }
146}
147
148impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
149 fn dbg_var_addr(
152 &mut self,
153 dbg_var: &'ll DIVariable,
154 dbg_loc: &'ll DILocation,
155 variable_alloca: Self::Value,
156 direct_offset: Size,
157 indirect_offsets: &[Size],
158 fragment: &Option<Range<Size>>,
159 ) {
160 use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst};
161
162 let mut addr_ops = SmallVec::<[u64; 8]>::new();
164
165 if direct_offset.bytes() > 0 {
166 addr_ops.push(DW_OP_plus_uconst);
167 addr_ops.push(direct_offset.bytes());
168 }
169 for &offset in indirect_offsets {
170 addr_ops.push(DW_OP_deref);
171 if offset.bytes() > 0 {
172 addr_ops.push(DW_OP_plus_uconst);
173 addr_ops.push(offset.bytes());
174 }
175 }
176 if let Some(fragment) = fragment {
177 addr_ops.push(DW_OP_LLVM_fragment);
180 addr_ops.push(fragment.start.bits());
181 addr_ops.push((fragment.end - fragment.start).bits());
182 }
183
184 let di_builder = DIB(self.cx());
185 let addr_expr = unsafe {
186 llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len())
187 };
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
290struct DebugLoc {
295 file: Arc<SourceFile>,
297 line: u32,
299 col: u32,
301}
302
303impl<'ll> CodegenCx<'ll, '_> {
304 fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
309 let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
310 Ok(SourceFileAndLine { sf: file, line }) => {
311 let line_pos = file.lines()[line];
312
313 let line = (line + 1) as u32;
315 let col = (file.relative_position(pos) - line_pos).to_u32() + 1;
316
317 (file, line, col)
318 }
319 Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER),
320 };
321
322 if self.sess().target.is_like_msvc {
326 DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER }
327 } else {
328 DebugLoc { file, line, col }
329 }
330 }
331
332 fn create_template_type_parameter(
333 &self,
334 name: &str,
335 actual_type_metadata: &'ll DIType,
336 ) -> &'ll DITemplateTypeParameter {
337 unsafe {
338 llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
339 DIB(self),
340 None,
341 name.as_c_char_ptr(),
342 name.len(),
343 actual_type_metadata,
344 )
345 }
346 }
347}
348
349impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
350 fn create_function_debug_context(
351 &self,
352 instance: Instance<'tcx>,
353 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
354 llfn: &'ll Value,
355 mir: &mir::Body<'tcx>,
356 ) -> Option<FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>> {
357 if self.sess().opts.debuginfo == DebugInfo::None {
358 return None;
359 }
360
361 let empty_scope = DebugScope {
363 dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
364 inlined_at: None,
365 file_start_pos: BytePos(0),
366 file_end_pos: BytePos(0),
367 };
368 let mut fn_debug_context = FunctionDebugContext {
369 scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes),
370 inlined_function_scopes: Default::default(),
371 };
372
373 compute_mir_scopes(self, instance, mir, &mut fn_debug_context);
375
376 Some(fn_debug_context)
377 }
378
379 fn dbg_scope_fn(
380 &self,
381 instance: Instance<'tcx>,
382 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
383 maybe_definition_llfn: Option<&'ll Value>,
384 ) -> &'ll DIScope {
385 let tcx = self.tcx;
386
387 let def_id = instance.def_id();
388 let (containing_scope, is_method) = get_containing_scope(self, instance);
389 let span = tcx.def_span(def_id);
390 let loc = self.lookup_debug_loc(span.lo());
391 let file_metadata = file_metadata(self, &loc.file);
392
393 let function_type_metadata =
394 create_subroutine_type(self, &get_function_signature(self, fn_abi));
395
396 let mut name = String::with_capacity(64);
397 type_names::push_item_name(tcx, def_id, false, &mut name);
398
399 let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
401
402 let generics = tcx.generics_of(enclosing_fn_def_id);
406 let args = instance.args.truncate_to(tcx, generics);
407
408 type_names::push_generic_params(
409 tcx,
410 tcx.normalize_erasing_regions(self.typing_env(), args),
411 &mut name,
412 );
413
414 let template_parameters = get_template_parameters(self, generics, args);
415
416 let linkage_name = &mangled_name_of_instance(self, instance).name;
417 let linkage_name = if &name == linkage_name { "" } else { linkage_name };
419
420 let scope_line = loc.line;
422
423 let mut flags = DIFlags::FlagPrototyped;
424
425 if fn_abi.ret.layout.is_uninhabited() {
426 flags |= DIFlags::FlagNoReturn;
427 }
428
429 let mut spflags = DISPFlags::SPFlagDefinition;
430 if is_node_local_to_unit(self, def_id) {
431 spflags |= DISPFlags::SPFlagLocalToUnit;
432 }
433 if self.sess().opts.optimize != config::OptLevel::No {
434 spflags |= DISPFlags::SPFlagOptimized;
435 }
436 if let Some((id, _)) = tcx.entry_fn(()) {
437 if id == def_id {
438 spflags |= DISPFlags::SPFlagMainSubprogram;
439 }
440 }
441
442 let decl = is_method.then(|| unsafe {
447 llvm::LLVMRustDIBuilderCreateMethod(
448 DIB(self),
449 containing_scope,
450 name.as_c_char_ptr(),
451 name.len(),
452 linkage_name.as_c_char_ptr(),
453 linkage_name.len(),
454 file_metadata,
455 loc.line,
456 function_type_metadata,
457 flags,
458 spflags & !DISPFlags::SPFlagDefinition,
459 template_parameters,
460 )
461 });
462
463 return unsafe {
464 llvm::LLVMRustDIBuilderCreateFunction(
465 DIB(self),
466 containing_scope,
467 name.as_c_char_ptr(),
468 name.len(),
469 linkage_name.as_c_char_ptr(),
470 linkage_name.len(),
471 file_metadata,
472 loc.line,
473 function_type_metadata,
474 scope_line,
475 flags,
476 spflags,
477 maybe_definition_llfn,
478 template_parameters,
479 decl,
480 )
481 };
482
483 fn get_function_signature<'ll, 'tcx>(
484 cx: &CodegenCx<'ll, 'tcx>,
485 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
486 ) -> Vec<Option<&'ll llvm::Metadata>> {
487 if cx.sess().opts.debuginfo != DebugInfo::Full {
488 return vec![];
489 }
490
491 let mut signature = Vec::with_capacity(fn_abi.args.len() + 1);
492
493 signature.push(if fn_abi.ret.is_ignore() {
495 None
496 } else {
497 Some(type_di_node(cx, fn_abi.ret.layout.ty))
498 });
499
500 if cx.sess().target.is_like_msvc {
502 signature.extend(fn_abi.args.iter().map(|arg| {
513 let t = arg.layout.ty;
514 let t = match t.kind() {
515 ty::Array(ct, _)
516 if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() =>
517 {
518 Ty::new_imm_ptr(cx.tcx, *ct)
519 }
520 _ => t,
521 };
522 Some(type_di_node(cx, t))
523 }));
524 } else {
525 signature
526 .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty))));
527 }
528
529 signature
530 }
531
532 fn get_template_parameters<'ll, 'tcx>(
533 cx: &CodegenCx<'ll, 'tcx>,
534 generics: &ty::Generics,
535 args: GenericArgsRef<'tcx>,
536 ) -> &'ll DIArray {
537 if args.types().next().is_none() {
538 return create_DIArray(DIB(cx), &[]);
539 }
540
541 let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
543 let names = get_parameter_names(cx, generics);
544 iter::zip(args, names)
545 .filter_map(|(kind, name)| {
546 kind.as_type().map(|ty| {
547 let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
548 let actual_type_metadata = type_di_node(cx, actual_type);
549 Some(cx.create_template_type_parameter(
550 name.as_str(),
551 actual_type_metadata,
552 ))
553 })
554 })
555 .collect()
556 } else {
557 vec![]
558 };
559
560 create_DIArray(DIB(cx), &template_params)
561 }
562
563 fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
564 let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
565 get_parameter_names(cx, cx.tcx.generics_of(def_id))
566 });
567 names.extend(generics.own_params.iter().map(|param| param.name));
568 names
569 }
570
571 fn get_containing_scope<'ll, 'tcx>(
574 cx: &CodegenCx<'ll, 'tcx>,
575 instance: Instance<'tcx>,
576 ) -> (&'ll DIScope, bool) {
577 if let Some(imp_def_id) = cx.tcx.inherent_impl_of_assoc(instance.def_id()) {
583 let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
584 instance.args,
585 cx.typing_env(),
586 cx.tcx.type_of(imp_def_id),
587 );
588
589 if let ty::Adt(def, ..) = impl_self_ty.kind()
592 && !def.is_box()
593 {
594 if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() {
596 return (type_di_node(cx, impl_self_ty), true);
597 } else {
598 return (namespace::item_namespace(cx, def.did()), false);
599 }
600 }
601 }
602
603 let scope = namespace::item_namespace(
604 cx,
605 DefId {
606 krate: instance.def_id().krate,
607 index: cx
608 .tcx
609 .def_key(instance.def_id())
610 .parent
611 .expect("get_containing_scope: missing parent?"),
612 },
613 );
614 (scope, false)
615 }
616 }
617
618 fn dbg_loc(
619 &self,
620 scope: &'ll DIScope,
621 inlined_at: Option<&'ll DILocation>,
622 span: Span,
623 ) -> &'ll DILocation {
624 let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc {
630 (0, 0)
631 } else {
632 let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
633 (line, col)
634 };
635
636 unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) }
637 }
638
639 fn create_vtable_debuginfo(
640 &self,
641 ty: Ty<'tcx>,
642 trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
643 vtable: Self::Value,
644 ) {
645 metadata::create_vtable_di_node(self, ty, trait_ref, vtable)
646 }
647
648 fn extend_scope_to_file(
649 &self,
650 scope_metadata: &'ll DIScope,
651 file: &rustc_span::SourceFile,
652 ) -> &'ll DILexicalBlock {
653 metadata::extend_scope_to_file(self, scope_metadata, file)
654 }
655
656 fn debuginfo_finalize(&self) {
657 finalize(self)
658 }
659
660 fn create_dbg_var(
663 &self,
664 variable_name: Symbol,
665 variable_type: Ty<'tcx>,
666 scope_metadata: &'ll DIScope,
667 variable_kind: VariableKind,
668 span: Span,
669 ) -> &'ll DIVariable {
670 let loc = self.lookup_debug_loc(span.lo());
671 let file_metadata = file_metadata(self, &loc.file);
672
673 let type_metadata = spanned_type_di_node(self, variable_type, span);
674
675 let align = self.align_of(variable_type);
676
677 let name = variable_name.as_str();
678
679 match variable_kind {
680 ArgumentVariable(arg_index) => unsafe {
681 llvm::LLVMDIBuilderCreateParameterVariable(
682 DIB(self),
683 scope_metadata,
684 name.as_ptr(),
685 name.len(),
686 arg_index as c_uint,
687 file_metadata,
688 loc.line,
689 type_metadata,
690 llvm::Bool::TRUE, DIFlags::FlagZero,
692 )
693 },
694 LocalVariable => unsafe {
695 llvm::LLVMDIBuilderCreateAutoVariable(
696 DIB(self),
697 scope_metadata,
698 name.as_ptr(),
699 name.len(),
700 file_metadata,
701 loc.line,
702 type_metadata,
703 llvm::Bool::TRUE, DIFlags::FlagZero,
705 align.bits() as u32,
706 )
707 },
708 }
709 }
710}