wasmtime_debug/
write_debuginfo.rs

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