]>
Commit | Line | Data |
---|---|---|
29967ef6 XL |
1 | //! Write the debuginfo into an object file. |
2 | ||
3 | use rustc_data_structures::fx::FxHashMap; | |
4 | ||
5 | use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer}; | |
6 | use gimli::{RunTimeEndian, SectionId}; | |
7 | ||
8 | use crate::backend::WriteDebugInfo; | |
9 | ||
10 | use super::DebugContext; | |
11 | ||
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); | |
6a06907d | 17 | root.set(gimli::DW_AT_ranges, AttributeValue::RangeListRef(unit_range_list_id)); |
29967ef6 XL |
18 | |
19 | let mut sections = Sections::new(WriterRelocate::new(self.endian)); | |
20 | self.dwarf.write(&mut sections).unwrap(); | |
21 | ||
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); | |
27 | } | |
28 | Ok(()) | |
29 | }); | |
30 | ||
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); | |
35 | } | |
36 | } | |
37 | Ok(()) | |
38 | }); | |
39 | } | |
40 | } | |
41 | ||
42 | #[derive(Clone)] | |
43 | pub(crate) struct DebugReloc { | |
44 | pub(crate) offset: u32, | |
45 | pub(crate) size: u8, | |
46 | pub(crate) name: DebugRelocName, | |
47 | pub(crate) addend: i64, | |
48 | pub(crate) kind: object::RelocationKind, | |
49 | } | |
50 | ||
51 | #[derive(Clone)] | |
52 | pub(crate) enum DebugRelocName { | |
53 | Section(SectionId), | |
54 | Symbol(usize), | |
55 | } | |
56 | ||
57 | /// A [`Writer`] that collects all necessary relocations. | |
58 | #[derive(Clone)] | |
59 | pub(super) struct WriterRelocate { | |
60 | pub(super) relocs: Vec<DebugReloc>, | |
61 | pub(super) writer: EndianVec<RunTimeEndian>, | |
62 | } | |
63 | ||
64 | impl WriterRelocate { | |
65 | pub(super) fn new(endian: RunTimeEndian) -> Self { | |
6a06907d | 66 | WriterRelocate { relocs: Vec::new(), writer: EndianVec::new(endian) } |
29967ef6 XL |
67 | } |
68 | ||
69 | /// Perform the collected relocations to be usable for JIT usage. | |
70 | #[cfg(feature = "jit")] | |
5869c6ff | 71 | pub(super) fn relocate_for_jit(mut self, jit_module: &cranelift_jit::JITModule) -> Vec<u8> { |
29967ef6 XL |
72 | use std::convert::TryInto; |
73 | ||
74 | for reloc in self.relocs.drain(..) { | |
75 | match reloc.name { | |
76 | super::DebugRelocName::Section(_) => unreachable!(), | |
77 | super::DebugRelocName::Symbol(sym) => { | |
fc512014 XL |
78 | let addr = jit_module.get_finalized_function( |
79 | cranelift_module::FuncId::from_u32(sym.try_into().unwrap()), | |
80 | ); | |
29967ef6 | 81 | let val = (addr as u64 as i64 + reloc.addend) as u64; |
6a06907d | 82 | self.writer.write_udata_at(reloc.offset as usize, val, reloc.size).unwrap(); |
29967ef6 XL |
83 | } |
84 | } | |
85 | } | |
86 | self.writer.into_vec() | |
87 | } | |
88 | } | |
89 | ||
90 | impl Writer for WriterRelocate { | |
91 | type Endian = RunTimeEndian; | |
92 | ||
93 | fn endian(&self) -> Self::Endian { | |
94 | self.writer.endian() | |
95 | } | |
96 | ||
97 | fn len(&self) -> usize { | |
98 | self.writer.len() | |
99 | } | |
100 | ||
101 | fn write(&mut self, bytes: &[u8]) -> Result<()> { | |
102 | self.writer.write(bytes) | |
103 | } | |
104 | ||
105 | fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> { | |
106 | self.writer.write_at(offset, bytes) | |
107 | } | |
108 | ||
109 | fn write_address(&mut self, address: Address, size: u8) -> Result<()> { | |
110 | match address { | |
111 | Address::Constant(val) => self.write_udata(val, size), | |
112 | Address::Symbol { symbol, addend } => { | |
113 | let offset = self.len() as u64; | |
114 | self.relocs.push(DebugReloc { | |
115 | offset: offset as u32, | |
116 | size, | |
117 | name: DebugRelocName::Symbol(symbol), | |
118 | addend: addend as i64, | |
119 | kind: object::RelocationKind::Absolute, | |
120 | }); | |
121 | self.write_udata(0, size) | |
122 | } | |
123 | } | |
124 | } | |
125 | ||
126 | fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> Result<()> { | |
127 | let offset = self.len() as u32; | |
128 | self.relocs.push(DebugReloc { | |
129 | offset, | |
130 | size, | |
131 | name: DebugRelocName::Section(section), | |
132 | addend: val as i64, | |
133 | kind: object::RelocationKind::Absolute, | |
134 | }); | |
135 | self.write_udata(0, size) | |
136 | } | |
137 | ||
138 | fn write_offset_at( | |
139 | &mut self, | |
140 | offset: usize, | |
141 | val: usize, | |
142 | section: SectionId, | |
143 | size: u8, | |
144 | ) -> Result<()> { | |
145 | self.relocs.push(DebugReloc { | |
146 | offset: offset as u32, | |
147 | size, | |
148 | name: DebugRelocName::Section(section), | |
149 | addend: val as i64, | |
150 | kind: object::RelocationKind::Absolute, | |
151 | }); | |
152 | self.write_udata_at(offset, 0, size) | |
153 | } | |
154 | ||
155 | fn write_eh_pointer(&mut self, address: Address, eh_pe: gimli::DwEhPe, size: u8) -> Result<()> { | |
156 | match address { | |
157 | // Address::Constant arm copied from gimli | |
158 | Address::Constant(val) => { | |
159 | // Indirect doesn't matter here. | |
160 | let val = match eh_pe.application() { | |
161 | gimli::DW_EH_PE_absptr => val, | |
162 | gimli::DW_EH_PE_pcrel => { | |
163 | // TODO: better handling of sign | |
164 | let offset = self.len() as u64; | |
165 | offset.wrapping_sub(val) | |
166 | } | |
167 | _ => { | |
168 | return Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)); | |
169 | } | |
170 | }; | |
171 | self.write_eh_pointer_data(val, eh_pe.format(), size) | |
172 | } | |
173 | Address::Symbol { symbol, addend } => match eh_pe.application() { | |
174 | gimli::DW_EH_PE_pcrel => { | |
175 | let size = match eh_pe.format() { | |
176 | gimli::DW_EH_PE_sdata4 => 4, | |
177 | _ => return Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)), | |
178 | }; | |
179 | self.relocs.push(DebugReloc { | |
180 | offset: self.len() as u32, | |
181 | size, | |
182 | name: DebugRelocName::Symbol(symbol), | |
183 | addend, | |
184 | kind: object::RelocationKind::Relative, | |
185 | }); | |
186 | self.write_udata(0, size) | |
187 | } | |
188 | _ => Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)), | |
189 | }, | |
190 | } | |
191 | } | |
192 | } |