define_section!(
DebugFrame,
DebugFrameOffset, "A writable `.debug_frame` section."
);
define_section!(EhFrame, EhFrameOffset, "A writable `.eh_frame` section.");
define_id!(CieId, "An identifier for a CIE in a `FrameTable`.");
/// A table of frame description entries. #[derive(Debug, Default)] pubstruct FrameTable { /// Base id for CIEs.
base_id: BaseId, /// The common information entries.
cies: IndexSet<CommonInformationEntry>, /// The frame description entries.
fdes: Vec<(CieId, FrameDescriptionEntry)>,
}
impl FrameTable { /// Add a CIE and return its id. /// /// If the CIE already exists, then return the id of the existing CIE. pubfn add_cie(&mutself, cie: CommonInformationEntry) -> CieId { let (index, _) = self.cies.insert_full(cie);
CieId::new(self.base_id, index)
}
/// The number of CIEs. pubfn cie_count(&self) -> usize { self.cies.len()
}
/// Add a FDE. /// /// Does not check for duplicates. /// /// # Panics /// /// Panics if the CIE id is invalid. pubfn add_fde(&mutself, cie: CieId, fde: FrameDescriptionEntry) {
debug_assert_eq!(self.base_id, cie.base_id); self.fdes.push((cie, fde));
}
/// The number of FDEs. pubfn fde_count(&self) -> usize { self.fdes.len()
}
/// Write the frame table entries to the given `.debug_frame` section. pubfn write_debug_frame<W: Writer>(&self, w: &mut DebugFrame<W>) -> Result<()> { self.write(&mut w.0, false)
}
/// Write the frame table entries to the given `.eh_frame` section. pubfn write_eh_frame<W: Writer>(&self, w: &>mut EhFrame<W>) -> Result<()> { self.write(&mut w.0, true)
}
fn write<W: Writer>(&self, w: &mut W, eh_frame: bool) -> Result<()> { letmut cie_offsets = vec![None; self.cies.len()]; for (cie_id, fde) in &self.fdes { let cie_index = cie_id.index; let cie = self.cies.get_index(cie_index).unwrap(); let cie_offset = match cie_offsets[cie_index] {
Some(offset) => offset,
None => { // Only write CIEs as they are referenced. let offset = cie.write(w, eh_frame)?;
cie_offsets[cie_index] = Some(offset);
offset
}
};
/// A common information entry. This contains information that is shared between FDEs. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pubstruct CommonInformationEntry {
encoding: Encoding,
/// A constant that is factored out of code offsets. /// /// This should be set to the minimum instruction length. /// Writing a code offset that is not a multiple of this factor will generate an error.
code_alignment_factor: u8,
/// A constant that is factored out of data offsets. /// /// This should be set to the minimum data alignment for the frame. /// Writing a data offset that is not a multiple of this factor will generate an error.
data_alignment_factor: i8,
/// The return address register. This might not correspond to an actual machine register.
return_address_register: Register,
/// The address of the personality function and its encoding. pub personality: Option<(constants::DwEhPe, Address)>,
/// The encoding to use for the LSDA address in FDEs. /// /// If set then all FDEs which use this CIE must have a LSDA address. pub lsda_encoding: Option<constants::DwEhPe>,
/// The encoding to use for addresses in FDEs. pub fde_address_encoding: constants::DwEhPe,
/// True for signal trampolines. pub signal_trampoline: bool,
/// The initial instructions upon entry to this function.
instructions: Vec<CallFrameInstruction>,
}
impl CommonInformationEntry { /// Create a new common information entry. /// /// The encoding version must be a CFI version, not a DWARF version. pubfn new(
encoding: Encoding,
code_alignment_factor: u8,
data_alignment_factor: i8,
return_address_register: Register,
) -> Self {
CommonInformationEntry {
encoding,
code_alignment_factor,
data_alignment_factor,
return_address_register,
personality: None,
lsda_encoding: None,
fde_address_encoding: constants::DW_EH_PE_absptr,
signal_trampoline: false,
instructions: Vec::new(),
}
}
let length = (w.len() - length_base) as u64;
w.write_initial_length_at(length_offset, length, encoding.format)?;
Ok(offset)
}
}
/// A frame description entry. There should be one FDE per function. #[derive(Debug, Clone, PartialEq, Eq)] pubstruct FrameDescriptionEntry { /// The initial address of the function.
address: Address,
/// The length in bytes of the function.
length: u32,
/// The address of the LSDA. pub lsda: Option<Address>,
/// The instructions for this function, ordered by offset.
instructions: Vec<(u32, CallFrameInstruction)>,
}
impl FrameDescriptionEntry { /// Create a new frame description entry for a function. pubfn new(address: Address, length: u32) -> Self {
FrameDescriptionEntry {
address,
length,
lsda: None,
instructions: Vec::new(),
}
}
/// Add an instruction. /// /// Instructions must be added in increasing order of offset, or writing will fail. pubfn add_instruction(&mutself, offset: u32, instruction: CallFrameInstruction) {
debug_assert!(self.instructions.last().map(|x| x.0).unwrap_or(0) <= offset); self.instructions.push((offset, instruction));
}
fn write<W: Writer>(
&self,
w: &mut W,
eh_frame: bool,
cie_offset: usize,
cie: &CommonInformationEntry,
) -> Result<()> { let encoding = cie.encoding; let length_offset = w.write_initial_length(encoding.format)?; let length_base = w.len();
if eh_frame { // .eh_frame uses a relative offset which doesn't need relocation.
w.write_udata((w.len() - cie_offset) as u64, 4)?;
} else {
w.write_offset(
cie_offset,
SectionId::DebugFrame,
encoding.format.word_size(),
)?;
}
let length = (w.len() - length_base) as u64;
w.write_initial_length_at(length_offset, length, encoding.format)?;
Ok(())
}
}
/// An instruction in a frame description entry. /// /// This may be a CFA definition, a register rule, or some other directive. #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[non_exhaustive] pubenum CallFrameInstruction { /// Define the CFA rule to use the provided register and offset.
Cfa(Register, i32), /// Update the CFA rule to use the provided register. The offset is unchanged.
CfaRegister(Register), /// Update the CFA rule to use the provided offset. The register is unchanged.
CfaOffset(i32), /// Define the CFA rule to use the provided expression.
CfaExpression(Expression),
/// Restore the initial rule for the register.
Restore(Register), /// The previous value of the register is not recoverable.
Undefined(Register), /// The register has not been modified.
SameValue(Register), /// The previous value of the register is saved at address CFA + offset.
Offset(Register, i32), /// The previous value of the register is CFA + offset.
ValOffset(Register, i32), /// The previous value of the register is stored in another register.
Register(Register, Register), /// The previous value of the register is saved at address given by the expression.
Expression(Register, Expression), /// The previous value of the register is given by the expression.
ValExpression(Register, Expression),
/// Push all register rules onto a stack.
RememberState, /// Pop all register rules off the stack.
RestoreState, /// The size of the arguments that have been pushed onto the stack.
ArgsSize(u32),
/// AAarch64 extension: negate the `RA_SIGN_STATE` pseudo-register.
NegateRaState,
}
fn factored_code_delta(prev_offset: u32, offset: u32, factor: u8) -> Result<u32> { if offset < prev_offset { return Err(Error::InvalidFrameCodeOffset(offset));
} let delta = offset - prev_offset; let factor = u32::from(factor); let factored_delta = delta / factor; if delta != factored_delta * factor { return Err(Error::InvalidFrameCodeOffset(offset));
}
Ok(factored_delta)
}
fn factored_data_offset(offset: i32, factor: i8) -> Result<i32> { let factor = i32::from(factor); let factored_offset = offset / factor; if offset != factored_offset * factor { return Err(Error::InvalidFrameDataOffset(offset));
}
Ok(factored_offset)
}
#[cfg(feature = "read")] pub(crate) mod convert { usesuper::*; usecrate::read::{self, Reader}; usecrate::write::{ConvertError, ConvertResult}; use std::collections::{hash_map, HashMap};
impl FrameTable { /// Create a frame table by reading the data in the given section. /// /// `convert_address` is a function to convert read addresses into the `Address` /// type. For non-relocatable addresses, this function may simply return /// `Address::Constant(address)`. For relocatable addresses, it is the caller's /// responsibility to determine the symbol and addend corresponding to the address /// and return `Address::Symbol { symbol, addend }`. pubfn from<R, Section>(
frame: &Section,
convert_address: &dynFn(u64) -> Option<Address>,
) -> ConvertResult<FrameTable> where
R: Reader<Offset = usize>,
Section: read::UnwindSection<R>,
Section::Offset: read::UnwindOffset<usize>,
{ let bases = read::BaseAddresses::default().set_eh_frame(0);
// TODO: is it worth caching the parsed CIEs? It would be better if FDEs only // stored a reference. let from_fde = partial.parse(Section::cie_from_offset)?; let from_cie = from_fde.cie(); let cie_id = match cie_ids.entry(from_cie.offset()) {
hash_map::Entry::Occupied(o) => *o.get(),
hash_map::Entry::Vacant(e) => { let cie =
CommonInformationEntry::from(from_cie, frame, &bases, convert_address)?; let cie_id = frame_table.add_cie(cie);
e.insert(cie_id);
cie_id
}
}; let fde = FrameDescriptionEntry::from(&from_fde, frame, &bases, convert_address)?;
frame_table.add_fde(cie_id, fde);
}
cie.personality = match from_cie.personality_with_encoding() { // We treat these the same because the encoding already determines // whether it is indirect.
Some((eh_pe, read::Pointer::Direct(p)))
| Some((eh_pe, read::Pointer::Indirect(p))) => { let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?;
Some((eh_pe, address))
}
_ => None,
};
cie.lsda_encoding = from_cie.lsda_encoding();
cie.fde_address_encoding = from_cie
.fde_address_encoding()
.unwrap_or(constants::DW_EH_PE_absptr);
cie.signal_trampoline = from_cie.is_signal_trampoline();
match from_fde.lsda() { // We treat these the same because the encoding already determines // whether it is indirect.
Some(read::Pointer::Direct(p)) | Some(read::Pointer::Indirect(p)) => { let address = convert_address(p).ok_or(ConvertError::InvalidAddress)?;
fde.lsda = Some(address);
}
None => {}
}
#[test] fn test_frame_table() { for &version in &[1, 3, 4] { for &address_size in &[4, 8] { for &format in &[Format::Dwarf32, Format::Dwarf64] { let encoding = Encoding {
format,
version,
address_size,
}; letmut frames = FrameTable::default();
let cie1 = CommonInformationEntry::new(encoding, 1, 8, X86_64::RA); let cie1_id = frames.add_cie(cie1.clone());
assert_eq!(cie1_id, frames.add_cie(cie1.clone()));
// Test writing `.debug_frame`. letmut debug_frame = DebugFrame::from(EndianVec::new(LittleEndian));
frames.write_debug_frame(&mut debug_frame).unwrap();
letmut read_debug_frame =
read::DebugFrame::new(debug_frame.slice(), LittleEndian);
read_debug_frame.set_address_size(address_size); let convert_frames = FrameTable::from(&read_debug_frame, &|address| {
Some(Address::Constant(address))
})
.unwrap();
assert_eq!(frames.cies, convert_frames.cies);
assert_eq!(frames.fdes.len(), convert_frames.fdes.len()); for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) {
assert_eq!(a.1, b.1);
}
if version == 1 { // Test writing `.eh_frame`. letmut eh_frame = EhFrame::from(EndianVec::new(LittleEndian));
frames.write_eh_frame(&mut eh_frame).unwrap();
letmut read_eh_frame = read::EhFrame::new(eh_frame.slice(), LittleEndian);
read_eh_frame.set_address_size(address_size); let convert_frames = FrameTable::from(&read_eh_frame, &|address| {
Some(Address::Constant(address))
})
.unwrap();
assert_eq!(frames.cies, convert_frames.cies);
assert_eq!(frames.fdes.len(), convert_frames.fdes.len()); for (a, b) in frames.fdes.iter().zip(convert_frames.fdes.iter()) {
assert_eq!(a.1, b.1);
}
}
}
}
}
}
let fde_instructions_aarch64 = [(0, CallFrameInstruction::NegateRaState)];
for &version in &[1, 3, 4] { for &address_size in &[4, 8] { for &vendor in &[Vendor::Default, Vendor::AArch64] { for &format in &[Format::Dwarf32, Format::Dwarf64] { let encoding = Encoding {
format,
version,
address_size,
}; letmut frames = FrameTable::default();
letmut cie = CommonInformationEntry::new(encoding, 2, 8, X86_64::RA); for i in &cie_instructions {
cie.add_instruction(i.clone());
} let cie_id = frames.add_cie(cie);
letmut fde = FrameDescriptionEntry::new(Address::Constant(0x1000), 0x10); for (o, i) in &fde_instructions {
fde.add_instruction(*o, i.clone());
}
frames.add_fde(cie_id, fde);
if vendor == Vendor::AArch64 { letmut fde =
FrameDescriptionEntry::new(Address::Constant(0x2000), 0x10); for (o, i) in &fde_instructions_aarch64 {
fde.add_instruction(*o, i.clone());
}
frames.add_fde(cie_id, fde);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.