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