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