3 use crate::backend::WriteDebugInfo;
5 use std::marker::PhantomData;
7 use syntax::source_map::FileName;
10 Address, AttributeValue, DwarfUnit, EndianVec, FileId, LineProgram, LineString,
11 LineStringTable, Range, RangeList, Result, Sections, UnitEntryId, Writer,
13 use gimli::{Encoding, Format, LineEncoding, RunTimeEndian, SectionId};
15 fn target_endian(tcx: TyCtxt) -> RunTimeEndian {
16 use rustc::ty::layout::Endian;
18 match tcx.data_layout.endian {
19 Endian::Big => RunTimeEndian::Big,
20 Endian::Little => RunTimeEndian::Little,
24 fn line_program_add_file(
25 line_program: &mut LineProgram,
26 line_strings: &mut LineStringTable,
30 FileName::Real(path) => {
31 let dir_name = path.parent().unwrap().to_str().unwrap().as_bytes();
32 let dir_id = if !dir_name.is_empty() {
33 let dir_name = LineString::new(dir_name, line_program.encoding(), line_strings);
34 line_program.add_directory(dir_name)
36 line_program.default_directory()
38 let file_name = LineString::new(
39 path.file_name().unwrap().to_str().unwrap().as_bytes(),
40 line_program.encoding(),
43 line_program.add_file(file_name, dir_id, None)
45 // FIXME give more appropriate file names
47 let dir_id = line_program.default_directory();
48 let dummy_file_name = LineString::new(
49 file.to_string().into_bytes(),
50 line_program.encoding(),
53 line_program.add_file(dummy_file_name, dir_id, None)
59 pub struct DebugReloc {
62 pub name: DebugRelocName,
67 pub enum DebugRelocName {
72 pub struct DebugContext<'tcx> {
75 endian: RunTimeEndian,
76 symbols: indexmap::IndexMap<FuncId, String>,
79 unit_range_list: RangeList,
81 types: HashMap<Ty<'tcx>, UnitEntryId>,
84 impl<'tcx> DebugContext<'tcx> {
85 pub fn new(tcx: TyCtxt<'tcx>, address_size: u8) -> Self {
86 let encoding = Encoding {
87 format: Format::Dwarf32,
88 // TODO: this should be configurable
89 // macOS doesn't seem to support DWARF > 3
94 let mut dwarf = DwarfUnit::new(encoding);
96 // FIXME: how to get version when building out of tree?
97 // Normally this would use option_env!("CFG_VERSION").
98 let producer = format!("cranelift fn (rustc version {})", "unknown version");
99 let comp_dir = tcx.sess.working_dir.0.to_string_lossy().into_owned();
100 let name = match tcx.sess.local_crate_source_file {
101 Some(ref path) => path.to_string_lossy().into_owned(),
102 None => tcx.crate_name(LOCAL_CRATE).to_string(),
105 let line_program = LineProgram::new(
107 LineEncoding::default(),
108 LineString::new(comp_dir.as_bytes(), encoding, &mut dwarf.line_strings),
109 LineString::new(name.as_bytes(), encoding, &mut dwarf.line_strings),
112 dwarf.unit.line_program = line_program;
115 let name = dwarf.strings.add(&*name);
116 let comp_dir = dwarf.strings.add(&*comp_dir);
118 let root = dwarf.unit.root();
119 let root = dwarf.unit.get_mut(root);
121 gimli::DW_AT_producer,
122 AttributeValue::StringRef(dwarf.strings.add(producer)),
125 gimli::DW_AT_language,
126 AttributeValue::Language(gimli::DW_LANG_Rust),
128 root.set(gimli::DW_AT_name, AttributeValue::StringRef(name));
129 root.set(gimli::DW_AT_comp_dir, AttributeValue::StringRef(comp_dir));
132 AttributeValue::Address(Address::Constant(0)),
139 endian: target_endian(tcx),
140 symbols: indexmap::IndexMap::new(),
143 unit_range_list: RangeList(Vec::new()),
145 types: HashMap::new(),
149 fn emit_location(&mut self, entry_id: UnitEntryId, span: Span) {
150 let loc = self.tcx.sess.source_map().lookup_char_pos(span.lo());
152 let file_id = line_program_add_file(
153 &mut self.dwarf.unit.line_program,
154 &mut self.dwarf.line_strings,
158 let entry = self.dwarf.unit.get_mut(entry_id);
161 gimli::DW_AT_decl_file,
162 AttributeValue::FileIndex(Some(file_id)),
165 gimli::DW_AT_decl_line,
166 AttributeValue::Udata(loc.line as u64),
168 // FIXME: probably omit this
170 gimli::DW_AT_decl_column,
171 AttributeValue::Udata(loc.col.to_usize() as u64),
175 fn dwarf_ty(&mut self, ty: Ty<'tcx>) -> UnitEntryId {
176 if let Some(type_id) = self.types.get(ty) {
180 let new_entry = |dwarf: &mut DwarfUnit, tag| {
181 dwarf.unit.add(dwarf.unit.root(), tag)
184 let primtive = |dwarf: &mut DwarfUnit, ate| {
185 let type_id = new_entry(dwarf, gimli::DW_TAG_base_type);
186 let type_entry = dwarf.unit.get_mut(type_id);
187 type_entry.set(gimli::DW_AT_encoding, AttributeValue::Encoding(ate));
191 let type_id = match ty.kind {
192 ty::Bool => primtive(&mut self.dwarf, gimli::DW_ATE_boolean),
193 ty::Char => primtive(&mut self.dwarf, gimli::DW_ATE_UTF),
194 ty::Uint(_) => primtive(&mut self.dwarf, gimli::DW_ATE_unsigned),
195 ty::Int(_) => primtive(&mut self.dwarf, gimli::DW_ATE_signed),
196 ty::Float(_) => primtive(&mut self.dwarf, gimli::DW_ATE_float),
197 ty::Ref(_, pointee_ty, mutbl) | ty::RawPtr(ty::TypeAndMut { ty: pointee_ty, mutbl }) => {
198 let type_id = new_entry(&mut self.dwarf, gimli::DW_TAG_pointer_type);
200 // Ensure that type is inserted before recursing to avoid duplicates
201 self.types.insert(ty, type_id);
203 let pointee = self.dwarf_ty(pointee_ty);
205 let type_entry = self.dwarf.unit.get_mut(type_id);
207 //type_entry.set(gimli::DW_AT_mutable, AttributeValue::Flag(mutbl == rustc::hir::Mutability::MutMutable));
208 type_entry.set(gimli::DW_AT_type, AttributeValue::ThisUnitEntryRef(pointee));
212 _ => new_entry(&mut self.dwarf, gimli::DW_TAG_structure_type),
214 let name = format!("{}", ty);
215 let layout = self.tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap();
217 let type_entry = self.dwarf.unit.get_mut(type_id);
219 type_entry.set(gimli::DW_AT_name, AttributeValue::String(name.into_bytes()));
220 type_entry.set(gimli::DW_AT_byte_size, AttributeValue::Udata(layout.size.bytes()));
222 self.types.insert(ty, type_id);
227 pub fn emit<P: WriteDebugInfo>(&mut self, product: &mut P) {
228 let unit_range_list_id = self.dwarf.unit.ranges.add(self.unit_range_list.clone());
229 let root = self.dwarf.unit.root();
230 let root = self.dwarf.unit.get_mut(root);
233 AttributeValue::RangeListRef(unit_range_list_id),
236 let mut sections = Sections::new(WriterRelocate::new(self));
237 self.dwarf.write(&mut sections).unwrap();
239 let mut section_map = HashMap::new();
240 let _: Result<()> = sections.for_each_mut(|id, section| {
241 if !section.writer.slice().is_empty() {
242 let section_id = product.add_debug_section(id, section.writer.take());
243 section_map.insert(id, section_id);
248 let _: Result<()> = sections.for_each(|id, section| {
249 if let Some(section_id) = section_map.get(&id) {
250 for reloc in §ion.relocs {
251 product.add_debug_reloc(§ion_map, &self.symbols, section_id, reloc);
259 pub struct FunctionDebugContext<'a, 'tcx> {
260 debug_context: &'a mut DebugContext<'tcx>,
261 entry_id: UnitEntryId,
263 instance: Instance<'tcx>,
264 mir: &'tcx mir::Body<'tcx>,
267 impl<'a, 'tcx> FunctionDebugContext<'a, 'tcx> {
269 debug_context: &'a mut DebugContext<'tcx>,
270 instance: Instance<'tcx>,
275 let mir = debug_context.tcx.instance_mir(instance.def);
277 let (symbol, _) = debug_context.symbols.insert_full(func_id, name.to_string());
279 // FIXME: add to appropriate scope intead of root
280 let scope = debug_context.dwarf.unit.root();
282 let entry_id = debug_context
285 .add(scope, gimli::DW_TAG_subprogram);
286 let entry = debug_context.dwarf.unit.get_mut(entry_id);
287 let name_id = debug_context.dwarf.strings.add(name);
289 gimli::DW_AT_linkage_name,
290 AttributeValue::StringRef(name_id),
295 AttributeValue::Address(Address::Symbol { symbol, addend: 0 }),
298 debug_context.emit_location(entry_id, mir.span);
300 FunctionDebugContext {
312 isa: &dyn cranelift::codegen::isa::TargetIsa,
313 source_info_set: &indexmap::IndexSet<(Span, mir::SourceScope)>,
315 let tcx = self.debug_context.tcx;
317 let line_program = &mut self.debug_context.dwarf.unit.line_program;
319 line_program.begin_sequence(Some(Address::Symbol {
324 let encinfo = isa.encoding_info();
325 let func = &context.func;
326 let mut ebbs = func.layout.ebbs().collect::<Vec<_>>();
327 ebbs.sort_by_key(|ebb| func.offsets[*ebb]); // Ensure inst offsets always increase
329 let line_strings = &mut self.debug_context.dwarf.line_strings;
330 let mut create_row_for_span = |line_program: &mut LineProgram, span: Span| {
331 let loc = tcx.sess.source_map().lookup_char_pos(span.lo());
332 let file_id = line_program_add_file(line_program, line_strings, &loc.file.name);
335 "srcloc {:>04X} {}:{}:{}",
336 line_program.row().address_offset,
342 line_program.row().file = file_id;
343 line_program.row().line = loc.line as u64;
344 line_program.row().column = loc.col.to_u32() as u64 + 1;
345 line_program.generate_row();
350 for (offset, inst, size) in func.inst_offsets(ebb, &encinfo) {
351 let srcloc = func.srclocs[inst];
352 line_program.row().address_offset = offset as u64;
353 if !srcloc.is_default() {
354 let source_info = *source_info_set.get_index(srcloc.bits() as usize).unwrap();
355 create_row_for_span(line_program, source_info.0);
357 create_row_for_span(line_program, self.mir.span);
363 line_program.end_sequence(end as u64);
365 let entry = self.debug_context.dwarf.unit.get_mut(self.entry_id);
366 entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(end as u64));
369 let value_labels_ranges = context.build_value_labels_ranges(isa).unwrap();
371 for (value_label, value_loc_ranges) in value_labels_ranges.iter() {
372 let live_ranges = RangeList(
373 Some(Range::BaseAddress {
374 address: Address::Symbol {
383 .map(|val_loc_range| Range::OffsetPair {
384 begin: u64::from(val_loc_range.start),
385 end: u64::from(val_loc_range.end),
390 let live_ranges_id = self.debug_context.dwarf.unit.ranges.add(live_ranges);
392 let local_ty = tcx.subst_and_normalize_erasing_regions(
393 self.instance.substs,
394 ty::ParamEnv::reveal_all(),
395 &self.mir.local_decls[mir::Local::from_u32(value_label.as_u32())].ty,
397 let local_type = self.debug_context.dwarf_ty(local_ty);
403 .add(self.entry_id, gimli::DW_TAG_variable);
404 let var_entry = self.debug_context.dwarf.unit.get_mut(var_id);
408 AttributeValue::RangeListRef(live_ranges_id),
412 AttributeValue::String(format!("{:?}", value_label).into_bytes()),
416 AttributeValue::ThisUnitEntryRef(local_type),
424 .push(Range::StartLength {
425 begin: Address::Symbol {
435 struct WriterRelocate {
436 relocs: Vec<DebugReloc>,
437 writer: EndianVec<RunTimeEndian>,
440 impl WriterRelocate {
441 fn new(ctx: &DebugContext) -> Self {
444 writer: EndianVec::new(ctx.endian),
449 impl Writer for WriterRelocate {
450 type Endian = RunTimeEndian;
452 fn endian(&self) -> Self::Endian {
456 fn len(&self) -> usize {
460 fn write(&mut self, bytes: &[u8]) -> Result<()> {
461 self.writer.write(bytes)
464 fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> {
465 self.writer.write_at(offset, bytes)
468 fn write_address(&mut self, address: Address, size: u8) -> Result<()> {
470 Address::Constant(val) => self.write_udata(val, size),
471 Address::Symbol { symbol, addend } => {
472 let offset = self.len() as u64;
473 self.relocs.push(DebugReloc {
474 offset: offset as u32,
476 name: DebugRelocName::Symbol(symbol),
477 addend: addend as i64,
479 self.write_udata(0, size)
484 // TODO: implement write_eh_pointer
486 fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> Result<()> {
487 let offset = self.len() as u32;
488 self.relocs.push(DebugReloc {
491 name: DebugRelocName::Section(section),
494 self.write_udata(0, size)
504 self.relocs.push(DebugReloc {
505 offset: offset as u32,
507 name: DebugRelocName::Section(section),
510 self.write_udata_at(offset, 0, size)