1 pub use crate::debug::transform::transform_dwarf; 2 use crate::debug::ModuleMemoryOffset; 3 use crate::CompiledFunctionsMetadata; 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 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 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 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 110 fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> Result<()> { 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 122 fn write_offset_at( 123 &mut self, 124 offset: usize, 125 val: usize, 126 section: SectionId, 127 size: u8, 128 ) -> Result<()> { 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 140 fn create_frame_table<'a>( 141 isa: &dyn TargetIsa, 142 funcs: &CompiledFunctionsMetadata, 143 ) -> Option<FrameTable> { 144 let mut table = FrameTable::default(); 145 146 let cie_id = table.add_cie(isa.create_systemv_cie()?); 147 148 for (i, metadata) in funcs { 149 if let Some(UnwindInfo::SystemV(info)) = &metadata.unwind_info { 150 table.add_fde( 151 cie_id, 152 info.to_fde(Address::Symbol { 153 symbol: i.index(), 154 addend: 0, 155 }), 156 ); 157 } 158 } 159 160 Some(table) 161 } 162 163 pub fn emit_dwarf<'a>( 164 isa: &dyn TargetIsa, 165 debuginfo_data: &DebugInfoData, 166 funcs: &CompiledFunctionsMetadata, 167 memory_offset: &ModuleMemoryOffset, 168 ) -> anyhow::Result<Vec<DwarfSection>> { 169 let dwarf = transform_dwarf(isa, debuginfo_data, funcs, memory_offset)?; 170 let frame_table = create_frame_table(isa, funcs); 171 let sections = emit_dwarf_sections(isa, dwarf, frame_table)?; 172 Ok(sections) 173 } 174