about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbjorn3 <17426603+bjorn3@users.noreply.github.com>2024-03-27 15:08:07 +0100
committerGitHub <noreply@github.com>2024-03-27 15:08:07 +0100
commit68b59311fa8fe0baa6bc82b5c300215417034e7e (patch)
tree712443f3cacdb6c65cb54de8539d256b92215440
parentcfd7325f20806b478fc144baeaeeaccf913ae0aa (diff)
parent41246b2cf629a0b2699360f35952cff8a7d3d784 (diff)
downloadrust-68b59311fa8fe0baa6bc82b5c300215417034e7e.tar.gz
rust-68b59311fa8fe0baa6bc82b5c300215417034e7e.zip
Merge pull request #1470 from rust-lang/debuginfo_improvements
Various small debuginfo improvements
-rw-r--r--src/base.rs2
-rw-r--r--src/debuginfo/mod.rs107
-rw-r--r--src/lib.rs2
3 files changed, 98 insertions, 13 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 2d9c2ecdbc2..b541cf0512e 100644
--- a/src/debuginfo/mod.rs
+++ b/src/debuginfo/mod.rs
@@ -8,11 +8,13 @@ mod unwind;
 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_codegen_ssa::debuginfo::type_names;
+use rustc_hir::def_id::DefIdMap;
 use rustc_session::Session;
 
 pub(crate) use self::emit::{DebugReloc, DebugRelocName};
@@ -28,6 +30,8 @@ pub(crate) struct DebugContext {
 
     dwarf: DwarfUnit,
     unit_range_list: RangeList,
+    stack_pointer_register: Register,
+    namespace_map: DefIdMap<UnitEntryId>,
 
     should_remap_filepaths: bool,
 }
@@ -39,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
@@ -60,6 +64,15 @@ impl DebugContext {
             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();
@@ -95,7 +108,7 @@ impl DebugContext {
         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();
@@ -103,6 +116,12 @@ impl DebugContext {
             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)));
         }
@@ -111,14 +130,43 @@ impl DebugContext {
             endian,
             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);
@@ -126,18 +174,55 @@ impl DebugContext {
         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
+        // 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));
+
+        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.
         entry.set(gimli::DW_AT_name, AttributeValue::StringRef(name_id));
-        entry.set(gimli::DW_AT_linkage_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));
+
+        if tcx.is_reachable_non_generic(instance.def_id()) {
+            entry.set(gimli::DW_AT_external, AttributeValue::FlagPresent);
+        }
 
         FunctionDebugContext {
             entry_id,
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 @@ impl CodegenCx {
         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
         };