wasm_debug/
write_debuginfo.rs1use 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}