Path: blob/main/crates/cranelift/src/debug/write_debuginfo.rs
1693 views
use crate::debug::Compilation;1pub use crate::debug::transform::transform_dwarf;2use cranelift_codegen::ir::Endianness;3use cranelift_codegen::isa::{4TargetIsa,5unwind::{CfaUnwindInfo, UnwindInfo},6};7use gimli::write::{Address, Dwarf, EndianVec, FrameTable, Result, Sections, Writer};8use gimli::{RunTimeEndian, SectionId};910pub struct DwarfSection {11pub name: &'static str,12pub body: Vec<u8>,13pub relocs: Vec<DwarfSectionReloc>,14}1516#[derive(Clone)]17pub struct DwarfSectionReloc {18pub target: DwarfSectionRelocTarget,19pub offset: u32,20pub addend: i32,21pub size: u8,22}2324#[derive(Clone)]25pub enum DwarfSectionRelocTarget {26Func(usize),27Section(&'static str),28}2930fn emit_dwarf_sections(31isa: &dyn TargetIsa,32mut dwarf: Dwarf,33frames: Option<FrameTable>,34) -> anyhow::Result<Vec<DwarfSection>> {35let endian = match isa.endianness() {36Endianness::Little => RunTimeEndian::Little,37Endianness::Big => RunTimeEndian::Big,38};39let writer = WriterRelocate {40relocs: Vec::new(),41writer: EndianVec::new(endian),42};43let mut sections = Sections::new(writer);44dwarf.write(&mut sections)?;45if let Some(frames) = frames {46frames.write_debug_frame(&mut sections.debug_frame)?;47}4849let mut result = Vec::new();50sections.for_each_mut(|id, s| -> anyhow::Result<()> {51let name = id.name();52let body = s.writer.take();53if body.is_empty() {54return Ok(());55}56let mut relocs = vec![];57::std::mem::swap(&mut relocs, &mut s.relocs);58result.push(DwarfSection { name, body, relocs });59Ok(())60})?;6162Ok(result)63}6465#[derive(Clone)]66pub struct WriterRelocate {67relocs: Vec<DwarfSectionReloc>,68writer: EndianVec<RunTimeEndian>,69}7071impl Writer for WriterRelocate {72type Endian = RunTimeEndian;7374fn endian(&self) -> Self::Endian {75self.writer.endian()76}7778fn len(&self) -> usize {79self.writer.len()80}8182fn write(&mut self, bytes: &[u8]) -> Result<()> {83self.writer.write(bytes)84}8586fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> {87self.writer.write_at(offset, bytes)88}8990fn write_address(&mut self, address: Address, size: u8) -> Result<()> {91match address {92Address::Constant(val) => self.write_udata(val, size),93Address::Symbol { symbol, addend } => {94let offset = self.len() as u32;95self.relocs.push(DwarfSectionReloc {96target: DwarfSectionRelocTarget::Func(symbol),97offset,98size,99addend: addend as i32,100});101self.write_udata(addend as u64, size)102}103}104}105106fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> Result<()> {107let offset = self.len() as u32;108let target = DwarfSectionRelocTarget::Section(section.name());109self.relocs.push(DwarfSectionReloc {110target,111offset,112size,113addend: val as i32,114});115self.write_udata(val as u64, size)116}117118fn write_offset_at(119&mut self,120offset: usize,121val: usize,122section: SectionId,123size: u8,124) -> Result<()> {125let target = DwarfSectionRelocTarget::Section(section.name());126self.relocs.push(DwarfSectionReloc {127target,128offset: offset as u32,129size,130addend: val as i32,131});132self.write_udata_at(offset, val as u64, size)133}134}135136fn create_frame_table(137isa: &dyn TargetIsa,138compilation: &mut Compilation<'_>,139) -> Option<FrameTable> {140let mut table = FrameTable::default();141142let cie_id = table.add_cie(isa.create_systemv_cie()?);143144for (_, symbol, metadata) in compilation.functions() {145// The CFA-based unwind info will either be natively present, or we146// have generated it and placed into the "cfa_unwind_info" auxiliary147// field. We shouldn't emit both, though, it'd be wasteful.148let mut unwind_info: Option<&CfaUnwindInfo> = None;149if let Some(UnwindInfo::SystemV(info)) = &metadata.unwind_info {150debug_assert!(metadata.cfa_unwind_info.is_none());151unwind_info = Some(info);152} else if let Some(info) = &metadata.cfa_unwind_info {153unwind_info = Some(info);154}155156if let Some(info) = unwind_info {157table.add_fde(cie_id, info.to_fde(Address::Symbol { symbol, addend: 0 }));158}159}160161Some(table)162}163164pub fn emit_dwarf(165isa: &dyn TargetIsa,166compilation: &mut Compilation<'_>,167) -> anyhow::Result<Vec<DwarfSection>> {168let dwarf = transform_dwarf(isa, compilation)?;169let frame_table = create_frame_table(isa, compilation);170let sections = emit_dwarf_sections(isa, dwarf, frame_table)?;171Ok(sections)172}173174175