Skip to content

Commit 68b5931

Browse files
authored
Merge pull request #1470 from rust-lang/debuginfo_improvements
Various small debuginfo improvements
2 parents cfd7325 + 41246b2 commit 68b5931

File tree

3 files changed

+98
-13
lines changed

3 files changed

+98
-13
lines changed

src/base.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ pub(crate) fn codegen_fn<'tcx>(
7070
let clif_comments = crate::pretty_clif::CommentWriter::new(tcx, instance);
7171

7272
let func_debug_cx = if let Some(debug_context) = &mut cx.debug_context {
73-
Some(debug_context.define_function(tcx, &symbol_name, mir.span))
73+
Some(debug_context.define_function(tcx, instance, &symbol_name, mir.span))
7474
} else {
7575
None
7676
};

src/debuginfo/mod.rs

+96-11
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ mod unwind;
88
use cranelift_codegen::ir::Endianness;
99
use cranelift_codegen::isa::TargetIsa;
1010
use gimli::write::{
11-
Address, AttributeValue, DwarfUnit, FileId, LineProgram, LineString, Range, RangeList,
12-
UnitEntryId,
11+
Address, AttributeValue, DwarfUnit, Expression, FileId, LineProgram, LineString, Range,
12+
RangeList, UnitEntryId,
1313
};
14-
use gimli::{Encoding, Format, LineEncoding, RunTimeEndian};
14+
use gimli::{AArch64, Encoding, Format, LineEncoding, Register, RiscV, RunTimeEndian, X86_64};
1515
use indexmap::IndexSet;
16+
use rustc_codegen_ssa::debuginfo::type_names;
17+
use rustc_hir::def_id::DefIdMap;
1618
use rustc_session::Session;
1719

1820
pub(crate) use self::emit::{DebugReloc, DebugRelocName};
@@ -28,6 +30,8 @@ pub(crate) struct DebugContext {
2830

2931
dwarf: DwarfUnit,
3032
unit_range_list: RangeList,
33+
stack_pointer_register: Register,
34+
namespace_map: DefIdMap<UnitEntryId>,
3135

3236
should_remap_filepaths: bool,
3337
}
@@ -39,7 +43,7 @@ pub(crate) struct FunctionDebugContext {
3943
}
4044

4145
impl DebugContext {
42-
pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa) -> Self {
46+
pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, cgu_name: &str) -> Self {
4347
let encoding = Encoding {
4448
format: Format::Dwarf32,
4549
// FIXME this should be configurable
@@ -60,6 +64,15 @@ impl DebugContext {
6064
Endianness::Big => RunTimeEndian::Big,
6165
};
6266

67+
let stack_pointer_register = match isa.triple().architecture {
68+
target_lexicon::Architecture::Aarch64(_) => AArch64::SP,
69+
target_lexicon::Architecture::Riscv64(_) => RiscV::SP,
70+
target_lexicon::Architecture::X86_64 | target_lexicon::Architecture::X86_64h => {
71+
X86_64::RSP
72+
}
73+
_ => Register(u16::MAX),
74+
};
75+
6376
let mut dwarf = DwarfUnit::new(encoding);
6477

6578
let should_remap_filepaths = tcx.sess.should_prefer_remapped_for_codegen();
@@ -95,14 +108,20 @@ impl DebugContext {
95108
dwarf.unit.line_program = line_program;
96109

97110
{
98-
let name = dwarf.strings.add(name);
111+
let name = dwarf.strings.add(format!("{name}/@/{cgu_name}"));
99112
let comp_dir = dwarf.strings.add(comp_dir);
100113

101114
let root = dwarf.unit.root();
102115
let root = dwarf.unit.get_mut(root);
103116
root.set(gimli::DW_AT_producer, AttributeValue::StringRef(dwarf.strings.add(producer)));
104117
root.set(gimli::DW_AT_language, AttributeValue::Language(gimli::DW_LANG_Rust));
105118
root.set(gimli::DW_AT_name, AttributeValue::StringRef(name));
119+
120+
// This will be replaced when emitting the debuginfo. It is only
121+
// defined here to ensure that the order of the attributes matches
122+
// rustc.
123+
root.set(gimli::DW_AT_stmt_list, AttributeValue::Udata(0));
124+
106125
root.set(gimli::DW_AT_comp_dir, AttributeValue::StringRef(comp_dir));
107126
root.set(gimli::DW_AT_low_pc, AttributeValue::Address(Address::Constant(0)));
108127
}
@@ -111,33 +130,99 @@ impl DebugContext {
111130
endian,
112131
dwarf,
113132
unit_range_list: RangeList(Vec::new()),
133+
stack_pointer_register,
134+
namespace_map: DefIdMap::default(),
114135
should_remap_filepaths,
115136
}
116137
}
117138

118-
pub(crate) fn define_function(
139+
fn item_namespace(&mut self, tcx: TyCtxt<'_>, def_id: DefId) -> UnitEntryId {
140+
if let Some(&scope) = self.namespace_map.get(&def_id) {
141+
return scope;
142+
}
143+
144+
let def_key = tcx.def_key(def_id);
145+
let parent_scope = def_key
146+
.parent
147+
.map(|parent| self.item_namespace(tcx, DefId { krate: def_id.krate, index: parent }))
148+
.unwrap_or(self.dwarf.unit.root());
149+
150+
let namespace_name = {
151+
let mut output = String::new();
152+
type_names::push_item_name(tcx, def_id, false, &mut output);
153+
output
154+
};
155+
let namespace_name_id = self.dwarf.strings.add(namespace_name);
156+
157+
let scope = self.dwarf.unit.add(parent_scope, gimli::DW_TAG_namespace);
158+
let scope_entry = self.dwarf.unit.get_mut(scope);
159+
scope_entry.set(gimli::DW_AT_name, AttributeValue::StringRef(namespace_name_id));
160+
161+
self.namespace_map.insert(def_id, scope);
162+
scope
163+
}
164+
165+
pub(crate) fn define_function<'tcx>(
119166
&mut self,
120-
tcx: TyCtxt<'_>,
121-
name: &str,
167+
tcx: TyCtxt<'tcx>,
168+
instance: Instance<'tcx>,
169+
linkage_name: &str,
122170
function_span: Span,
123171
) -> FunctionDebugContext {
124172
let (file, line, column) = DebugContext::get_span_loc(tcx, function_span, function_span);
125173

126174
let file_id = self.add_source_file(&file);
127175

128176
// FIXME: add to appropriate scope instead of root
129-
let scope = self.dwarf.unit.root();
177+
let scope = self.item_namespace(tcx, tcx.parent(instance.def_id()));
178+
179+
let mut name = String::new();
180+
type_names::push_item_name(tcx, instance.def_id(), false, &mut name);
181+
182+
// Find the enclosing function, in case this is a closure.
183+
let enclosing_fn_def_id = tcx.typeck_root_def_id(instance.def_id());
184+
185+
// We look up the generics of the enclosing function and truncate the args
186+
// to their length in order to cut off extra stuff that might be in there for
187+
// closures or coroutines.
188+
let generics = tcx.generics_of(enclosing_fn_def_id);
189+
let args = instance.args.truncate_to(tcx, generics);
190+
191+
type_names::push_generic_params(
192+
tcx,
193+
tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), args),
194+
enclosing_fn_def_id,
195+
&mut name,
196+
);
130197

131198
let entry_id = self.dwarf.unit.add(scope, gimli::DW_TAG_subprogram);
132199
let entry = self.dwarf.unit.get_mut(entry_id);
200+
let linkage_name_id =
201+
if name != linkage_name { Some(self.dwarf.strings.add(linkage_name)) } else { None };
133202
let name_id = self.dwarf.strings.add(name);
203+
204+
// These will be replaced in FunctionDebugContext::finalize. They are
205+
// only defined here to ensure that the order of the attributes matches
206+
// rustc.
207+
entry.set(gimli::DW_AT_low_pc, AttributeValue::Udata(0));
208+
entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(0));
209+
210+
let mut frame_base_expr = Expression::new();
211+
frame_base_expr.op_reg(self.stack_pointer_register);
212+
entry.set(gimli::DW_AT_frame_base, AttributeValue::Exprloc(frame_base_expr));
213+
214+
if let Some(linkage_name_id) = linkage_name_id {
215+
entry.set(gimli::DW_AT_linkage_name, AttributeValue::StringRef(linkage_name_id));
216+
}
134217
// Gdb requires DW_AT_name. Otherwise the DW_TAG_subprogram is skipped.
135218
entry.set(gimli::DW_AT_name, AttributeValue::StringRef(name_id));
136-
entry.set(gimli::DW_AT_linkage_name, AttributeValue::StringRef(name_id));
137219

138220
entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id)));
139221
entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line));
140-
entry.set(gimli::DW_AT_decl_column, AttributeValue::Udata(column));
222+
223+
if tcx.is_reachable_non_generic(instance.def_id()) {
224+
entry.set(gimli::DW_AT_external, AttributeValue::FlagPresent);
225+
}
141226

142227
FunctionDebugContext {
143228
entry_id,

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ impl CodegenCx {
148148
let unwind_context =
149149
UnwindContext::new(isa, matches!(backend_config.codegen_mode, CodegenMode::Aot));
150150
let debug_context = if debug_info && !tcx.sess.target.options.is_like_windows {
151-
Some(DebugContext::new(tcx, isa))
151+
Some(DebugContext::new(tcx, isa, cgu_name.as_str()))
152152
} else {
153153
None
154154
};

0 commit comments

Comments
 (0)