Skip to content

Commit

Permalink
read/cfi: implement DW_CFA_AARCH64_negate_ra_state
Browse files Browse the repository at this point in the history
  • Loading branch information
philipc committed Aug 10, 2023
1 parent 1555c68 commit 8a1efa8
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 6 deletions.
8 changes: 8 additions & 0 deletions crates/examples/src/bin/dwarfdump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,11 @@ fn dump_eh_frame<R: Reader, W: Write>(
.unwrap_or(mem::size_of::<usize>() as u8);
eh_frame.set_address_size(address_size);

match file.architecture() {
object::Architecture::Aarch64 => eh_frame.set_vendor(gimli::Vendor::AArch64),
_ => {}
}

fn register_name_none(_: gimli::Register) -> Option<&'static str> {
None
}
Expand Down Expand Up @@ -1050,6 +1055,9 @@ fn dump_cfi_instructions<R: Reader, W: Write>(
ArgsSize { size } => {
writeln!(w, " DW_CFA_GNU_args_size ({})", size)?;
}
NegateRaState => {
writeln!(w, " DW_CFA_AARCH64_negate_ra_state")?;
}
Nop => {
writeln!(w, " DW_CFA_nop")?;
}
Expand Down
9 changes: 9 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ impl Format {
}
}

/// Which vendor extensions to support.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Vendor {
/// A default set of extensions, including some common GNU extensions.
Default,
/// AAarch64 extensions.
AArch64,
}

/// Encoding parameters that are commonly used for multiple DWARF sections.
///
/// This is intended to be small enough to pass by value.
Expand Down
11 changes: 10 additions & 1 deletion src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,20 @@ use core::fmt;
// }
// }
macro_rules! dw {
($(#[$meta:meta])* $struct_name:ident($struct_type:ty) { $($name:ident = $val:expr),+ $(,)? }) => {
($(#[$meta:meta])* $struct_name:ident($struct_type:ty)
{ $($name:ident = $val:expr),+ $(,)? }
$(, aliases { $($alias_name:ident = $alias_val:expr),+ $(,)? })?
) => {
$(#[$meta])*
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct $struct_name(pub $struct_type);

$(
pub const $name: $struct_name = $struct_name($val);
)+
$($(
pub const $alias_name: $struct_name = $struct_name($alias_val);
)+)*

impl $struct_name {
pub fn static_string(&self) -> Option<&'static str> {
Expand Down Expand Up @@ -182,6 +188,9 @@ DwCfa(u8) {
DW_CFA_GNU_window_save = 0x2d,
DW_CFA_GNU_args_size = 0x2e,
DW_CFA_GNU_negative_offset_extended = 0x2f,
},
aliases {
DW_CFA_AARCH64_negate_ra_state = 0x2d,
});

dw!(
Expand Down
86 changes: 81 additions & 5 deletions src/read/cfi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use core::mem;
use core::num::Wrapping;

use super::util::{ArrayLike, ArrayVec};
use crate::common::{DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId};
use crate::common::{
DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId, Vendor,
};
use crate::constants::{self, DwEhPe};
use crate::endianity::Endianity;
use crate::read::{
Expand All @@ -34,6 +36,7 @@ pub struct DebugFrame<R: Reader> {
section: R,
address_size: u8,
segment_size: u8,
vendor: Vendor,
}

impl<R: Reader> DebugFrame<R> {
Expand All @@ -52,6 +55,13 @@ impl<R: Reader> DebugFrame<R> {
pub fn set_segment_size(&mut self, segment_size: u8) {
self.segment_size = segment_size
}

/// Set the vendor extensions to use.
///
/// This defaults to `None`.
pub fn set_vendor(&mut self, vendor: Vendor) {
self.vendor = vendor;
}
}

impl<'input, Endian> DebugFrame<EndianSlice<'input, Endian>>
Expand Down Expand Up @@ -95,6 +105,7 @@ impl<R: Reader> From<R> for DebugFrame<R> {
section,
address_size: mem::size_of::<usize>() as u8,
segment_size: 0,
vendor: Vendor::Default,
}
}
}
Expand Down Expand Up @@ -482,6 +493,7 @@ impl<'a, R: Reader + 'a> EhHdrTable<'a, R> {
pub struct EhFrame<R: Reader> {
section: R,
address_size: u8,
vendor: Vendor,
}

impl<R: Reader> EhFrame<R> {
Expand All @@ -491,6 +503,13 @@ impl<R: Reader> EhFrame<R> {
pub fn set_address_size(&mut self, address_size: u8) {
self.address_size = address_size
}

/// Set the vendor extensions to use.
///
/// This defaults to `None`.
pub fn set_vendor(&mut self, vendor: Vendor) {
self.vendor = vendor;
}
}

impl<'input, Endian> EhFrame<EndianSlice<'input, Endian>>
Expand Down Expand Up @@ -533,6 +552,7 @@ impl<R: Reader> From<R> for EhFrame<R> {
EhFrame {
section,
address_size: mem::size_of::<usize>() as u8,
vendor: Vendor::Default,
}
}
}
Expand Down Expand Up @@ -613,6 +633,9 @@ pub trait _UnwindSectionPrivate<R: Reader> {

/// The segment size to use if `has_address_and_segment_sizes` returns false.
fn segment_size(&self) -> u8;

/// The vendor extensions to use.
fn vendor(&self) -> Vendor;
}

/// A section holding unwind information: either `.debug_frame` or
Expand Down Expand Up @@ -808,6 +831,10 @@ impl<R: Reader> _UnwindSectionPrivate<R> for DebugFrame<R> {
fn segment_size(&self) -> u8 {
self.segment_size
}

fn vendor(&self) -> Vendor {
self.vendor
}
}

impl<R: Reader> UnwindSection<R> for DebugFrame<R> {
Expand Down Expand Up @@ -848,6 +875,10 @@ impl<R: Reader> _UnwindSectionPrivate<R> for EhFrame<R> {
fn segment_size(&self) -> u8 {
0
}

fn vendor(&self) -> Vendor {
self.vendor
}
}

impl<R: Reader> UnwindSection<R> for EhFrame<R> {
Expand Down Expand Up @@ -1421,6 +1452,7 @@ impl<R: Reader> CommonInformationEntry<R> {
address_size: self.address_size,
section: section.section(),
},
vendor: section.vendor(),
}
}

Expand Down Expand Up @@ -1764,6 +1796,7 @@ impl<R: Reader> FrameDescriptionEntry<R> {
address_size: self.cie.address_size,
section: section.section(),
},
vendor: section.vendor(),
}
}

Expand Down Expand Up @@ -2400,6 +2433,18 @@ impl<'a, 'ctx, R: Reader, A: UnwindContextStorage<R>> UnwindTable<'a, 'ctx, R, A
self.ctx.row_mut().saved_args_size = size;
}

// AARCH64 extension.
NegateRaState => {
let register = crate::AArch64::RA_SIGN_STATE;
let value = match self.ctx.row().register(register) {
RegisterRule::Undefined => 0,
RegisterRule::Constant(value) => value,
_ => return Err(Error::CfiInstructionInInvalidContext),
};
self.ctx
.set_register_rule(register, RegisterRule::Constant(value ^ 1))?;
}

// No operation.
Nop => {}
};
Expand Down Expand Up @@ -2801,6 +2846,9 @@ pub enum RegisterRule<R: Reader> {

/// "The rule is defined externally to this specification by the augmenter."
Architectural,

/// This is a pseudo-register with a constant value.
Constant(u64),
}

impl<R: Reader> RegisterRule<R> {
Expand Down Expand Up @@ -3088,6 +3136,17 @@ pub enum CallFrameInstruction<R: Reader> {
size: u64,
},

/// > DW_CFA_AARCH64_negate_ra_state
/// >
/// > AARCH64 Extension
/// >
/// > The DW_CFA_AARCH64_negate_ra_state operation negates bit[0] of the
/// > RA_SIGN_STATE pseudo-register. It does not take any operands. The
/// > DW_CFA_AARCH64_negate_ra_state must not be mixed with other DWARF Register
/// > Rule Instructions on the RA_SIGN_STATE pseudo-register in one Common
/// > Information Entry (CIE) and Frame Descriptor Entry (FDE) program sequence.
NegateRaState,

// 6.4.2.5 Padding Instruction
/// > 1. DW_CFA_nop
/// >
Expand All @@ -3104,6 +3163,7 @@ impl<R: Reader> CallFrameInstruction<R> {
input: &mut R,
address_encoding: Option<DwEhPe>,
parameters: &PointerEncodingParameters<R>,
vendor: Vendor,
) -> Result<CallFrameInstruction<R>> {
let instruction = input.read_u8()?;
let high_bits = instruction & CFI_INSTRUCTION_HIGH_BITS_MASK;
Expand Down Expand Up @@ -3292,6 +3352,10 @@ impl<R: Reader> CallFrameInstruction<R> {
Ok(CallFrameInstruction::ArgsSize { size })
}

constants::DW_CFA_AARCH64_negate_ra_state if vendor == Vendor::AArch64 => {
Ok(CallFrameInstruction::NegateRaState)
}

otherwise => Err(Error::UnknownCallFrameInstruction(otherwise)),
}
}
Expand All @@ -3306,6 +3370,7 @@ pub struct CallFrameInstructionIter<'a, R: Reader> {
input: R,
address_encoding: Option<constants::DwEhPe>,
parameters: PointerEncodingParameters<'a, R>,
vendor: Vendor,
}

impl<'a, R: Reader> CallFrameInstructionIter<'a, R> {
Expand All @@ -3315,8 +3380,12 @@ impl<'a, R: Reader> CallFrameInstructionIter<'a, R> {
return Ok(None);
}

match CallFrameInstruction::parse(&mut self.input, self.address_encoding, &self.parameters)
{
match CallFrameInstruction::parse(
&mut self.input,
self.address_encoding,
&self.parameters,
self.vendor,
) {
Ok(instruction) => Ok(Some(instruction)),
Err(e) => {
self.input.empty();
Expand Down Expand Up @@ -4436,7 +4505,7 @@ mod tests {
address_size,
section: &R::default(),
};
CallFrameInstruction::parse(input, None, parameters)
CallFrameInstruction::parse(input, None, parameters, Vendor::Default)
}

#[test]
Expand Down Expand Up @@ -4549,7 +4618,12 @@ mod tests {
section: &EndianSlice::new(&[], LittleEndian),
};
assert_eq!(
CallFrameInstruction::parse(input, Some(constants::DW_EH_PE_textrel), parameters),
CallFrameInstruction::parse(
input,
Some(constants::DW_EH_PE_textrel),
parameters,
Vendor::Default
),
Ok(CallFrameInstruction::SetLoc {
address: expected_addr,
})
Expand Down Expand Up @@ -5056,6 +5130,7 @@ mod tests {
input,
address_encoding: None,
parameters,
vendor: Vendor::Default,
};

assert_eq!(
Expand Down Expand Up @@ -5093,6 +5168,7 @@ mod tests {
input,
address_encoding: None,
parameters,
vendor: Vendor::Default,
};

assert_eq!(
Expand Down
7 changes: 7 additions & 0 deletions src/write/cfi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,9 @@ pub enum CallFrameInstruction {
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,
}

impl CallFrameInstruction {
Expand Down Expand Up @@ -523,6 +526,9 @@ impl CallFrameInstruction {
w.write_u8(constants::DW_CFA_GNU_args_size.0)?;
w.write_uleb128(size.into())?;
}
CallFrameInstruction::NegateRaState => {
w.write_u8(constants::DW_CFA_AARCH64_negate_ra_state.0)?;
}
}
Ok(())
}
Expand Down Expand Up @@ -834,6 +840,7 @@ pub(crate) mod convert {
read::CallFrameInstruction::ArgsSize { size } => {
CallFrameInstruction::ArgsSize(size as u32)
}
read::CallFrameInstruction::NegateRaState => CallFrameInstruction::NegateRaState,
read::CallFrameInstruction::Nop => return Ok(None),
}))
}
Expand Down

0 comments on commit 8a1efa8

Please sign in to comment.