1 //! Write the debuginfo into an object file.
3 use rustc_data_structures::fx::FxHashMap;
5 use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer};
6 use gimli::{RunTimeEndian, SectionId};
8 use crate::backend::WriteDebugInfo;
10 use super::DebugContext;
12 impl DebugContext<'_> {
13 pub(crate) fn emit<P: WriteDebugInfo>(&mut self, product: &mut P) {
14 let unit_range_list_id = self.dwarf.unit.ranges.add(self.unit_range_list.clone());
15 let root = self.dwarf.unit.root();
16 let root = self.dwarf.unit.get_mut(root);
19 AttributeValue::RangeListRef(unit_range_list_id),
22 let mut sections = Sections::new(WriterRelocate::new(self.endian));
23 self.dwarf.write(&mut sections).unwrap();
25 let mut section_map = FxHashMap::default();
26 let _: Result<()> = sections.for_each_mut(|id, section| {
27 if !section.writer.slice().is_empty() {
28 let section_id = product.add_debug_section(id, section.writer.take());
29 section_map.insert(id, section_id);
34 let _: Result<()> = sections.for_each(|id, section| {
35 if let Some(section_id) = section_map.get(&id) {
36 for reloc in §ion.relocs {
37 product.add_debug_reloc(§ion_map, section_id, reloc);
46 pub(crate) struct DebugReloc {
47 pub(crate) offset: u32,
49 pub(crate) name: DebugRelocName,
50 pub(crate) addend: i64,
51 pub(crate) kind: object::RelocationKind,
55 pub(crate) enum DebugRelocName {
60 /// A [`Writer`] that collects all necessary relocations.
62 pub(super) struct WriterRelocate {
63 pub(super) relocs: Vec<DebugReloc>,
64 pub(super) writer: EndianVec<RunTimeEndian>,
68 pub(super) fn new(endian: RunTimeEndian) -> Self {
71 writer: EndianVec::new(endian),
75 /// Perform the collected relocations to be usable for JIT usage.
76 #[cfg(feature = "jit")]
77 pub(super) fn relocate_for_jit(
79 jit_product: &cranelift_simplejit::SimpleJITProduct,
81 use std::convert::TryInto;
83 for reloc in self.relocs.drain(..) {
85 super::DebugRelocName::Section(_) => unreachable!(),
86 super::DebugRelocName::Symbol(sym) => {
87 let addr = jit_product
88 .lookup_func(cranelift_module::FuncId::from_u32(sym.try_into().unwrap()));
89 let val = (addr as u64 as i64 + reloc.addend) as u64;
91 .write_udata_at(reloc.offset as usize, val, reloc.size)
96 self.writer.into_vec()
100 impl Writer for WriterRelocate {
101 type Endian = RunTimeEndian;
103 fn endian(&self) -> Self::Endian {
107 fn len(&self) -> usize {
111 fn write(&mut self, bytes: &[u8]) -> Result<()> {
112 self.writer.write(bytes)
115 fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> {
116 self.writer.write_at(offset, bytes)
119 fn write_address(&mut self, address: Address, size: u8) -> Result<()> {
121 Address::Constant(val) => self.write_udata(val, size),
122 Address::Symbol { symbol, addend } => {
123 let offset = self.len() as u64;
124 self.relocs.push(DebugReloc {
125 offset: offset as u32,
127 name: DebugRelocName::Symbol(symbol),
128 addend: addend as i64,
129 kind: object::RelocationKind::Absolute,
131 self.write_udata(0, size)
136 fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> Result<()> {
137 let offset = self.len() as u32;
138 self.relocs.push(DebugReloc {
141 name: DebugRelocName::Section(section),
143 kind: object::RelocationKind::Absolute,
145 self.write_udata(0, size)
155 self.relocs.push(DebugReloc {
156 offset: offset as u32,
158 name: DebugRelocName::Section(section),
160 kind: object::RelocationKind::Absolute,
162 self.write_udata_at(offset, 0, size)
165 fn write_eh_pointer(&mut self, address: Address, eh_pe: gimli::DwEhPe, size: u8) -> Result<()> {
167 // Address::Constant arm copied from gimli
168 Address::Constant(val) => {
169 // Indirect doesn't matter here.
170 let val = match eh_pe.application() {
171 gimli::DW_EH_PE_absptr => val,
172 gimli::DW_EH_PE_pcrel => {
173 // TODO: better handling of sign
174 let offset = self.len() as u64;
175 offset.wrapping_sub(val)
178 return Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe));
181 self.write_eh_pointer_data(val, eh_pe.format(), size)
183 Address::Symbol { symbol, addend } => match eh_pe.application() {
184 gimli::DW_EH_PE_pcrel => {
185 let size = match eh_pe.format() {
186 gimli::DW_EH_PE_sdata4 => 4,
187 _ => return Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)),
189 self.relocs.push(DebugReloc {
190 offset: self.len() as u32,
192 name: DebugRelocName::Symbol(symbol),
194 kind: object::RelocationKind::Relative,
196 self.write_udata(0, size)
198 _ => Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)),