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