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;
39use crate::llvm::debuginfo::{
40 DIArray, DIBuilderBox, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope,
41 DITemplateTypeParameter, DIType, DIVariable,
42};
43use crate::value::Value;
44
45mod create_scope_map;
46mod dwarf_const;
47mod gdb;
48pub(crate) mod metadata;
49mod namespace;
50mod utils;
51
52use self::create_scope_map::compute_mir_scopes;
53pub(crate) use self::metadata::build_global_var_di_node;
54
55#[allow(non_upper_case_globals)]
60const DW_TAG_auto_variable: c_uint = 0x100;
61#[allow(non_upper_case_globals)]
62const DW_TAG_arg_variable: c_uint = 0x101;
63
64pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> {
66 llmod: &'ll llvm::Module,
67 builder: DIBuilderBox<'ll>,
68 created_files: RefCell<UnordMap<Option<(StableSourceFileId, SourceFileHash)>, &'ll DIFile>>,
69
70 type_map: metadata::TypeMap<'ll, 'tcx>,
71 adt_stack: RefCell<Vec<(DefId, GenericArgsRef<'tcx>)>>,
72 namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
73 recursion_marker_type: OnceCell<&'ll DIType>,
74}
75
76impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
77 pub(crate) fn new(llmod: &'ll llvm::Module) -> Self {
78 debug!("CodegenUnitDebugContext::new");
79 let builder = DIBuilderBox::new(llmod);
80 CodegenUnitDebugContext {
82 llmod,
83 builder,
84 created_files: Default::default(),
85 type_map: Default::default(),
86 adt_stack: Default::default(),
87 namespace_map: RefCell::new(Default::default()),
88 recursion_marker_type: OnceCell::new(),
89 }
90 }
91
92 pub(crate) fn finalize(&self, sess: &Session) {
93 unsafe { llvm::LLVMDIBuilderFinalize(self.builder.as_ref()) };
94
95 match sess.target.debuginfo_kind {
96 DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym => {
97 llvm::add_module_flag_u32(
104 self.llmod,
105 llvm::ModuleFlagMergeBehavior::Max,
110 "Dwarf Version",
111 sess.dwarf_version(),
112 );
113 }
114 DebuginfoKind::Pdb => {
115 llvm::add_module_flag_u32(
117 self.llmod,
118 llvm::ModuleFlagMergeBehavior::Warning,
119 "CodeView",
120 1,
121 );
122 }
123 }
124
125 llvm::add_module_flag_u32(
127 self.llmod,
128 llvm::ModuleFlagMergeBehavior::Warning,
129 "Debug Info Version",
130 unsafe { llvm::LLVMRustDebugMetadataVersion() },
131 );
132 }
133}
134
135pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
137 if let Some(dbg_cx) = &cx.dbg_cx {
138 debug!("finalize");
139
140 if gdb::needs_gdb_debug_scripts_section(cx) {
141 gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
146 }
147
148 dbg_cx.finalize(cx.sess());
149 }
150}
151
152impl<'ll> Builder<'_, 'll, '_> {
153 pub(crate) fn get_dbg_loc(&self) -> Option<&'ll DILocation> {
154 unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) }
155 }
156}
157
158impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
159 fn dbg_var_addr(
162 &mut self,
163 dbg_var: &'ll DIVariable,
164 dbg_loc: &'ll DILocation,
165 variable_alloca: Self::Value,
166 direct_offset: Size,
167 indirect_offsets: &[Size],
168 fragment: Option<Range<Size>>,
169 ) {
170 use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst};
171
172 let mut addr_ops = SmallVec::<[u64; 8]>::new();
174
175 if direct_offset.bytes() > 0 {
176 addr_ops.push(DW_OP_plus_uconst);
177 addr_ops.push(direct_offset.bytes() as u64);
178 }
179 for &offset in indirect_offsets {
180 addr_ops.push(DW_OP_deref);
181 if offset.bytes() > 0 {
182 addr_ops.push(DW_OP_plus_uconst);
183 addr_ops.push(offset.bytes() as u64);
184 }
185 }
186 if let Some(fragment) = fragment {
187 addr_ops.push(DW_OP_LLVM_fragment);
190 addr_ops.push(fragment.start.bits() as u64);
191 addr_ops.push((fragment.end - fragment.start).bits() as u64);
192 }
193
194 unsafe {
195 llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
197 DIB(self.cx()),
198 variable_alloca,
199 dbg_var,
200 addr_ops.as_ptr(),
201 addr_ops.len() as c_uint,
202 dbg_loc,
203 self.llbb(),
204 );
205 }
206 }
207
208 fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) {
209 unsafe {
210 llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc);
211 }
212 }
213
214 fn clear_dbg_loc(&mut self) {
215 unsafe {
216 llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, ptr::null());
217 }
218 }
219
220 fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
221 gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
222 }
223
224 fn set_var_name(&mut self, value: &'ll Value, name: &str) {
225 if self.sess().fewer_names() {
227 return;
228 }
229
230 let param_or_inst = unsafe {
233 llvm::LLVMIsAArgument(value).is_some() || llvm::LLVMIsAInstruction(value).is_some()
234 };
235 if !param_or_inst {
236 return;
237 }
238
239 if llvm::get_value_name(value).is_empty() {
243 llvm::set_value_name(value, name.as_bytes());
244 }
245 }
246}
247
248struct DebugLoc {
253 file: Arc<SourceFile>,
255 line: u32,
257 col: u32,
259}
260
261impl<'ll> CodegenCx<'ll, '_> {
262 fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
267 let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
268 Ok(SourceFileAndLine { sf: file, line }) => {
269 let line_pos = file.lines()[line];
270
271 let line = (line + 1) as u32;
273 let col = (file.relative_position(pos) - line_pos).to_u32() + 1;
274
275 (file, line, col)
276 }
277 Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER),
278 };
279
280 if self.sess().target.is_like_msvc {
284 DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER }
285 } else {
286 DebugLoc { file, line, col }
287 }
288 }
289
290 fn create_template_type_parameter(
291 &self,
292 name: &str,
293 actual_type_metadata: &'ll DIType,
294 ) -> &'ll DITemplateTypeParameter {
295 unsafe {
296 llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
297 DIB(self),
298 None,
299 name.as_c_char_ptr(),
300 name.len(),
301 actual_type_metadata,
302 )
303 }
304 }
305}
306
307impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
308 fn create_function_debug_context(
309 &self,
310 instance: Instance<'tcx>,
311 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
312 llfn: &'ll Value,
313 mir: &mir::Body<'tcx>,
314 ) -> Option<FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>> {
315 if self.sess().opts.debuginfo == DebugInfo::None {
316 return None;
317 }
318
319 let empty_scope = DebugScope {
321 dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
322 inlined_at: None,
323 file_start_pos: BytePos(0),
324 file_end_pos: BytePos(0),
325 };
326 let mut fn_debug_context = FunctionDebugContext {
327 scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes),
328 inlined_function_scopes: Default::default(),
329 };
330
331 compute_mir_scopes(self, instance, mir, &mut fn_debug_context);
333
334 Some(fn_debug_context)
335 }
336
337 fn dbg_scope_fn(
338 &self,
339 instance: Instance<'tcx>,
340 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
341 maybe_definition_llfn: Option<&'ll Value>,
342 ) -> &'ll DIScope {
343 let tcx = self.tcx;
344
345 let def_id = instance.def_id();
346 let (containing_scope, is_method) = get_containing_scope(self, instance);
347 let span = tcx.def_span(def_id);
348 let loc = self.lookup_debug_loc(span.lo());
349 let file_metadata = file_metadata(self, &loc.file);
350
351 let function_type_metadata =
352 create_subroutine_type(self, get_function_signature(self, fn_abi));
353
354 let mut name = String::with_capacity(64);
355 type_names::push_item_name(tcx, def_id, false, &mut name);
356
357 let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
359
360 let generics = tcx.generics_of(enclosing_fn_def_id);
364 let args = instance.args.truncate_to(tcx, generics);
365
366 type_names::push_generic_params(
367 tcx,
368 tcx.normalize_erasing_regions(self.typing_env(), args),
369 &mut name,
370 );
371
372 let template_parameters = get_template_parameters(self, generics, args);
373
374 let linkage_name = &mangled_name_of_instance(self, instance).name;
375 let linkage_name = if &name == linkage_name { "" } else { linkage_name };
377
378 let scope_line = loc.line;
380
381 let mut flags = DIFlags::FlagPrototyped;
382
383 if fn_abi.ret.layout.is_uninhabited() {
384 flags |= DIFlags::FlagNoReturn;
385 }
386
387 let mut spflags = DISPFlags::SPFlagDefinition;
388 if is_node_local_to_unit(self, def_id) {
389 spflags |= DISPFlags::SPFlagLocalToUnit;
390 }
391 if self.sess().opts.optimize != config::OptLevel::No {
392 spflags |= DISPFlags::SPFlagOptimized;
393 }
394 if let Some((id, _)) = tcx.entry_fn(()) {
395 if id == def_id {
396 spflags |= DISPFlags::SPFlagMainSubprogram;
397 }
398 }
399
400 let decl = is_method.then(|| unsafe {
405 llvm::LLVMRustDIBuilderCreateMethod(
406 DIB(self),
407 containing_scope,
408 name.as_c_char_ptr(),
409 name.len(),
410 linkage_name.as_c_char_ptr(),
411 linkage_name.len(),
412 file_metadata,
413 loc.line,
414 function_type_metadata,
415 flags,
416 spflags & !DISPFlags::SPFlagDefinition,
417 template_parameters,
418 )
419 });
420
421 return unsafe {
422 llvm::LLVMRustDIBuilderCreateFunction(
423 DIB(self),
424 containing_scope,
425 name.as_c_char_ptr(),
426 name.len(),
427 linkage_name.as_c_char_ptr(),
428 linkage_name.len(),
429 file_metadata,
430 loc.line,
431 function_type_metadata,
432 scope_line,
433 flags,
434 spflags,
435 maybe_definition_llfn,
436 template_parameters,
437 decl,
438 )
439 };
440
441 fn get_function_signature<'ll, 'tcx>(
442 cx: &CodegenCx<'ll, 'tcx>,
443 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
444 ) -> &'ll DIArray {
445 if cx.sess().opts.debuginfo != DebugInfo::Full {
446 return create_DIArray(DIB(cx), &[]);
447 }
448
449 let mut signature = Vec::with_capacity(fn_abi.args.len() + 1);
450
451 signature.push(if fn_abi.ret.is_ignore() {
453 None
454 } else {
455 Some(type_di_node(cx, fn_abi.ret.layout.ty))
456 });
457
458 if cx.sess().target.is_like_msvc {
460 signature.extend(fn_abi.args.iter().map(|arg| {
471 let t = arg.layout.ty;
472 let t = match t.kind() {
473 ty::Array(ct, _)
474 if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() =>
475 {
476 Ty::new_imm_ptr(cx.tcx, *ct)
477 }
478 _ => t,
479 };
480 Some(type_di_node(cx, t))
481 }));
482 } else {
483 signature
484 .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty))));
485 }
486
487 create_DIArray(DIB(cx), &signature[..])
488 }
489
490 fn get_template_parameters<'ll, 'tcx>(
491 cx: &CodegenCx<'ll, 'tcx>,
492 generics: &ty::Generics,
493 args: GenericArgsRef<'tcx>,
494 ) -> &'ll DIArray {
495 if args.types().next().is_none() {
496 return create_DIArray(DIB(cx), &[]);
497 }
498
499 let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
501 let names = get_parameter_names(cx, generics);
502 iter::zip(args, names)
503 .filter_map(|(kind, name)| {
504 kind.as_type().map(|ty| {
505 let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
506 let actual_type_metadata = type_di_node(cx, actual_type);
507 Some(cx.create_template_type_parameter(
508 name.as_str(),
509 actual_type_metadata,
510 ))
511 })
512 })
513 .collect()
514 } else {
515 vec![]
516 };
517
518 create_DIArray(DIB(cx), &template_params)
519 }
520
521 fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
522 let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
523 get_parameter_names(cx, cx.tcx.generics_of(def_id))
524 });
525 names.extend(generics.own_params.iter().map(|param| param.name));
526 names
527 }
528
529 fn get_containing_scope<'ll, 'tcx>(
532 cx: &CodegenCx<'ll, 'tcx>,
533 instance: Instance<'tcx>,
534 ) -> (&'ll DIScope, bool) {
535 if let Some(imp_def_id) = cx.tcx.inherent_impl_of_assoc(instance.def_id()) {
541 let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
542 instance.args,
543 cx.typing_env(),
544 cx.tcx.type_of(imp_def_id),
545 );
546
547 if let ty::Adt(def, ..) = impl_self_ty.kind()
550 && !def.is_box()
551 {
552 if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param() {
554 return (type_di_node(cx, impl_self_ty), true);
555 } else {
556 return (namespace::item_namespace(cx, def.did()), false);
557 }
558 }
559 }
560
561 let scope = namespace::item_namespace(
562 cx,
563 DefId {
564 krate: instance.def_id().krate,
565 index: cx
566 .tcx
567 .def_key(instance.def_id())
568 .parent
569 .expect("get_containing_scope: missing parent?"),
570 },
571 );
572 (scope, false)
573 }
574 }
575
576 fn dbg_loc(
577 &self,
578 scope: &'ll DIScope,
579 inlined_at: Option<&'ll DILocation>,
580 span: Span,
581 ) -> &'ll DILocation {
582 let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc {
588 (0, 0)
589 } else {
590 let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
591 (line, col)
592 };
593
594 unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) }
595 }
596
597 fn create_vtable_debuginfo(
598 &self,
599 ty: Ty<'tcx>,
600 trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
601 vtable: Self::Value,
602 ) {
603 metadata::create_vtable_di_node(self, ty, trait_ref, vtable)
604 }
605
606 fn extend_scope_to_file(
607 &self,
608 scope_metadata: &'ll DIScope,
609 file: &rustc_span::SourceFile,
610 ) -> &'ll DILexicalBlock {
611 metadata::extend_scope_to_file(self, scope_metadata, file)
612 }
613
614 fn debuginfo_finalize(&self) {
615 finalize(self)
616 }
617
618 fn create_dbg_var(
621 &self,
622 variable_name: Symbol,
623 variable_type: Ty<'tcx>,
624 scope_metadata: &'ll DIScope,
625 variable_kind: VariableKind,
626 span: Span,
627 ) -> &'ll DIVariable {
628 let loc = self.lookup_debug_loc(span.lo());
629 let file_metadata = file_metadata(self, &loc.file);
630
631 let type_metadata = spanned_type_di_node(self, variable_type, span);
632
633 let (argument_index, dwarf_tag) = match variable_kind {
634 ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
635 LocalVariable => (0, DW_TAG_auto_variable),
636 };
637 let align = self.align_of(variable_type);
638
639 let name = variable_name.as_str();
640 unsafe {
641 llvm::LLVMRustDIBuilderCreateVariable(
642 DIB(self),
643 dwarf_tag,
644 scope_metadata,
645 name.as_c_char_ptr(),
646 name.len(),
647 file_metadata,
648 loc.line,
649 type_metadata,
650 true,
651 DIFlags::FlagZero,
652 argument_index,
653 align.bits() as u32,
654 )
655 }
656 }
657}