wasm_debug/
write_debuginfo.rs

1use faerie::artifact::{Decl, SectionKind};
2use faerie::*;
3use gimli::write::{Address, Dwarf, EndianVec, Result, Sections, Writer};
4use gimli::{RunTimeEndian, SectionId};
5
6#[derive(Clone)]
7struct DebugReloc {
8    offset: u32,
9    size: u8,
10    name: String,
11    addend: i64,
12}
13
14pub enum ResolvedSymbol {
15    PhysicalAddress(u64),
16    Reloc { name: String, addend: i64 },
17}
18
19pub trait SymbolResolver {
20    fn resolve_symbol(&self, symbol: usize, addend: i64) -> ResolvedSymbol;
21}
22
23pub fn emit_dwarf(
24    artifact: &mut Artifact,
25    mut dwarf: Dwarf,
26    symbol_resolver: &dyn SymbolResolver,
27) -> anyhow::Result<()> {
28    let endian = RunTimeEndian::Little;
29
30    let mut sections = Sections::new(WriterRelocate::new(endian, symbol_resolver));
31    dwarf.write(&mut sections)?;
32    sections.for_each_mut(|id, s| -> anyhow::Result<()> {
33        artifact.declare_with(
34            id.name(),
35            Decl::section(SectionKind::Debug),
36            s.writer.take(),
37        )
38    })?;
39    sections.for_each_mut(|id, s| -> anyhow::Result<()> {
40        for reloc in &s.relocs {
41            artifact.link_with(
42                faerie::Link {
43                    from: id.name(),
44                    to: &reloc.name,
45                    at: u64::from(reloc.offset),
46                },
47                faerie::Reloc::Debug {
48                    size: reloc.size,
49                    addend: reloc.addend as i32,
50                },
51            )?;
52        }
53        Ok(())
54    })?;
55    Ok(())
56}
57
58#[derive(Clone)]
59pub struct WriterRelocate<'a> {
60    relocs: Vec<DebugReloc>,
61    writer: EndianVec<RunTimeEndian>,
62    symbol_resolver: &'a dyn SymbolResolver,
63}
64
65impl<'a> WriterRelocate<'a> {
66    pub fn new(endian: RunTimeEndian, symbol_resolver: &'a dyn SymbolResolver) -> Self {
67        WriterRelocate {
68            relocs: Vec::new(),
69            writer: EndianVec::new(endian),
70            symbol_resolver,
71        }
72    }
73}
74
75impl<'a> Writer for WriterRelocate<'a> {
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                match self.symbol_resolver.resolve_symbol(symbol, addend as i64) {
99                    ResolvedSymbol::PhysicalAddress(addr) => self.write_udata(addr, size),
100                    ResolvedSymbol::Reloc { name, addend } => {
101                        let offset = self.len() as u64;
102                        self.relocs.push(DebugReloc {
103                            offset: offset as u32,
104                            size,
105                            name,
106                            addend,
107                        });
108                        self.write_udata(addend as u64, size)
109                    }
110                }
111            }
112        }
113    }
114
115    fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> Result<()> {
116        let offset = self.len() as u32;
117        let name = section.name().to_string();
118        self.relocs.push(DebugReloc {
119            offset,
120            size,
121            name,
122            addend: val as i64,
123        });
124        self.write_udata(val as u64, size)
125    }
126
127    fn write_offset_at(
128        &mut self,
129        offset: usize,
130        val: usize,
131        section: SectionId,
132        size: u8,
133    ) -> Result<()> {
134        let name = section.name().to_string();
135        self.relocs.push(DebugReloc {
136            offset: offset as u32,
137            size,
138            name,
139            addend: val as i64,
140        });
141        self.write_udata_at(offset, val as u64, size)
142    }
143}