]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
Rollup merge of #78354 - 12101111:rustbuild_profiler, r=Mark-Simulacrum
[rust.git] / compiler / rustc_codegen_cranelift / src / debuginfo / emit.rs
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);
17         root.set(
18             gimli::DW_AT_ranges,
19             AttributeValue::RangeListRef(unit_range_list_id),
20         );
21
22         let mut sections = Sections::new(WriterRelocate::new(self.endian));
23         self.dwarf.write(&mut sections).unwrap();
24
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);
30             }
31             Ok(())
32         });
33
34         let _: Result<()> = sections.for_each(|id, section| {
35             if let Some(section_id) = section_map.get(&id) {
36                 for reloc in &section.relocs {
37                     product.add_debug_reloc(&section_map, section_id, reloc);
38                 }
39             }
40             Ok(())
41         });
42     }
43 }
44
45 #[derive(Clone)]
46 pub(crate) struct DebugReloc {
47     pub(crate) offset: u32,
48     pub(crate) size: u8,
49     pub(crate) name: DebugRelocName,
50     pub(crate) addend: i64,
51     pub(crate) kind: object::RelocationKind,
52 }
53
54 #[derive(Clone)]
55 pub(crate) enum DebugRelocName {
56     Section(SectionId),
57     Symbol(usize),
58 }
59
60 /// A [`Writer`] that collects all necessary relocations.
61 #[derive(Clone)]
62 pub(super) struct WriterRelocate {
63     pub(super) relocs: Vec<DebugReloc>,
64     pub(super) writer: EndianVec<RunTimeEndian>,
65 }
66
67 impl WriterRelocate {
68     pub(super) fn new(endian: RunTimeEndian) -> Self {
69         WriterRelocate {
70             relocs: Vec::new(),
71             writer: EndianVec::new(endian),
72         }
73     }
74
75     /// Perform the collected relocations to be usable for JIT usage.
76     #[cfg(feature = "jit")]
77     pub(super) fn relocate_for_jit(
78         mut self,
79         jit_product: &cranelift_simplejit::SimpleJITProduct,
80     ) -> Vec<u8> {
81         use std::convert::TryInto;
82
83         for reloc in self.relocs.drain(..) {
84             match reloc.name {
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;
90                     self.writer
91                         .write_udata_at(reloc.offset as usize, val, reloc.size)
92                         .unwrap();
93                 }
94             }
95         }
96         self.writer.into_vec()
97     }
98 }
99
100 impl Writer for WriterRelocate {
101     type Endian = RunTimeEndian;
102
103     fn endian(&self) -> Self::Endian {
104         self.writer.endian()
105     }
106
107     fn len(&self) -> usize {
108         self.writer.len()
109     }
110
111     fn write(&mut self, bytes: &[u8]) -> Result<()> {
112         self.writer.write(bytes)
113     }
114
115     fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> {
116         self.writer.write_at(offset, bytes)
117     }
118
119     fn write_address(&mut self, address: Address, size: u8) -> Result<()> {
120         match address {
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,
126                     size,
127                     name: DebugRelocName::Symbol(symbol),
128                     addend: addend as i64,
129                     kind: object::RelocationKind::Absolute,
130                 });
131                 self.write_udata(0, size)
132             }
133         }
134     }
135
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 {
139             offset,
140             size,
141             name: DebugRelocName::Section(section),
142             addend: val as i64,
143             kind: object::RelocationKind::Absolute,
144         });
145         self.write_udata(0, size)
146     }
147
148     fn write_offset_at(
149         &mut self,
150         offset: usize,
151         val: usize,
152         section: SectionId,
153         size: u8,
154     ) -> Result<()> {
155         self.relocs.push(DebugReloc {
156             offset: offset as u32,
157             size,
158             name: DebugRelocName::Section(section),
159             addend: val as i64,
160             kind: object::RelocationKind::Absolute,
161         });
162         self.write_udata_at(offset, 0, size)
163     }
164
165     fn write_eh_pointer(&mut self, address: Address, eh_pe: gimli::DwEhPe, size: u8) -> Result<()> {
166         match address {
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)
176                     }
177                     _ => {
178                         return Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe));
179                     }
180                 };
181                 self.write_eh_pointer_data(val, eh_pe.format(), size)
182             }
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)),
188                     };
189                     self.relocs.push(DebugReloc {
190                         offset: self.len() as u32,
191                         size,
192                         name: DebugRelocName::Symbol(symbol),
193                         addend,
194                         kind: object::RelocationKind::Relative,
195                     });
196                     self.write_udata(0, size)
197                 }
198                 _ => Err(gimli::write::Error::UnsupportedPointerEncoding(eh_pe)),
199             },
200         }
201     }
202 }