1 //! Handling of everything related to debuginfo.
9 use cranelift_codegen
::ir
::Endianness
;
10 use cranelift_codegen
::isa
::TargetIsa
;
11 use cranelift_module
::DataId
;
13 Address
, AttributeValue
, DwarfUnit
, Expression
, FileId
, LineProgram
, LineString
, Range
,
14 RangeList
, UnitEntryId
,
16 use gimli
::{AArch64, Encoding, Format, LineEncoding, Register, RiscV, RunTimeEndian, X86_64}
;
17 use indexmap
::IndexSet
;
18 use rustc_codegen_ssa
::debuginfo
::type_names
;
19 use rustc_hir
::def
::DefKind
;
20 use rustc_hir
::def_id
::DefIdMap
;
21 use rustc_session
::Session
;
22 use rustc_span
::{FileNameDisplayPreference, SourceFileHash, StableSourceFileId}
;
23 use rustc_target
::abi
::call
::FnAbi
;
25 pub(crate) use self::emit
::{DebugReloc, DebugRelocName}
;
26 pub(crate) use self::types
::TypeDebugContext
;
27 pub(crate) use self::unwind
::UnwindContext
;
28 use crate::debuginfo
::emit
::{address_for_data, address_for_func}
;
29 use crate::prelude
::*;
31 pub(crate) fn producer(sess
: &Session
) -> String
{
32 format
!("rustc version {} with cranelift {}", sess
.cfg_version
, cranelift_codegen
::VERSION
)
35 pub(crate) struct DebugContext
{
36 endian
: RunTimeEndian
,
39 unit_range_list
: RangeList
,
40 created_files
: FxHashMap
<(StableSourceFileId
, SourceFileHash
), FileId
>,
41 stack_pointer_register
: Register
,
42 namespace_map
: DefIdMap
<UnitEntryId
>,
43 array_size_type
: UnitEntryId
,
45 filename_display_preference
: FileNameDisplayPreference
,
48 pub(crate) struct FunctionDebugContext
{
49 entry_id
: UnitEntryId
,
50 function_source_loc
: (FileId
, u64, u64),
51 source_loc_set
: IndexSet
<(FileId
, u64, u64)>,
55 pub(crate) fn new(tcx
: TyCtxt
<'_
>, isa
: &dyn TargetIsa
, cgu_name
: &str) -> Self {
56 let encoding
= Encoding
{
57 format
: Format
::Dwarf32
,
58 // FIXME this should be configurable
59 // macOS doesn't seem to support DWARF > 3
60 // 5 version is required for md5 file hash
61 version
: if tcx
.sess
.target
.is_like_osx
{
64 // FIXME change to version 5 once the gdb and lldb shipping with the latest debian
68 address_size
: isa
.frontend_config().pointer_bytes(),
71 let endian
= match isa
.endianness() {
72 Endianness
::Little
=> RunTimeEndian
::Little
,
73 Endianness
::Big
=> RunTimeEndian
::Big
,
76 let stack_pointer_register
= match isa
.triple().architecture
{
77 target_lexicon
::Architecture
::Aarch64(_
) => AArch64
::SP
,
78 target_lexicon
::Architecture
::Riscv64(_
) => RiscV
::SP
,
79 target_lexicon
::Architecture
::X86_64
| target_lexicon
::Architecture
::X86_64h
=> {
82 _
=> Register(u16::MAX
),
85 let mut dwarf
= DwarfUnit
::new(encoding
);
87 use rustc_session
::config
::RemapPathScopeComponents
;
89 let filename_display_preference
=
90 tcx
.sess
.filename_display_preference(RemapPathScopeComponents
::DEBUGINFO
);
92 let producer
= producer(tcx
.sess
);
94 tcx
.sess
.opts
.working_dir
.to_string_lossy(filename_display_preference
).to_string();
96 let (name
, file_info
) = match tcx
.sess
.local_crate_source_file() {
98 let name
= path
.to_string_lossy(filename_display_preference
).to_string();
101 None
=> (tcx
.crate_name(LOCAL_CRATE
).to_string(), None
),
104 let mut line_program
= LineProgram
::new(
106 LineEncoding
::default(),
107 LineString
::new(comp_dir
.as_bytes(), encoding
, &mut dwarf
.line_strings
),
108 LineString
::new(name
.as_bytes(), encoding
, &mut dwarf
.line_strings
),
111 line_program
.file_has_md5
= file_info
.is_some();
113 dwarf
.unit
.line_program
= line_program
;
116 let name
= dwarf
.strings
.add(format
!("{name}/@/{cgu_name}"));
117 let comp_dir
= dwarf
.strings
.add(comp_dir
);
119 let root
= dwarf
.unit
.root();
120 let root
= dwarf
.unit
.get_mut(root
);
121 root
.set(gimli
::DW_AT_producer
, AttributeValue
::StringRef(dwarf
.strings
.add(producer
)));
122 root
.set(gimli
::DW_AT_language
, AttributeValue
::Language(gimli
::DW_LANG_Rust
));
123 root
.set(gimli
::DW_AT_name
, AttributeValue
::StringRef(name
));
125 // This will be replaced when emitting the debuginfo. It is only
126 // defined here to ensure that the order of the attributes matches
128 root
.set(gimli
::DW_AT_stmt_list
, AttributeValue
::Udata(0));
130 root
.set(gimli
::DW_AT_comp_dir
, AttributeValue
::StringRef(comp_dir
));
131 root
.set(gimli
::DW_AT_low_pc
, AttributeValue
::Address(Address
::Constant(0)));
134 let array_size_type
= dwarf
.unit
.add(dwarf
.unit
.root(), gimli
::DW_TAG_base_type
);
135 let array_size_type_entry
= dwarf
.unit
.get_mut(array_size_type
);
136 array_size_type_entry
.set(
138 AttributeValue
::StringRef(dwarf
.strings
.add("__ARRAY_SIZE_TYPE__")),
140 array_size_type_entry
141 .set(gimli
::DW_AT_encoding
, AttributeValue
::Encoding(gimli
::DW_ATE_unsigned
));
142 array_size_type_entry
.set(
143 gimli
::DW_AT_byte_size
,
144 AttributeValue
::Udata(isa
.frontend_config().pointer_bytes().into()),
150 unit_range_list
: RangeList(Vec
::new()),
151 created_files
: FxHashMap
::default(),
152 stack_pointer_register
,
153 namespace_map
: DefIdMap
::default(),
155 filename_display_preference
,
159 fn item_namespace(&mut self, tcx
: TyCtxt
<'_
>, def_id
: DefId
) -> UnitEntryId
{
160 if let Some(&scope
) = self.namespace_map
.get(&def_id
) {
164 let def_key
= tcx
.def_key(def_id
);
165 let parent_scope
= def_key
167 .map(|parent
| self.item_namespace(tcx
, DefId { krate: def_id.krate, index: parent }
))
168 .unwrap_or(self.dwarf
.unit
.root());
170 let namespace_name
= {
171 let mut output
= String
::new();
172 type_names
::push_item_name(tcx
, def_id
, false, &mut output
);
175 let namespace_name_id
= self.dwarf
.strings
.add(namespace_name
);
177 let scope
= self.dwarf
.unit
.add(parent_scope
, gimli
::DW_TAG_namespace
);
178 let scope_entry
= self.dwarf
.unit
.get_mut(scope
);
179 scope_entry
.set(gimli
::DW_AT_name
, AttributeValue
::StringRef(namespace_name_id
));
181 self.namespace_map
.insert(def_id
, scope
);
185 pub(crate) fn define_function
<'tcx
>(
188 type_dbg
: &mut TypeDebugContext
<'tcx
>,
189 instance
: Instance
<'tcx
>,
190 fn_abi
: &'tcx FnAbi
<'tcx
, Ty
<'tcx
>>,
193 ) -> FunctionDebugContext
{
194 let (file_id
, line
, column
) = self.get_span_loc(tcx
, function_span
, function_span
);
196 let scope
= self.item_namespace(tcx
, tcx
.parent(instance
.def_id()));
198 let mut name
= String
::new();
199 type_names
::push_item_name(tcx
, instance
.def_id(), false, &mut name
);
201 // Find the enclosing function, in case this is a closure.
202 let enclosing_fn_def_id
= tcx
.typeck_root_def_id(instance
.def_id());
204 // We look up the generics of the enclosing function and truncate the args
205 // to their length in order to cut off extra stuff that might be in there for
206 // closures or coroutines.
207 let generics
= tcx
.generics_of(enclosing_fn_def_id
);
208 let args
= instance
.args
.truncate_to(tcx
, generics
);
210 type_names
::push_generic_params(
212 tcx
.normalize_erasing_regions(ty
::ParamEnv
::reveal_all(), args
),
217 let entry_id
= self.dwarf
.unit
.add(scope
, gimli
::DW_TAG_subprogram
);
218 let entry
= self.dwarf
.unit
.get_mut(entry_id
);
219 let linkage_name_id
=
220 if name
!= linkage_name { Some(self.dwarf.strings.add(linkage_name)) }
else { None }
;
221 let name_id
= self.dwarf
.strings
.add(name
);
223 // These will be replaced in FunctionDebugContext::finalize. They are
224 // only defined here to ensure that the order of the attributes matches
226 entry
.set(gimli
::DW_AT_low_pc
, AttributeValue
::Udata(0));
227 entry
.set(gimli
::DW_AT_high_pc
, AttributeValue
::Udata(0));
229 let mut frame_base_expr
= Expression
::new();
230 frame_base_expr
.op_reg(self.stack_pointer_register
);
231 entry
.set(gimli
::DW_AT_frame_base
, AttributeValue
::Exprloc(frame_base_expr
));
233 if let Some(linkage_name_id
) = linkage_name_id
{
234 entry
.set(gimli
::DW_AT_linkage_name
, AttributeValue
::StringRef(linkage_name_id
));
236 // Gdb requires DW_AT_name. Otherwise the DW_TAG_subprogram is skipped.
237 entry
.set(gimli
::DW_AT_name
, AttributeValue
::StringRef(name_id
));
239 entry
.set(gimli
::DW_AT_decl_file
, AttributeValue
::FileIndex(Some(file_id
)));
240 entry
.set(gimli
::DW_AT_decl_line
, AttributeValue
::Udata(line
));
242 if !fn_abi
.ret
.is_ignore() {
243 let return_dw_ty
= self.debug_type(tcx
, type_dbg
, fn_abi
.ret
.layout
.ty
);
244 let entry
= self.dwarf
.unit
.get_mut(entry_id
);
245 entry
.set(gimli
::DW_AT_type
, AttributeValue
::UnitRef(return_dw_ty
));
248 if tcx
.is_reachable_non_generic(instance
.def_id()) {
249 let entry
= self.dwarf
.unit
.get_mut(entry_id
);
250 entry
.set(gimli
::DW_AT_external
, AttributeValue
::FlagPresent
);
253 FunctionDebugContext
{
255 function_source_loc
: (file_id
, line
, column
),
256 source_loc_set
: IndexSet
::new(),
260 // Adapted from https://github.com/rust-lang/rust/blob/10a7aa14fed9b528b74b0f098c4899c37c09a9c7/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs#L1288-L1346
261 pub(crate) fn define_static
<'tcx
>(
264 type_dbg
: &mut TypeDebugContext
<'tcx
>,
268 let DefKind
::Static { nested, .. }
= tcx
.def_kind(def_id
) else { bug!() }
;
273 let scope
= self.item_namespace(tcx
, tcx
.parent(def_id
));
275 let span
= tcx
.def_span(def_id
);
276 let (file_id
, line
, _column
) = self.get_span_loc(tcx
, span
, span
);
278 let static_type
= Instance
::mono(tcx
, def_id
).ty(tcx
, ty
::ParamEnv
::reveal_all());
279 let static_layout
= tcx
.layout_of(ty
::ParamEnv
::reveal_all().and(static_type
)).unwrap();
280 // FIXME use the actual type layout
281 let type_id
= self.debug_type(tcx
, type_dbg
, static_type
);
283 let name
= tcx
.item_name(def_id
);
284 let linkage_name
= tcx
.symbol_name(Instance
::mono(tcx
, def_id
)).name
;
286 let entry_id
= self.dwarf
.unit
.add(scope
, gimli
::DW_TAG_variable
);
287 let entry
= self.dwarf
.unit
.get_mut(entry_id
);
288 let linkage_name_id
= if name
.as_str() != linkage_name
{
289 Some(self.dwarf
.strings
.add(linkage_name
))
293 let name_id
= self.dwarf
.strings
.add(name
.as_str());
295 entry
.set(gimli
::DW_AT_name
, AttributeValue
::StringRef(name_id
));
296 entry
.set(gimli
::DW_AT_type
, AttributeValue
::UnitRef(type_id
));
298 if tcx
.is_reachable_non_generic(def_id
) {
299 entry
.set(gimli
::DW_AT_external
, AttributeValue
::FlagPresent
);
302 entry
.set(gimli
::DW_AT_decl_file
, AttributeValue
::FileIndex(Some(file_id
)));
303 entry
.set(gimli
::DW_AT_decl_line
, AttributeValue
::Udata(line
));
305 entry
.set(gimli
::DW_AT_alignment
, AttributeValue
::Udata(static_layout
.align
.pref
.bytes()));
307 let mut expr
= Expression
::new();
308 expr
.op_addr(address_for_data(data_id
));
309 entry
.set(gimli
::DW_AT_location
, AttributeValue
::Exprloc(expr
));
311 if let Some(linkage_name_id
) = linkage_name_id
{
312 entry
.set(gimli
::DW_AT_linkage_name
, AttributeValue
::StringRef(linkage_name_id
));
317 impl FunctionDebugContext
{
318 pub(crate) fn finalize(
320 debug_context
: &mut DebugContext
,
324 let end
= self.create_debug_lines(debug_context
, func_id
, context
);
329 .push(Range
::StartLength { begin: address_for_func(func_id), length: u64::from(end) }
);
331 let func_entry
= debug_context
.dwarf
.unit
.get_mut(self.entry_id
);
332 // Gdb requires both DW_AT_low_pc and DW_AT_high_pc. Otherwise the DW_TAG_subprogram is skipped.
333 func_entry
.set(gimli
::DW_AT_low_pc
, AttributeValue
::Address(address_for_func(func_id
)));
334 // Using Udata for DW_AT_high_pc requires at least DWARF4
335 func_entry
.set(gimli
::DW_AT_high_pc
, AttributeValue
::Udata(u64::from(end
)));