]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
Auto merge of #87820 - elichai:patch-2, r=kennytm
[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(gimli::DW_AT_ranges, AttributeValue::RangeListRef(unit_range_list_id));
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 &section.relocs {
34                     product.add_debug_reloc(&section_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 {
66         WriterRelocate { relocs: Vec::new(), writer: EndianVec::new(endian) }
67     }
68
69     /// Perform the collected relocations to be usable for JIT usage.
70     #[cfg(feature = "jit")]
71     pub(super) fn relocate_for_jit(mut self, jit_module: &cranelift_jit::JITModule) -> Vec<u8> {
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) => {
78                     let addr = jit_module.get_finalized_function(
79                         cranelift_module::FuncId::from_u32(sym.try_into().unwrap()),
80                     );
81                     let val = (addr as u64 as i64 + reloc.addend) as u64;
82                     self.writer.write_udata_at(reloc.offset as usize, val, reloc.size).unwrap();
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                         // FIXME 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 }