wasmtime_cranelift/debug/
write_debuginfo.rs

1pub 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}