1 pub use crate::debug::transform::transform_dwarf;
2 use crate::CompiledFunctions;
3 use cranelift_codegen::ir::Endianness;
4 use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa};
5 use cranelift_entity::EntityRef;
6 use gimli::write::{Address, Dwarf, EndianVec, FrameTable, Result, Sections, Writer};
7 use gimli::{RunTimeEndian, SectionId};
8 use wasmtime_environ::{DebugInfoData, ModuleMemoryOffset};
9 
10 #[allow(missing_docs)]
11 pub struct DwarfSection {
12     pub name: &'static str,
13     pub body: Vec<u8>,
14     pub relocs: Vec<DwarfSectionReloc>,
15 }
16 
17 #[allow(missing_docs)]
18 #[derive(Clone)]
19 pub struct DwarfSectionReloc {
20     pub target: DwarfSectionRelocTarget,
21     pub offset: u32,
22     pub addend: i32,
23     pub size: u8,
24 }
25 
26 #[allow(missing_docs)]
27 #[derive(Clone)]
28 pub enum DwarfSectionRelocTarget {
29     Func(usize),
30     Section(&'static str),
31 }
32 
33 fn emit_dwarf_sections(
34     isa: &dyn TargetIsa,
35     mut dwarf: Dwarf,
36     frames: Option<FrameTable>,
37 ) -> anyhow::Result<Vec<DwarfSection>> {
38     let endian = match isa.endianness() {
39         Endianness::Little => RunTimeEndian::Little,
40         Endianness::Big => RunTimeEndian::Big,
41     };
42     let writer = WriterRelocate {
43         relocs: Vec::new(),
44         writer: EndianVec::new(endian),
45     };
46     let mut sections = Sections::new(writer);
47     dwarf.write(&mut sections)?;
48     if let Some(frames) = frames {
49         frames.write_debug_frame(&mut sections.debug_frame)?;
50     }
51 
52     let mut result = Vec::new();
53     sections.for_each_mut(|id, s| -> anyhow::Result<()> {
54         let name = id.name();
55         let body = s.writer.take();
56         let mut relocs = vec![];
57         ::std::mem::swap(&mut relocs, &mut s.relocs);
58         result.push(DwarfSection { name, body, relocs });
59         Ok(())
60     })?;
61 
62     Ok(result)
63 }
64 
65 #[derive(Clone)]
66 pub struct WriterRelocate {
67     relocs: Vec<DwarfSectionReloc>,
68     writer: EndianVec<RunTimeEndian>,
69 }
70 
71 impl Writer for WriterRelocate {
72     type Endian = RunTimeEndian;
73 
74     fn endian(&self) -> Self::Endian {
75         self.writer.endian()
76     }
77 
78     fn len(&self) -> usize {
79         self.writer.len()
80     }
81 
82     fn write(&mut self, bytes: &[u8]) -> Result<()> {
83         self.writer.write(bytes)
84     }
85 
86     fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> {
87         self.writer.write_at(offset, bytes)
88     }
89 
90     fn write_address(&mut self, address: Address, size: u8) -> Result<()> {
91         match address {
92             Address::Constant(val) => self.write_udata(val, size),
93             Address::Symbol { symbol, addend } => {
94                 let offset = self.len() as u32;
95                 self.relocs.push(DwarfSectionReloc {
96                     target: DwarfSectionRelocTarget::Func(symbol),
97                     offset,
98                     size,
99                     addend: addend as i32,
100                 });
101                 self.write_udata(addend as u64, size)
102             }
103         }
104     }
105 
106     fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> Result<()> {
107         let offset = self.len() as u32;
108         let target = DwarfSectionRelocTarget::Section(section.name());
109         self.relocs.push(DwarfSectionReloc {
110             target,
111             offset,
112             size,
113             addend: val as i32,
114         });
115         self.write_udata(val as u64, size)
116     }
117 
118     fn write_offset_at(
119         &mut self,
120         offset: usize,
121         val: usize,
122         section: SectionId,
123         size: u8,
124     ) -> Result<()> {
125         let target = DwarfSectionRelocTarget::Section(section.name());
126         self.relocs.push(DwarfSectionReloc {
127             target,
128             offset: offset as u32,
129             size,
130             addend: val as i32,
131         });
132         self.write_udata_at(offset, val as u64, size)
133     }
134 }
135 
136 fn create_frame_table<'a>(isa: &dyn TargetIsa, funcs: &CompiledFunctions) -> Option<FrameTable> {
137     let mut table = FrameTable::default();
138 
139     let cie_id = table.add_cie(isa.create_systemv_cie()?);
140 
141     for (i, f) in funcs {
142         if let Some(UnwindInfo::SystemV(info)) = &f.unwind_info {
143             table.add_fde(
144                 cie_id,
145                 info.to_fde(Address::Symbol {
146                     symbol: i.index(),
147                     addend: 0,
148                 }),
149             );
150         }
151     }
152 
153     Some(table)
154 }
155 
156 pub fn emit_dwarf<'a>(
157     isa: &dyn TargetIsa,
158     debuginfo_data: &DebugInfoData,
159     funcs: &CompiledFunctions,
160     memory_offset: &ModuleMemoryOffset,
161 ) -> anyhow::Result<Vec<DwarfSection>> {
162     let dwarf = transform_dwarf(isa, debuginfo_data, funcs, memory_offset)?;
163     let frame_table = create_frame_table(isa, funcs);
164     let sections = emit_dwarf_sections(isa, dwarf, frame_table)?;
165     Ok(sections)
166 }
167