From 09ec683ae72086278db2ba8fa0d6168814b51b93 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 27 Mar 2024 10:57:13 +0000 Subject: [PATCH 1/6] Emit DW_AT_frame_base debuginfo attribute --- src/debuginfo/mod.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 2d9c2ecdbc2..56307aa3bb9 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -8,10 +8,10 @@ use cranelift_codegen::ir::Endianness; use cranelift_codegen::isa::TargetIsa; use gimli::write::{ - Address, AttributeValue, DwarfUnit, FileId, LineProgram, LineString, Range, RangeList, - UnitEntryId, + Address, AttributeValue, DwarfUnit, Expression, FileId, LineProgram, LineString, Range, + RangeList, UnitEntryId, }; -use gimli::{Encoding, Format, LineEncoding, RunTimeEndian}; +use gimli::{AArch64, Encoding, Format, LineEncoding, Register, RiscV, RunTimeEndian, X86_64}; use indexmap::IndexSet; use rustc_session::Session; @@ -28,6 +28,7 @@ pub(crate) struct DebugContext { dwarf: DwarfUnit, unit_range_list: RangeList, + stack_pointer_register: Register, should_remap_filepaths: bool, } @@ -60,6 +61,15 @@ pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa) -> Self { Endianness::Big => RunTimeEndian::Big, }; + let stack_pointer_register = match isa.triple().architecture { + target_lexicon::Architecture::Aarch64(_) => AArch64::SP, + target_lexicon::Architecture::Riscv64(_) => RiscV::SP, + target_lexicon::Architecture::X86_64 | target_lexicon::Architecture::X86_64h => { + X86_64::RSP + } + _ => Register(u16::MAX), + }; + let mut dwarf = DwarfUnit::new(encoding); let should_remap_filepaths = tcx.sess.should_prefer_remapped_for_codegen(); @@ -111,6 +121,7 @@ pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa) -> Self { endian, dwarf, unit_range_list: RangeList(Vec::new()), + stack_pointer_register, should_remap_filepaths, } } @@ -135,6 +146,10 @@ pub(crate) fn define_function( entry.set(gimli::DW_AT_name, AttributeValue::StringRef(name_id)); entry.set(gimli::DW_AT_linkage_name, AttributeValue::StringRef(name_id)); + let mut frame_base_expr = Expression::new(); + frame_base_expr.op_reg(self.stack_pointer_register); + entry.set(gimli::DW_AT_frame_base, AttributeValue::Exprloc(frame_base_expr)); + entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id))); entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line)); entry.set(gimli::DW_AT_decl_column, AttributeValue::Udata(column)); From c76c269aa466b786d4ca3a78dae9cb84912406ed Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 27 Mar 2024 11:04:35 +0000 Subject: [PATCH 2/6] Reduce debuginfo divergence between cg_llvm and cg_clif --- src/debuginfo/mod.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 56307aa3bb9..44ee2b822a9 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -142,17 +142,25 @@ pub(crate) fn define_function( let entry_id = self.dwarf.unit.add(scope, gimli::DW_TAG_subprogram); let entry = self.dwarf.unit.get_mut(entry_id); let name_id = self.dwarf.strings.add(name); - // Gdb requires DW_AT_name. Otherwise the DW_TAG_subprogram is skipped. - entry.set(gimli::DW_AT_name, AttributeValue::StringRef(name_id)); - entry.set(gimli::DW_AT_linkage_name, AttributeValue::StringRef(name_id)); + + // These will be replaced in FunctionDebugContext::finalize. They are + // only defined here to ensure that the order of the attributes matches + // rustc. + entry.set(gimli::DW_AT_low_pc, AttributeValue::Udata(0)); + entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(0)); let mut frame_base_expr = Expression::new(); frame_base_expr.op_reg(self.stack_pointer_register); entry.set(gimli::DW_AT_frame_base, AttributeValue::Exprloc(frame_base_expr)); + // Gdb requires DW_AT_name. Otherwise the DW_TAG_subprogram is skipped. + // FIXME only include the function name and not the full mangled symbol + entry.set(gimli::DW_AT_name, AttributeValue::StringRef(name_id)); + entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id))); entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line)); - entry.set(gimli::DW_AT_decl_column, AttributeValue::Udata(column)); + + // FIXME set DW_AT_external as appropriate FunctionDebugContext { entry_id, From e48d7d242fcf378d66d27dddea546029239bd5c6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 27 Mar 2024 12:43:47 +0000 Subject: [PATCH 3/6] Emit namespace debuginfo --- src/base.rs | 2 +- src/debuginfo/mod.rs | 63 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/base.rs b/src/base.rs index dbce6d165d2..4e60f820594 100644 --- a/src/base.rs +++ b/src/base.rs @@ -70,7 +70,7 @@ pub(crate) fn codegen_fn<'tcx>( let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance); let func_debug_cx = if let Some(debug_context) = &mut cx.debug_context { - Some(debug_context.define_function(tcx, &symbol_name, mir.span)) + Some(debug_context.define_function(tcx, instance, &symbol_name, mir.span)) } else { None }; diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 44ee2b822a9..2b5f472c5fc 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -13,6 +13,8 @@ }; use gimli::{AArch64, Encoding, Format, LineEncoding, Register, RiscV, RunTimeEndian, X86_64}; use indexmap::IndexSet; +use rustc_codegen_ssa::debuginfo::type_names; +use rustc_hir::def_id::DefIdMap; use rustc_session::Session; pub(crate) use self::emit::{DebugReloc, DebugRelocName}; @@ -29,6 +31,7 @@ pub(crate) struct DebugContext { dwarf: DwarfUnit, unit_range_list: RangeList, stack_pointer_register: Register, + namespace_map: DefIdMap, should_remap_filepaths: bool, } @@ -122,14 +125,42 @@ pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa) -> Self { dwarf, unit_range_list: RangeList(Vec::new()), stack_pointer_register, + namespace_map: DefIdMap::default(), should_remap_filepaths, } } - pub(crate) fn define_function( + fn item_namespace(&mut self, tcx: TyCtxt<'_>, def_id: DefId) -> UnitEntryId { + if let Some(&scope) = self.namespace_map.get(&def_id) { + return scope; + } + + let def_key = tcx.def_key(def_id); + let parent_scope = def_key + .parent + .map(|parent| self.item_namespace(tcx, DefId { krate: def_id.krate, index: parent })) + .unwrap_or(self.dwarf.unit.root()); + + let namespace_name = { + let mut output = String::new(); + type_names::push_item_name(tcx, def_id, false, &mut output); + output + }; + let namespace_name_id = self.dwarf.strings.add(namespace_name); + + let scope = self.dwarf.unit.add(parent_scope, gimli::DW_TAG_namespace); + let scope_entry = self.dwarf.unit.get_mut(scope); + scope_entry.set(gimli::DW_AT_name, AttributeValue::StringRef(namespace_name_id)); + + self.namespace_map.insert(def_id, scope); + scope + } + + pub(crate) fn define_function<'tcx>( &mut self, - tcx: TyCtxt<'_>, - name: &str, + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + linkage_name: &str, function_span: Span, ) -> FunctionDebugContext { let (file, line, column) = DebugContext::get_span_loc(tcx, function_span, function_span); @@ -137,10 +168,31 @@ pub(crate) fn define_function( let file_id = self.add_source_file(&file); // FIXME: add to appropriate scope instead of root - let scope = self.dwarf.unit.root(); + let scope = self.item_namespace(tcx, tcx.parent(instance.def_id())); + + let mut name = String::new(); + type_names::push_item_name(tcx, instance.def_id(), false, &mut name); + + // Find the enclosing function, in case this is a closure. + let enclosing_fn_def_id = tcx.typeck_root_def_id(instance.def_id()); + + // We look up the generics of the enclosing function and truncate the args + // to their length in order to cut off extra stuff that might be in there for + // closures or coroutines. + let generics = tcx.generics_of(enclosing_fn_def_id); + let args = instance.args.truncate_to(tcx, generics); + + type_names::push_generic_params( + tcx, + tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args), + enclosing_fn_def_id, + &mut name, + ); let entry_id = self.dwarf.unit.add(scope, gimli::DW_TAG_subprogram); let entry = self.dwarf.unit.get_mut(entry_id); + let linkage_name_id = + if name != linkage_name { Some(self.dwarf.strings.add(linkage_name)) } else { None }; let name_id = self.dwarf.strings.add(name); // These will be replaced in FunctionDebugContext::finalize. They are @@ -153,6 +205,9 @@ pub(crate) fn define_function( frame_base_expr.op_reg(self.stack_pointer_register); entry.set(gimli::DW_AT_frame_base, AttributeValue::Exprloc(frame_base_expr)); + if let Some(linkage_name_id) = linkage_name_id { + entry.set(gimli::DW_AT_linkage_name, AttributeValue::StringRef(linkage_name_id)); + } // Gdb requires DW_AT_name. Otherwise the DW_TAG_subprogram is skipped. // FIXME only include the function name and not the full mangled symbol entry.set(gimli::DW_AT_name, AttributeValue::StringRef(name_id)); From 98eaaeda111673c617134fe2dcd3f10bb6dfc2f0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 27 Mar 2024 12:57:24 +0000 Subject: [PATCH 4/6] Match unit names with cg_llvm --- src/debuginfo/mod.rs | 10 ++++++++-- src/lib.rs | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 2b5f472c5fc..4232018916f 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -43,7 +43,7 @@ pub(crate) struct FunctionDebugContext { } impl DebugContext { - pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa) -> Self { + pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, cgu_name: &str) -> Self { let encoding = Encoding { format: Format::Dwarf32, // FIXME this should be configurable @@ -108,7 +108,7 @@ pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa) -> Self { dwarf.unit.line_program = line_program; { - let name = dwarf.strings.add(name); + let name = dwarf.strings.add(format!("{name}/@/{cgu_name}")); let comp_dir = dwarf.strings.add(comp_dir); let root = dwarf.unit.root(); @@ -116,6 +116,12 @@ pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa) -> Self { root.set(gimli::DW_AT_producer, AttributeValue::StringRef(dwarf.strings.add(producer))); root.set(gimli::DW_AT_language, AttributeValue::Language(gimli::DW_LANG_Rust)); root.set(gimli::DW_AT_name, AttributeValue::StringRef(name)); + + // This will be replaced when emitting the debuginfo. It is only + // defined here to ensure that the order of the attributes matches + // rustc. + root.set(gimli::DW_AT_stmt_list, AttributeValue::Udata(0)); + root.set(gimli::DW_AT_comp_dir, AttributeValue::StringRef(comp_dir)); root.set(gimli::DW_AT_low_pc, AttributeValue::Address(Address::Constant(0))); } diff --git a/src/lib.rs b/src/lib.rs index a121ac75a28..d0ab64a5584 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -148,7 +148,7 @@ fn new( let unwind_context = UnwindContext::new(isa, matches!(backend_config.codegen_mode, CodegenMode::Aot)); let debug_context = if debug_info && !tcx.sess.target.options.is_like_windows { - Some(DebugContext::new(tcx, isa)) + Some(DebugContext::new(tcx, isa, cgu_name.as_str())) } else { None }; From a64387bb6be6360df09e4844c35d63b50b20262e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 27 Mar 2024 13:28:40 +0000 Subject: [PATCH 5/6] Emit DW_AT_external if applicable --- src/debuginfo/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index 4232018916f..ef684199756 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -221,6 +221,10 @@ pub(crate) fn define_function<'tcx>( entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id))); entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line)); + if tcx.is_reachable_non_generic(instance.def_id()) { + entry.set(gimli::DW_AT_external, AttributeValue::FlagPresent); + } + // FIXME set DW_AT_external as appropriate FunctionDebugContext { From 41246b2cf629a0b2699360f35952cff8a7d3d784 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 27 Mar 2024 13:35:11 +0000 Subject: [PATCH 6/6] Remove fixed todos --- src/debuginfo/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/debuginfo/mod.rs b/src/debuginfo/mod.rs index ef684199756..b541cf0512e 100644 --- a/src/debuginfo/mod.rs +++ b/src/debuginfo/mod.rs @@ -215,7 +215,6 @@ pub(crate) fn define_function<'tcx>( entry.set(gimli::DW_AT_linkage_name, AttributeValue::StringRef(linkage_name_id)); } // Gdb requires DW_AT_name. Otherwise the DW_TAG_subprogram is skipped. - // FIXME only include the function name and not the full mangled symbol entry.set(gimli::DW_AT_name, AttributeValue::StringRef(name_id)); entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id))); @@ -225,8 +224,6 @@ pub(crate) fn define_function<'tcx>( entry.set(gimli::DW_AT_external, AttributeValue::FlagPresent); } - // FIXME set DW_AT_external as appropriate - FunctionDebugContext { entry_id, function_source_loc: (file_id, line, column),