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