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