rustc_codegen_llvm/debuginfo/
mod.rs
1#![doc = include_str!("doc.md")]
2
3use std::cell::{OnceCell, RefCell};
4use std::ops::Range;
5use std::ptr;
6use std::sync::Arc;
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 namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
70 recursion_marker_type: OnceCell<&'ll DIType>,
71}
72
73impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
74 pub(crate) fn new(llmod: &'ll llvm::Module) -> Self {
75 debug!("CodegenUnitDebugContext::new");
76 let builder = DIBuilderBox::new(llmod);
77 CodegenUnitDebugContext {
79 llmod,
80 builder,
81 created_files: Default::default(),
82 type_map: Default::default(),
83 namespace_map: RefCell::new(Default::default()),
84 recursion_marker_type: OnceCell::new(),
85 }
86 }
87
88 pub(crate) fn finalize(&self, sess: &Session) {
89 unsafe { llvm::LLVMDIBuilderFinalize(self.builder.as_ref()) };
90
91 match sess.target.debuginfo_kind {
92 DebuginfoKind::Dwarf | DebuginfoKind::DwarfDsym => {
93 llvm::add_module_flag_u32(
100 self.llmod,
101 llvm::ModuleFlagMergeBehavior::Max,
106 "Dwarf Version",
107 sess.dwarf_version(),
108 );
109 }
110 DebuginfoKind::Pdb => {
111 llvm::add_module_flag_u32(
113 self.llmod,
114 llvm::ModuleFlagMergeBehavior::Warning,
115 "CodeView",
116 1,
117 );
118 }
119 }
120
121 llvm::add_module_flag_u32(
123 self.llmod,
124 llvm::ModuleFlagMergeBehavior::Warning,
125 "Debug Info Version",
126 unsafe { llvm::LLVMRustDebugMetadataVersion() },
127 );
128 }
129}
130
131pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
133 if let Some(dbg_cx) = &cx.dbg_cx {
134 debug!("finalize");
135
136 if gdb::needs_gdb_debug_scripts_section(cx) {
137 gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
142 }
143
144 dbg_cx.finalize(cx.sess());
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() as u64);
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() as u64);
174 }
175 }
176 if let Some(fragment) = fragment {
177 addr_ops.push(DW_OP_LLVM_fragment);
180 addr_ops.push(fragment.start.bits() as u64);
181 addr_ops.push((fragment.end - fragment.start).bits() as u64);
182 }
183
184 unsafe {
185 llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
187 DIB(self.cx()),
188 variable_alloca,
189 dbg_var,
190 addr_ops.as_ptr(),
191 addr_ops.len() as c_uint,
192 dbg_loc,
193 self.llbb(),
194 );
195 }
196 }
197
198 fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) {
199 unsafe {
200 llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc);
201 }
202 }
203
204 fn clear_dbg_loc(&mut self) {
205 unsafe {
206 llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, ptr::null());
207 }
208 }
209
210 fn get_dbg_loc(&self) -> Option<&'ll DILocation> {
211 unsafe { llvm::LLVMGetCurrentDebugLocation2(self.llbuilder) }
212 }
213
214 fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
215 gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
216 }
217
218 fn set_var_name(&mut self, value: &'ll Value, name: &str) {
219 if self.sess().fewer_names() {
221 return;
222 }
223
224 let param_or_inst = unsafe {
227 llvm::LLVMIsAArgument(value).is_some() || llvm::LLVMIsAInstruction(value).is_some()
228 };
229 if !param_or_inst {
230 return;
231 }
232
233 if llvm::get_value_name(value).is_empty() {
237 llvm::set_value_name(value, name.as_bytes());
238 }
239 }
240}
241
242struct DebugLoc {
247 file: Arc<SourceFile>,
249 line: u32,
251 col: u32,
253}
254
255impl<'ll> CodegenCx<'ll, '_> {
256 fn lookup_debug_loc(&self, pos: BytePos) -> DebugLoc {
261 let (file, line, col) = match self.sess().source_map().lookup_line(pos) {
262 Ok(SourceFileAndLine { sf: file, line }) => {
263 let line_pos = file.lines()[line];
264
265 let line = (line + 1) as u32;
267 let col = (file.relative_position(pos) - line_pos).to_u32() + 1;
268
269 (file, line, col)
270 }
271 Err(file) => (file, UNKNOWN_LINE_NUMBER, UNKNOWN_COLUMN_NUMBER),
272 };
273
274 if self.sess().target.is_like_msvc {
278 DebugLoc { file, line, col: UNKNOWN_COLUMN_NUMBER }
279 } else {
280 DebugLoc { file, line, col }
281 }
282 }
283
284 fn create_template_type_parameter(
285 &self,
286 name: &str,
287 actual_type_metadata: &'ll DIType,
288 ) -> &'ll DITemplateTypeParameter {
289 unsafe {
290 llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
291 DIB(self),
292 None,
293 name.as_c_char_ptr(),
294 name.len(),
295 actual_type_metadata,
296 )
297 }
298 }
299}
300
301impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
302 fn create_function_debug_context(
303 &self,
304 instance: Instance<'tcx>,
305 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
306 llfn: &'ll Value,
307 mir: &mir::Body<'tcx>,
308 ) -> Option<FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>> {
309 if self.sess().opts.debuginfo == DebugInfo::None {
310 return None;
311 }
312
313 let empty_scope = DebugScope {
315 dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
316 inlined_at: None,
317 file_start_pos: BytePos(0),
318 file_end_pos: BytePos(0),
319 };
320 let mut fn_debug_context = FunctionDebugContext {
321 scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes),
322 inlined_function_scopes: Default::default(),
323 };
324
325 compute_mir_scopes(self, instance, mir, &mut fn_debug_context);
327
328 Some(fn_debug_context)
329 }
330
331 fn dbg_scope_fn(
332 &self,
333 instance: Instance<'tcx>,
334 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
335 maybe_definition_llfn: Option<&'ll Value>,
336 ) -> &'ll DIScope {
337 let tcx = self.tcx;
338
339 let def_id = instance.def_id();
340 let (containing_scope, is_method) = get_containing_scope(self, instance);
341 let span = tcx.def_span(def_id);
342 let loc = self.lookup_debug_loc(span.lo());
343 let file_metadata = file_metadata(self, &loc.file);
344
345 let function_type_metadata =
346 create_subroutine_type(self, get_function_signature(self, fn_abi));
347
348 let mut name = String::with_capacity(64);
349 type_names::push_item_name(tcx, def_id, false, &mut name);
350
351 let enclosing_fn_def_id = tcx.typeck_root_def_id(def_id);
353
354 let generics = tcx.generics_of(enclosing_fn_def_id);
358 let args = instance.args.truncate_to(tcx, generics);
359
360 type_names::push_generic_params(
361 tcx,
362 tcx.normalize_erasing_regions(self.typing_env(), args),
363 &mut name,
364 );
365
366 let template_parameters = get_template_parameters(self, generics, args);
367
368 let linkage_name = &mangled_name_of_instance(self, instance).name;
369 let linkage_name = if &name == linkage_name { "" } else { linkage_name };
371
372 let scope_line = loc.line;
374
375 let mut flags = DIFlags::FlagPrototyped;
376
377 if fn_abi.ret.layout.is_uninhabited() {
378 flags |= DIFlags::FlagNoReturn;
379 }
380
381 let mut spflags = DISPFlags::SPFlagDefinition;
382 if is_node_local_to_unit(self, def_id) {
383 spflags |= DISPFlags::SPFlagLocalToUnit;
384 }
385 if self.sess().opts.optimize != config::OptLevel::No {
386 spflags |= DISPFlags::SPFlagOptimized;
387 }
388 if let Some((id, _)) = tcx.entry_fn(()) {
389 if id == def_id {
390 spflags |= DISPFlags::SPFlagMainSubprogram;
391 }
392 }
393
394 let decl = is_method.then(|| unsafe {
399 llvm::LLVMRustDIBuilderCreateMethod(
400 DIB(self),
401 containing_scope,
402 name.as_c_char_ptr(),
403 name.len(),
404 linkage_name.as_c_char_ptr(),
405 linkage_name.len(),
406 file_metadata,
407 loc.line,
408 function_type_metadata,
409 flags,
410 spflags & !DISPFlags::SPFlagDefinition,
411 template_parameters,
412 )
413 });
414
415 return unsafe {
416 llvm::LLVMRustDIBuilderCreateFunction(
417 DIB(self),
418 containing_scope,
419 name.as_c_char_ptr(),
420 name.len(),
421 linkage_name.as_c_char_ptr(),
422 linkage_name.len(),
423 file_metadata,
424 loc.line,
425 function_type_metadata,
426 scope_line,
427 flags,
428 spflags,
429 maybe_definition_llfn,
430 template_parameters,
431 decl,
432 )
433 };
434
435 fn get_function_signature<'ll, 'tcx>(
436 cx: &CodegenCx<'ll, 'tcx>,
437 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
438 ) -> &'ll DIArray {
439 if cx.sess().opts.debuginfo != DebugInfo::Full {
440 return create_DIArray(DIB(cx), &[]);
441 }
442
443 let mut signature = Vec::with_capacity(fn_abi.args.len() + 1);
444
445 signature.push(if fn_abi.ret.is_ignore() {
447 None
448 } else {
449 Some(type_di_node(cx, fn_abi.ret.layout.ty))
450 });
451
452 if cx.sess().target.is_like_msvc {
454 signature.extend(fn_abi.args.iter().map(|arg| {
465 let t = arg.layout.ty;
466 let t = match t.kind() {
467 ty::Array(ct, _)
468 if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() =>
469 {
470 Ty::new_imm_ptr(cx.tcx, *ct)
471 }
472 _ => t,
473 };
474 Some(type_di_node(cx, t))
475 }));
476 } else {
477 signature
478 .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty))));
479 }
480
481 create_DIArray(DIB(cx), &signature[..])
482 }
483
484 fn get_template_parameters<'ll, 'tcx>(
485 cx: &CodegenCx<'ll, 'tcx>,
486 generics: &ty::Generics,
487 args: GenericArgsRef<'tcx>,
488 ) -> &'ll DIArray {
489 let template_params = metadata::get_template_parameters(cx, generics, args);
490 create_DIArray(DIB(cx), &template_params)
491 }
492
493 fn get_containing_scope<'ll, 'tcx>(
496 cx: &CodegenCx<'ll, 'tcx>,
497 instance: Instance<'tcx>,
498 ) -> (&'ll DIScope, bool) {
499 if let Some(impl_def_id) = cx.tcx.impl_of_method(instance.def_id()) {
503 if cx.tcx.trait_id_of_impl(impl_def_id).is_none() {
505 let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
506 instance.args,
507 cx.typing_env(),
508 cx.tcx.type_of(impl_def_id),
509 );
510
511 if let ty::Adt(def, ..) = impl_self_ty.kind()
514 && !def.is_box()
515 {
516 if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param()
518 {
519 return (type_di_node(cx, impl_self_ty), true);
520 } else {
521 return (namespace::item_namespace(cx, def.did()), false);
522 }
523 }
524 } else {
525 }
528 }
529
530 let scope = namespace::item_namespace(
531 cx,
532 DefId {
533 krate: instance.def_id().krate,
534 index: cx
535 .tcx
536 .def_key(instance.def_id())
537 .parent
538 .expect("get_containing_scope: missing parent?"),
539 },
540 );
541 (scope, false)
542 }
543 }
544
545 fn dbg_loc(
546 &self,
547 scope: &'ll DIScope,
548 inlined_at: Option<&'ll DILocation>,
549 span: Span,
550 ) -> &'ll DILocation {
551 let (line, col) = if span.is_dummy() && !self.sess().target.is_like_msvc {
557 (0, 0)
558 } else {
559 let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
560 (line, col)
561 };
562
563 unsafe { llvm::LLVMDIBuilderCreateDebugLocation(self.llcx, line, col, scope, inlined_at) }
564 }
565
566 fn create_vtable_debuginfo(
567 &self,
568 ty: Ty<'tcx>,
569 trait_ref: Option<ty::ExistentialTraitRef<'tcx>>,
570 vtable: Self::Value,
571 ) {
572 metadata::create_vtable_di_node(self, ty, trait_ref, vtable)
573 }
574
575 fn extend_scope_to_file(
576 &self,
577 scope_metadata: &'ll DIScope,
578 file: &rustc_span::SourceFile,
579 ) -> &'ll DILexicalBlock {
580 metadata::extend_scope_to_file(self, scope_metadata, file)
581 }
582
583 fn debuginfo_finalize(&self) {
584 finalize(self)
585 }
586
587 fn create_dbg_var(
590 &self,
591 variable_name: Symbol,
592 variable_type: Ty<'tcx>,
593 scope_metadata: &'ll DIScope,
594 variable_kind: VariableKind,
595 span: Span,
596 ) -> &'ll DIVariable {
597 let loc = self.lookup_debug_loc(span.lo());
598 let file_metadata = file_metadata(self, &loc.file);
599
600 let type_metadata = type_di_node(self, variable_type);
601
602 let (argument_index, dwarf_tag) = match variable_kind {
603 ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
604 LocalVariable => (0, DW_TAG_auto_variable),
605 };
606 let align = self.align_of(variable_type);
607
608 let name = variable_name.as_str();
609 unsafe {
610 llvm::LLVMRustDIBuilderCreateVariable(
611 DIB(self),
612 dwarf_tag,
613 scope_metadata,
614 name.as_c_char_ptr(),
615 name.len(),
616 file_metadata,
617 loc.line,
618 type_metadata,
619 true,
620 DIFlags::FlagZero,
621 argument_index,
622 align.bits() as u32,
623 )
624 }
625 }
626}