1 //! Handling of everything related to debuginfo.
10 use cranelift_codegen
::ir
::Endianness
;
11 use cranelift_codegen
::isa
::TargetIsa
;
14 Address
, AttributeValue
, DwarfUnit
, FileId
, LineProgram
, LineString
, Range
, RangeList
,
17 use gimli
::{Encoding, Format, LineEncoding, RunTimeEndian}
;
18 use indexmap
::IndexSet
;
20 pub(crate) use emit
::{DebugReloc, DebugRelocName}
;
21 pub(crate) use unwind
::UnwindContext
;
23 pub(crate) struct DebugContext
{
24 endian
: RunTimeEndian
,
27 unit_range_list
: RangeList
,
30 pub(crate) struct FunctionDebugContext
{
31 entry_id
: UnitEntryId
,
32 function_source_loc
: (FileId
, u64, u64),
33 source_loc_set
: indexmap
::IndexSet
<(FileId
, u64, u64)>,
37 pub(crate) fn new(tcx
: TyCtxt
<'_
>, isa
: &dyn TargetIsa
) -> Self {
38 let encoding
= Encoding
{
39 format
: Format
::Dwarf32
,
40 // FIXME this should be configurable
41 // macOS doesn't seem to support DWARF > 3
42 // 5 version is required for md5 file hash
43 version
: if tcx
.sess
.target
.is_like_osx
{
46 // FIXME change to version 5 once the gdb and lldb shipping with the latest debian
50 address_size
: isa
.frontend_config().pointer_bytes(),
53 let endian
= match isa
.endianness() {
54 Endianness
::Little
=> RunTimeEndian
::Little
,
55 Endianness
::Big
=> RunTimeEndian
::Big
,
58 let mut dwarf
= DwarfUnit
::new(encoding
);
60 let producer
= format
!(
61 "cg_clif (rustc {}, cranelift {})",
62 rustc_interface
::util
::version_str().unwrap_or("unknown version"),
63 cranelift_codegen
::VERSION
,
69 .to_string_lossy(FileNameDisplayPreference
::Remapped
)
71 let (name
, file_info
) = match tcx
.sess
.local_crate_source_file
.clone() {
73 let name
= path
.to_string_lossy().into_owned();
76 None
=> (tcx
.crate_name(LOCAL_CRATE
).to_string(), None
),
79 let mut line_program
= LineProgram
::new(
81 LineEncoding
::default(),
82 LineString
::new(comp_dir
.as_bytes(), encoding
, &mut dwarf
.line_strings
),
83 LineString
::new(name
.as_bytes(), encoding
, &mut dwarf
.line_strings
),
86 line_program
.file_has_md5
= file_info
.is_some();
88 dwarf
.unit
.line_program
= line_program
;
91 let name
= dwarf
.strings
.add(name
);
92 let comp_dir
= dwarf
.strings
.add(comp_dir
);
94 let root
= dwarf
.unit
.root();
95 let root
= dwarf
.unit
.get_mut(root
);
96 root
.set(gimli
::DW_AT_producer
, AttributeValue
::StringRef(dwarf
.strings
.add(producer
)));
97 root
.set(gimli
::DW_AT_language
, AttributeValue
::Language(gimli
::DW_LANG_Rust
));
98 root
.set(gimli
::DW_AT_name
, AttributeValue
::StringRef(name
));
99 root
.set(gimli
::DW_AT_comp_dir
, AttributeValue
::StringRef(comp_dir
));
100 root
.set(gimli
::DW_AT_low_pc
, AttributeValue
::Address(Address
::Constant(0)));
103 DebugContext { endian, dwarf, unit_range_list: RangeList(Vec::new()) }
106 pub(crate) fn define_function(
111 ) -> FunctionDebugContext
{
112 let (file
, line
, column
) = DebugContext
::get_span_loc(tcx
, function_span
, function_span
);
114 let file_id
= self.add_source_file(&file
);
116 // FIXME: add to appropriate scope instead of root
117 let scope
= self.dwarf
.unit
.root();
119 let entry_id
= self.dwarf
.unit
.add(scope
, gimli
::DW_TAG_subprogram
);
120 let entry
= self.dwarf
.unit
.get_mut(entry_id
);
121 let name_id
= self.dwarf
.strings
.add(name
);
122 // Gdb requires DW_AT_name. Otherwise the DW_TAG_subprogram is skipped.
123 entry
.set(gimli
::DW_AT_name
, AttributeValue
::StringRef(name_id
));
124 entry
.set(gimli
::DW_AT_linkage_name
, AttributeValue
::StringRef(name_id
));
126 entry
.set(gimli
::DW_AT_decl_file
, AttributeValue
::FileIndex(Some(file_id
)));
127 entry
.set(gimli
::DW_AT_decl_line
, AttributeValue
::Udata(line
));
128 entry
.set(gimli
::DW_AT_decl_column
, AttributeValue
::Udata(column
));
130 FunctionDebugContext
{
132 function_source_loc
: (file_id
, line
, column
),
133 source_loc_set
: IndexSet
::new(),
138 impl FunctionDebugContext
{
139 pub(crate) fn finalize(
141 debug_context
: &mut DebugContext
,
145 let symbol
= func_id
.as_u32() as usize;
147 let end
= self.create_debug_lines(debug_context
, symbol
, context
);
149 debug_context
.unit_range_list
.0.push(Range
::StartLength
{
150 begin
: Address
::Symbol { symbol, addend: 0 }
,
151 length
: u64::from(end
),
154 let func_entry
= debug_context
.dwarf
.unit
.get_mut(self.entry_id
);
155 // Gdb requires both DW_AT_low_pc and DW_AT_high_pc. Otherwise the DW_TAG_subprogram is skipped.
158 AttributeValue
::Address(Address
::Symbol { symbol, addend: 0 }
),
160 // Using Udata for DW_AT_high_pc requires at least DWARF4
161 func_entry
.set(gimli
::DW_AT_high_pc
, AttributeValue
::Udata(u64::from(end
)));