1 use crate::debug::Compilation;
2 pub use crate::debug::transform::transform_dwarf;
3 use cranelift_codegen::ir::Endianness;
4 use cranelift_codegen::isa::{
5 TargetIsa,
6 unwind::{CfaUnwindInfo, UnwindInfo},
7 };
8 use gimli::write::{
9 Address, Dwarf, EndianVec, FrameTable, Result as WriteResult, Sections, Writer,
10 };
11 use gimli::{RunTimeEndian, SectionId};
12 use wasmtime_environ::error::Result as EnvResult;
13
14 pub struct DwarfSection {
15 pub name: &'static str,
16 pub body: Vec<u8>,
17 pub relocs: Vec<DwarfSectionReloc>,
18 }
19
20 #[derive(Clone)]
21 pub struct DwarfSectionReloc {
22 pub target: DwarfSectionRelocTarget,
23 pub offset: u32,
24 pub addend: i32,
25 pub size: u8,
26 }
27
28 #[derive(Clone)]
29 pub enum DwarfSectionRelocTarget {
30 Func(usize),
31 Section(&'static str),
32 }
33
emit_dwarf_sections( isa: &dyn TargetIsa, mut dwarf: Dwarf, frames: Option<FrameTable>, ) -> EnvResult<Vec<DwarfSection>>34 fn emit_dwarf_sections(
35 isa: &dyn TargetIsa,
36 mut dwarf: Dwarf,
37 frames: Option<FrameTable>,
38 ) -> EnvResult<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| -> EnvResult<()> {
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)]
70 pub struct WriterRelocate {
71 relocs: Vec<DwarfSectionReloc>,
72 writer: EndianVec<RunTimeEndian>,
73 }
74
75 impl Writer for WriterRelocate {
76 type Endian = RunTimeEndian;
77
endian(&self) -> Self::Endian78 fn endian(&self) -> Self::Endian {
79 self.writer.endian()
80 }
81
len(&self) -> usize82 fn len(&self) -> usize {
83 self.writer.len()
84 }
85
write(&mut self, bytes: &[u8]) -> WriteResult<()>86 fn write(&mut self, bytes: &[u8]) -> WriteResult<()> {
87 self.writer.write(bytes)
88 }
89
write_at(&mut self, offset: usize, bytes: &[u8]) -> WriteResult<()>90 fn write_at(&mut self, offset: usize, bytes: &[u8]) -> WriteResult<()> {
91 self.writer.write_at(offset, bytes)
92 }
93
write_address(&mut self, address: Address, size: u8) -> WriteResult<()>94 fn write_address(&mut self, address: Address, size: u8) -> WriteResult<()> {
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
write_offset(&mut self, val: usize, section: SectionId, size: u8) -> WriteResult<()>110 fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> WriteResult<()> {
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
write_offset_at( &mut self, offset: usize, val: usize, section: SectionId, size: u8, ) -> WriteResult<()>122 fn write_offset_at(
123 &mut self,
124 offset: usize,
125 val: usize,
126 section: SectionId,
127 size: u8,
128 ) -> WriteResult<()> {
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
create_frame_table( isa: &dyn TargetIsa, compilation: &mut Compilation<'_>, ) -> Option<FrameTable>140 fn create_frame_table(
141 isa: &dyn TargetIsa,
142 compilation: &mut Compilation<'_>,
143 ) -> Option<FrameTable> {
144 let mut table = FrameTable::default();
145
146 let cie_id = table.add_cie(isa.create_systemv_cie()?);
147
148 for (_, symbol, metadata) in compilation.functions() {
149 // The CFA-based unwind info will either be natively present, or we
150 // have generated it and placed into the "cfa_unwind_info" auxiliary
151 // field. We shouldn't emit both, though, it'd be wasteful.
152 let mut unwind_info: Option<&CfaUnwindInfo> = None;
153 if let Some(UnwindInfo::SystemV(info)) = &metadata.unwind_info {
154 debug_assert!(metadata.cfa_unwind_info.is_none());
155 unwind_info = Some(info);
156 } else if let Some(info) = &metadata.cfa_unwind_info {
157 unwind_info = Some(info);
158 }
159
160 if let Some(info) = unwind_info {
161 table.add_fde(cie_id, info.to_fde(Address::Symbol { symbol, addend: 0 }));
162 }
163 }
164
165 Some(table)
166 }
167
emit_dwarf( isa: &dyn TargetIsa, compilation: &mut Compilation<'_>, ) -> EnvResult<Vec<DwarfSection>>168 pub fn emit_dwarf(
169 isa: &dyn TargetIsa,
170 compilation: &mut Compilation<'_>,
171 ) -> EnvResult<Vec<DwarfSection>> {
172 let dwarf = transform_dwarf(isa, compilation)?;
173 let frame_table = create_frame_table(isa, compilation);
174 let sections = emit_dwarf_sections(isa, dwarf, frame_table)?;
175 Ok(sections)
176 }
177