1 //! Write the debuginfo into an object file.
3 use cranelift_object::ObjectProduct;
4 use rustc_data_structures::fx::FxHashMap;
6 use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer};
7 use gimli::{RunTimeEndian, SectionId};
9 use super::object::WriteDebugInfo;
10 use super::DebugContext;
13 pub(crate) fn emit(&mut self, product: &mut ObjectProduct) {
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);
17 root.set(gimli::DW_AT_ranges, AttributeValue::RangeListRef(unit_range_list_id));
19 let mut sections = Sections::new(WriterRelocate::new(self.endian));
20 self.dwarf.write(&mut sections).unwrap();
22 let mut section_map = FxHashMap::default();
23 let _: Result<()> = sections.for_each_mut(|id, section| {
24 if !section.writer.slice().is_empty() {
25 let section_id = product.add_debug_section(id, section.writer.take());
26 section_map.insert(id, section_id);
31 let _: Result<()> = sections.for_each(|id, section| {
32 if let Some(section_id) = section_map.get(&id) {
33 for reloc in §ion.relocs {
34 product.add_debug_reloc(§ion_map, section_id, reloc);
43 pub(crate) struct DebugReloc {
44 pub(crate) offset: u32,
46 pub(crate) name: DebugRelocName,
47 pub(crate) addend: i64,
48 pub(crate) kind: object::RelocationKind,
52 pub(crate) enum DebugRelocName {
57 /// A [`Writer`] that collects all necessary relocations.
59 pub(super) struct WriterRelocate {
60 pub(super) relocs: Vec<DebugReloc>,
61 pub(super) writer: EndianVec<RunTimeEndian>,
65 pub(super) fn new(endian: RunTimeEndian) -> Self {
66 WriterRelocate { relocs: Vec::new(), writer: EndianVec::new(endian) }
69 /// Perform the collected relocations to be usable for JIT usage.
70 #[cfg(all(feature = "jit", not(windows)))]
71 pub(super) fn relocate_for_jit(mut self, jit_module: &cranelift_jit::JITModule) -> Vec<u8> {
72 for reloc in self.relocs.drain(..) {
74 super::DebugRelocName::Section(_) => unreachable!(),
75 super::DebugRelocName::Symbol(sym) => {
76 let addr = jit_module.get_finalized_function(
77 cranelift_module::FuncId::from_u32(sym.try_into().unwrap()),
79 let val = (addr as u64 as i64 + reloc.addend) as u64;
80 self.writer.write_udata_at(reloc.offset as usize, val, reloc.size).unwrap();
84 self.writer.into_vec()
88 impl Writer for WriterRelocate {
89 type Endian = RunTimeEndian;
91 fn endian(&self) -> Self::Endian {
95 fn len(&self) -> usize {
99 fn write(&mut self, bytes: &[u8]) -> Result<()> {
100 self.writer.write(bytes)
103 fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> {
104 self.writer.write_at(offset, bytes)
107 fn write_address(&mut self, address: Address, size: u8) -> Result<()> {
109 Address::Constant(val) => self.write_udata(val, size),
110 Address::Symbol { symbol, addend } => {
111 let offset = self.len() as u64;
112 self.relocs.push(DebugReloc {
113 offset: offset as u32,
115 name: DebugRelocName::Symbol(symbol),
116 addend: addend as i64,
117 kind: object::RelocationKind::Absolute,
119 self.write_udata(0, size)
124 fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> Result<()> {
125 let offset = self.len() as u32;
126 self.relocs.push(DebugReloc {
129 name: DebugRelocName::Section(section),
131 kind: object::RelocationKind::Absolute,
133 self.write_udata(0, size)
143 self.relocs.push(DebugReloc {
144 offset: offset as u32,
146 name: DebugRelocName::Section(section),
148 kind: object::RelocationKind::Absolute,
150 self.write_udata_at(offset, 0, size)
153 fn write_eh_pointer(&mut self, address: Address, eh_pe: gimli::DwEhPe, size: u8) -> Result<()> {
155 // Address::Constant arm copied from gimli
156 Address::Constant(val) => {
157 // Indirect doesn't matter here.
158 let val = match eh_pe.application() {
159 gimli::DW_EH_PE_absptr => val,
160 gimli::DW_EH_PE_pcrel => {
161 // FIXME better handling of sign
162 let offset = self.len() as u64;
163 offset.wrapping_sub(val)
166 return Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe));
169 self.write_eh_pointer_data(val, eh_pe.format(), size)
171 Address::Symbol { symbol, addend } => match eh_pe.application() {
172 gimli::DW_EH_PE_pcrel => {
173 let size = match eh_pe.format() {
174 gimli::DW_EH_PE_sdata4 => 4,
175 _ => return Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)),
177 self.relocs.push(DebugReloc {
178 offset: self.len() as u32,
180 name: DebugRelocName::Symbol(symbol),
182 kind: object::RelocationKind::Relative,
184 self.write_udata(0, size)
186 _ => Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)),