Skip to content

Commit

Permalink
WIP compact unwinding info
Browse files Browse the repository at this point in the history
  • Loading branch information
Gankra committed Apr 27, 2021
1 parent 8c0925e commit d815d57
Show file tree
Hide file tree
Showing 3 changed files with 1,668 additions and 2 deletions.
78 changes: 76 additions & 2 deletions symbolic-minidump/src/cfi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ use symbolic_debuginfo::pdb::PdbObject;
use symbolic_debuginfo::pe::{PeObject, RuntimeFunction, UnwindOperation};
use symbolic_debuginfo::{Object, ObjectError, ObjectLike};

use crate::compact::{CompactUnwindInfo, UnwindInfoFrame};

/// The latest version of the file format.
pub const CFICACHE_LATEST_VERSION: u32 = 1;

Expand Down Expand Up @@ -348,8 +350,16 @@ impl<W: Write> AsciiCfiWriter<W> {
Ok(())
};

// Indepdendently, Linux C++ exception handling information can also provide unwind info.
if let Some(section) = object.section("eh_frame") {
if let Some(section) = object.section("unwind_info") {
// Independently, MacOS compact unwinding information can also provide unwind info.
// Don't read eh_frame contents if unwind_info is present, because eh_frame
// may contain conflicting duplictes and unwind_info usually is more complete
// when present.
let frame = UnwindInfoFrame::new(&section.data, endian);
let info = CompactUnwindInfo::new(object, section.address, frame);
self.read_compact_unwind_info(&info)?;
} else if let Some(section) = object.section("eh_frame") {
// Independently, Linux C++ exception handling information can also provide unwind info.
let frame = EhFrame::new(&section.data, endian);
let info = UnwindInfo::new(object, section.address, frame);
self.read_cfi(&info)?;
Expand All @@ -358,6 +368,70 @@ impl<W: Write> AsciiCfiWriter<W> {
debug_frame_result
}

fn read_compact_unwind_info<R: Reader>(
&mut self,
info: &CompactUnwindInfo<R>,
) -> Result<(), CfiError> {
use crate::compact::CfiOp;

fn write_reg_name<W: Write>(
writer: &mut W,
register: crate::compact::CfiRegister,
arch: &Arch,
) -> Result<(), CfiError> {
use crate::compact::CfiRegister;
if register.is_cfa() {
write!(writer, ".cfa")?;
} else if register == CfiRegister::instruction_pointer() {
write!(writer, ".ra")?;
} else {
write!(writer, "${}", register.name(arch).unwrap())?;
}
Ok(())
}

let mut iter = info.iter()?;
while let Some(entry) = iter.next()? {
if let Some(instructions) = entry.cfi_instructions(&iter) {
let mut line = Vec::new();
let start_addr = entry.instruction_address;
let length = entry.len;
write!(line, "STACK CFI INIT {:x} {:x} ", start_addr, length)?;

for instruction in instructions {
// These two operations differ only in whether there should
// be a deref (^) at the end, so we can flatten away their
// differences and merge paths.
let (dest_reg, src_reg, offset, should_deref) = match instruction {
CfiOp::RegisterAt {
dest_reg,
src_reg,
offset_from_src,
} => (dest_reg, src_reg, offset_from_src, true),
CfiOp::RegisterIs {
dest_reg,
src_reg,
offset_from_src,
} => (dest_reg, src_reg, offset_from_src, false),
};

write_reg_name(&mut line, dest_reg, &info.arch)?;
write!(line, ": ")?;
write_reg_name(&mut line, src_reg, &info.arch)?;
write!(line, " {} + ", offset)?;
if should_deref {
write!(line, "^ ")?;
}
}

self.inner
.write_all(&line)
.and_then(|_| writeln!(self.inner))?;
}
}
Ok(())
}

fn read_cfi<U, R>(&mut self, info: &UnwindInfo<U>) -> Result<(), CfiError>
where
R: Reader + Eq,
Expand Down
Loading

0 comments on commit d815d57

Please sign in to comment.