This commit is contained in:
nora 2023-06-17 23:33:01 +02:00
parent 7a8a82b476
commit 591da9ff7d
8 changed files with 213 additions and 169 deletions

3
rustfmt.toml Normal file
View file

@ -0,0 +1,3 @@
reorder_imports = true
imports_granularity = "Module"
wrap_comments = true

View file

@ -1,13 +1,15 @@
//! # divination //! # divination
//! //!
//! the practice of seeking knowledge of the future or the unknown by supernatural means. //! the practice of seeking knowledge of the future or the unknown by
//! supernatural means.
//! //!
//! we ask supernatural means (the dynamic linker) for knowledge of the future //! we ask supernatural means (the dynamic linker) for knowledge of the future
//! (where we will find the dwarves) //! (where we will find the dwarves)
//! //!
//! first, we ask the dynamic linker to give us the `.eh_frame` for the current binary using //! first, we ask the dynamic linker to give us the `.eh_frame` for the current
//! the GNU extension (`_dl_find_object`)[https://www.gnu.org/software/libc/manual/html_node/Dynamic-Linker-Introspection.html]. //! binary using the GNU extension (`_dl_find_object`)[https://www.gnu.org/software/libc/manual/html_node/Dynamic-Linker-Introspection.html].
//! then, we parse that as beautiful DWARF call frame information, as god (or rather, the x86-64 psABI) intended. //! then, we parse that as beautiful DWARF call frame information, as god (or
//! rather, the x86-64 psABI) intended.
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
@ -23,7 +25,8 @@ struct dl_find_object {
dlfo_map_start: *const ffi::c_void, dlfo_map_start: *const ffi::c_void,
dlfo_map_end: *const ffi::c_void, dlfo_map_end: *const ffi::c_void,
dlf_link_map: *const ffi::c_void, dlf_link_map: *const ffi::c_void,
/// A pointer to the `PT_GNU_EH_FRAME` segment (the `.eh_frame_hdr` section). /// A pointer to the `PT_GNU_EH_FRAME` segment (the `.eh_frame_hdr`
/// section).
dlfo_eh_frame: *const ffi::c_void, dlfo_eh_frame: *const ffi::c_void,
} }
@ -164,7 +167,9 @@ impl fmt::Debug for Encoding {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
#[repr(u8)] #[repr(u8)]
enum ValueFormat { enum ValueFormat {
/// Unsigned value is encoded using the Little Endian Base 128 (LEB128) as defined by DWARF Debugging Information Format, Revision 2.0.0 (July 27, 1993). /// Unsigned value is encoded using the Little Endian Base 128 (LEB128) as
/// defined by DWARF Debugging Information Format, Revision 2.0.0 (July 27,
/// 1993).
DW_EH_PE_uleb128 = 0x01, DW_EH_PE_uleb128 = 0x01,
/// A 2 bytes unsigned value. /// A 2 bytes unsigned value.
DW_EH_PE_udata2 = 0x02, DW_EH_PE_udata2 = 0x02,
@ -172,7 +177,9 @@ enum ValueFormat {
DW_EH_PE_udata4 = 0x03, DW_EH_PE_udata4 = 0x03,
/// An 8 bytes unsigned value. /// An 8 bytes unsigned value.
DW_EH_PE_udata8 = 0x04, DW_EH_PE_udata8 = 0x04,
/// Signed value is encoded using the Little Endian Base 128 (LEB128) as defined by DWARF Debugging Information Format, Revision 2.0.0 (July 27, 1993). /// Signed value is encoded using the Little Endian Base 128 (LEB128) as
/// defined by DWARF Debugging Information Format, Revision 2.0.0 (July 27,
/// 1993).
DW_EH_PE_sleb128 = 0x09, DW_EH_PE_sleb128 = 0x09,
/// A 2 bytes signed value. /// A 2 bytes signed value.
DW_EH_PE_sdata2 = 0x0A, DW_EH_PE_sdata2 = 0x0A,

View file

@ -1,7 +1,8 @@
//! this implements the stuff necessary to get the uwutables for actual unwinding //! this implements the stuff necessary to get the uwutables for actual
//! unwinding
//! //!
//! for this we need a DWARF parser and a DWARF call frame information interpreter (yes, that shit is basically a programming //! for this we need a DWARF parser and a DWARF call frame information
//! language). See https://dwarfstd.org/doc/DWARF5.pdf for more information if more information is desired. //! interpreter (yes, that shit is basically a programming language). See https://dwarfstd.org/doc/DWARF5.pdf for more information if more information is desired.
mod divination; mod divination;
mod parse; mod parse;

View file

@ -11,16 +11,17 @@
//! LN //! LN
//! ``` //! ```
//! //!
//! The first column is the address for every location that contains code in a program //! The first column is the address for every location that contains code in a
//! (a relative offset in shared object files). The remaining columns contain unwinding rules //! program (a relative offset in shared object files). The remaining columns
//! that are associated with the indicated location. //! contain unwinding rules that are associated with the indicated location.
//! //!
//! The CFA column defines the rule which computes the Canonical Frame Address //! The CFA column defines the rule which computes the Canonical Frame Address
//! value; it may be either a register and a signed offset that are added together, or a //! value; it may be either a register and a signed offset that are added
//! DWARF expression that is evaluated. //! together, or a DWARF expression that is evaluated.
//! //!
//! The remaining columns describe register numbers that indicate whether a register has been saved //! The remaining columns describe register numbers that indicate whether a
//! and the rule to find the value for the previous frame. //! register has been saved and the rule to find the value for the previous
//! frame.
#![allow(non_upper_case_globals)] #![allow(non_upper_case_globals)]
#[cfg(test)] #[cfg(test)]
@ -28,7 +29,8 @@ mod tests;
use core::ffi::CStr; use core::ffi::CStr;
use alloc::{format, string::String}; use alloc::format;
use alloc::string::String;
/// The dwarf is invalid. This is fatal and should never happen. /// The dwarf is invalid. This is fatal and should never happen.
#[derive(Debug)] #[derive(Debug)]
@ -41,25 +43,27 @@ pub struct Expr;
#[derive(Debug)] #[derive(Debug)]
enum RegisterRule { enum RegisterRule {
/// A register that has this rule has no recoverable value in the previous frame. /// A register that has this rule has no recoverable value in the previous
/// (By convention, it is not preserved by a callee.) /// frame. (By convention, it is not preserved by a callee.)
Undefined, Undefined,
/// This register has not been modified from the previous frame. /// This register has not been modified from the previous frame.
/// (By convention, it is preserved by the callee, but the callee has not modified it.) /// (By convention, it is preserved by the callee, but the callee has not
/// modified it.)
SameValue, SameValue,
/// The previous value of this register is saved at the address CFA+N where CFA /// The previous value of this register is saved at the address CFA+N where
/// is the current CFA value and N is a signed offset /// CFA is the current CFA value and N is a signed offset
Offset(isize), Offset(isize),
/// The previous value of this register is the value CFA+N where CFA is the current CFA value /// The previous value of this register is the value CFA+N where CFA is the
/// and N is a signed offset. /// current CFA value and N is a signed offset.
ValOffset(isize), ValOffset(isize),
/// The previous value of this register is stored in another register numbered R. /// The previous value of this register is stored in another register
/// numbered R.
Register(u16), Register(u16),
/// The previous value of this register is located at the address produced by /// The previous value of this register is located at the address produced
/// executing the DWARF expression E (see Section 2.5 on page 26) /// by executing the DWARF expression E (see Section 2.5 on page 26)
Expression(Expr), Expression(Expr),
/// The previous value of this register is the value produced by executing the DWARF /// The previous value of this register is the value produced by executing
/// expression E (see Section 2.5 on page 26). /// the DWARF expression E (see Section 2.5 on page 26).
ValExpression(Expr), ValExpression(Expr),
/// The rule is defined externally to this specification by the augmenter. /// The rule is defined externally to this specification by the augmenter.
Architectural, Architectural,
@ -85,44 +89,48 @@ impl ILeb128 {
/// Common Information Entry /// Common Information Entry
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Cie<'a> { pub struct Cie<'a> {
/// A null-terminated UTF-8 string that identifies the augmentation to this CIE or /// A null-terminated UTF-8 string that identifies the augmentation to this
/// to the FDEs that use it. If a reader encounters an augmentation string that is /// CIE or to the FDEs that use it. If a reader encounters an
/// unexpected, then only the following fields can be read: /// augmentation string that is unexpected, then only the following
/// fields can be read:
/// - CIE: length, CIE_id, version, augmentation /// - CIE: length, CIE_id, version, augmentation
/// - FDE: length, CIE_pointer, initial_location, address_range /// - FDE: length, CIE_pointer, initial_location, address_range
/// ///
/// If there is no augmentation, this value is a zero byte. /// If there is no augmentation, this value is a zero byte.
/// ///
/// The augmentation string allows users to indicate that there is additional /// The augmentation string allows users to indicate that there is
/// target-specific information in the CIE or FDE which is needed to virtually unwind a /// additional target-specific information in the CIE or FDE which is
/// stack frame. For example, this might be information about dynamically allocated data /// needed to virtually unwind a stack frame. For example, this might be
/// which needs to be freed on exit from the routine. /// information about dynamically allocated data which needs to be freed
/// on exit from the routine.
/// ///
/// Because the .debug_frame section is useful independently of any .debug_info /// Because the .debug_frame section is useful independently of any
/// section, the augmentation string always uses UTF-8 encoding. /// .debug_info section, the augmentation string always uses UTF-8
/// encoding.
pub augmentation: &'a str, pub augmentation: &'a str,
/// A constant that is factored out of all advance location instructions (see /// A constant that is factored out of all advance location instructions
/// Section 6.4.2.1 on page 177). The resulting value is /// (see Section 6.4.2.1 on page 177). The resulting value is
/// (operand * code_alignment_factor). /// (operand * code_alignment_factor).
pub code_alignment_factor: u128, pub code_alignment_factor: u128,
/// A constant that is factored out of certain offset instructions (see /// A constant that is factored out of certain offset instructions (see
/// Sections 6.4.2.2 on page 177 and 6.4.2.3 on page 179). The resulting value is /// Sections 6.4.2.2 on page 177 and 6.4.2.3 on page 179). The resulting
/// (operand * data_alignment_factor). /// value is (operand * data_alignment_factor).
pub data_alignment_factor: i128, pub data_alignment_factor: i128,
/// An unsigned LEB128 constant that indicates which column in the rule table /// An unsigned LEB128 constant that indicates which column in the rule
/// represents the return address of the function. Note that this column might not /// table represents the return address of the function. Note that this
/// correspond to an actual machine register. /// column might not correspond to an actual machine register.
pub return_address_register: u128, pub return_address_register: u128,
/// A block of data whose contents are defined by the contents of the Augmentation /// A block of data whose contents are defined by the contents of the
/// String as described below. This field is only present if the Augmentation String /// Augmentation String as described below. This field is only present
/// contains the character 'z'. The size of this data is given by the Augentation Length. /// if the Augmentation String contains the character 'z'. The size of
/// this data is given by the Augentation Length.
pub augmentation_data: Option<&'a [u8]>, pub augmentation_data: Option<&'a [u8]>,
/// A sequence of rules that are interpreted to create the initial setting of each /// A sequence of rules that are interpreted to create the initial setting
/// column in the table. /// of each column in the table.
/// The default rule for all columns before interpretation of the initial instructions /// The default rule for all columns before interpretation of the initial
/// is the undefined rule. However, an ABI authoring body or a compilation /// instructions is the undefined rule. However, an ABI authoring body
/// system authoring body may specify an alternate default value for any or all /// or a compilation system authoring body may specify an alternate
/// columns. /// default value for any or all columns.
pub initial_instructions: &'a [u8], pub initial_instructions: &'a [u8],
} }
@ -130,20 +138,22 @@ pub struct Cie<'a> {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Fde<'a> { pub struct Fde<'a> {
/// A constant that gives the number of bytes of the header and instruction /// A constant that gives the number of bytes of the header and instruction
/// stream for this function, not including the length field itself (see Section 7.2.2 /// stream for this function, not including the length field itself (see
/// on page 184). The size of the length field plus the value of length must be an /// Section 7.2.2 on page 184). The size of the length field plus the
/// integral multiple of the address size. /// value of length must be an integral multiple of the address size.
pub length: usize, pub length: usize,
/// A constant offset into the .debug_frame section that denotes the CIE that is /// A constant offset into the .debug_frame section that denotes the CIE
/// associated with this FDE. /// that is associated with this FDE.
pub cie_pointer: Id, pub cie_pointer: Id,
/// The address of the first location associated with this table entry. If the /// The address of the first location associated with this table entry. If
/// segment_selector_size field of this FDEs CIE is non-zero, the initial /// the segment_selector_size field of this FDEs CIE is non-zero, the
/// location is preceded by a segment selector of the given length. /// initial location is preceded by a segment selector of the given
/// length.
pub initial_location: usize, pub initial_location: usize,
/// The number of bytes of program instructions described by this entry. /// The number of bytes of program instructions described by this entry.
pub address_range: usize, pub address_range: usize,
/// A sequence of table defining instructions that are described in Section 6.4.2. /// A sequence of table defining instructions that are described in Section
/// 6.4.2.
pub instructions: &'a [u8], pub instructions: &'a [u8],
} }
@ -152,17 +162,20 @@ pub enum Instruction {
//-------- 6.4.2.1 Row Creation Instructions //-------- 6.4.2.1 Row Creation Instructions
// //
/// The DW_CFA_set_loc instruction takes a single operand that represents a /// The DW_CFA_set_loc instruction takes a single operand that represents a
/// target address. The required action is to create a new table row using the /// target address. The required action is to create a new table row using
/// specified address as the location. All other values in the new row are initially /// the specified address as the location. All other values in the new
/// identical to the current row. The new location value is always greater than the /// row are initially identical to the current row. The new location
/// current one. If the segment_selector_size field of this FDEs CIE is non-zero, /// value is always greater than the current one. If the
/// the initial location is preceded by a segment selector of the given length. /// segment_selector_size field of this FDEs CIE is non-zero,
/// the initial location is preceded by a segment selector of the given
/// length.
SetLoc(usize), SetLoc(usize),
/// The DW_CFA_advance_loc instruction takes a single operand (encoded with /// The DW_CFA_advance_loc instruction takes a single operand (encoded with
/// the opcode) that represents a constant delta. The required action is to create a /// the opcode) that represents a constant delta. The required action is to
/// new table row with a location value that is computed by taking the current /// create a new table row with a location value that is computed by
/// entrys location value and adding the value of delta * code_alignment_factor. /// taking the current entrys location value and adding the value of
/// All other values in the new row are initially identical to the current row /// delta * code_alignment_factor. All other values in the new row are
/// initially identical to the current row
AdvanceLoc(u8), AdvanceLoc(u8),
/// The DW_CFA_advance_loc1 instruction takes a single ubyte operand that /// The DW_CFA_advance_loc1 instruction takes a single ubyte operand that
/// represents a constant delta. This instruction is identical to /// represents a constant delta. This instruction is identical to
@ -181,67 +194,69 @@ pub enum Instruction {
// //
/// The DW_CFA_def_cfa instruction takes two unsigned LEB128 operands /// The DW_CFA_def_cfa instruction takes two unsigned LEB128 operands
/// representing a register number and a (non-factored) offset. The required /// representing a register number and a (non-factored) offset. The required
/// action is to define the current CFA rule to use the provided register and offset /// action is to define the current CFA rule to use the provided register
/// and offset
DefCfa { DefCfa {
register_number: ULeb128, register_number: ULeb128,
offset: ULeb128, offset: ULeb128,
}, },
/// The DW_CFA_def_cfa_sf instruction takes two operands: an unsigned /// The DW_CFA_def_cfa_sf instruction takes two operands: an unsigned
/// LEB128 value representing a register number and a signed LEB128 factored /// LEB128 value representing a register number and a signed LEB128 factored
/// offset. This instruction is identical to DW_CFA_def_cfa except that the second /// offset. This instruction is identical to DW_CFA_def_cfa except that the
/// operand is signed and factored. The resulting offset is factored_offset * /// second operand is signed and factored. The resulting offset is
/// data_alignment_factor. /// factored_offset * data_alignment_factor.
DefCfaSf { DefCfaSf {
register_number: ULeb128, register_number: ULeb128,
offset: ULeb128, offset: ULeb128,
}, },
/// The DW_CFA_def_cfa_register instruction takes a single unsigned LEB128 /// The DW_CFA_def_cfa_register instruction takes a single unsigned LEB128
/// operand representing a register number. The required action is to define the /// operand representing a register number. The required action is to define
/// current CFA rule to use the provided register (but to keep the old offset). This /// the current CFA rule to use the provided register (but to keep the
/// operation is valid only if the current CFA rule is defined to use a register and /// old offset). This operation is valid only if the current CFA rule is
/// offset. /// defined to use a register and offset.
DefCfaRegister(ULeb128), DefCfaRegister(ULeb128),
/// The DW_CFA_def_cfa_offset instruction takes a single unsigned LEB128 /// The DW_CFA_def_cfa_offset instruction takes a single unsigned LEB128
/// operand representing a (non-factored) offset. The required action is to define /// operand representing a (non-factored) offset. The required action is to
/// the current CFA rule to use the provided offset (but to keep the old register). /// define the current CFA rule to use the provided offset (but to keep
/// This operation is valid only if the current CFA rule is defined to use a register /// the old register). This operation is valid only if the current CFA
/// and offset. /// rule is defined to use a register and offset.
DefCfaOffset(ULeb128), DefCfaOffset(ULeb128),
/// The DW_CFA_def_cfa_offset_sf instruction takes a signed LEB128 operand /// The DW_CFA_def_cfa_offset_sf instruction takes a signed LEB128 operand
/// representing a factored offset. This instruction is identical to /// representing a factored offset. This instruction is identical to
/// DW_CFA_def_cfa_offset except that the operand is signed and factored. The /// DW_CFA_def_cfa_offset except that the operand is signed and factored.
/// resulting offset is factored_offset * data_alignment_factor. This operation is /// The resulting offset is factored_offset * data_alignment_factor.
/// valid only if the current CFA rule is defined to use a register and offset. /// This operation is valid only if the current CFA rule is defined to
/// use a register and offset.
DefCfaOffsetSf(ULeb128), DefCfaOffsetSf(ULeb128),
/// The DW_CFA_def_cfa_expression instruction takes a single operand encoded /// The DW_CFA_def_cfa_expression instruction takes a single operand encoded
/// as a DW_FORM_exprloc value representing a DWARF expression. The /// as a DW_FORM_exprloc value representing a DWARF expression. The
/// required action is to establish that expression as the means by which the /// required action is to establish that expression as the means by which
/// current CFA is computed. /// the current CFA is computed.
DefCfaExpression(Expr), DefCfaExpression(Expr),
// //
//-------- 6.4.2.3 Register Rule Instructions //-------- 6.4.2.3 Register Rule Instructions
// //
/// The DW_CFA_undefined instruction takes a single unsigned LEB128 operand /// The DW_CFA_undefined instruction takes a single unsigned LEB128 operand
/// that represents a register number. The required action is to set the rule for the /// that represents a register number. The required action is to set the
/// specified register to “undefined.” /// rule for the specified register to “undefined.”
Undefined(ULeb128), Undefined(ULeb128),
/// The DW_CFA_same_value instruction takes a single unsigned LEB128 /// The DW_CFA_same_value instruction takes a single unsigned LEB128
/// operand that represents a register number. The required action is to set the /// operand that represents a register number. The required action is to set
/// rule for the specified register to “same value.” /// the rule for the specified register to “same value.”
SameValue(ULeb128), SameValue(ULeb128),
/// The DW_CFA_offset instruction takes two operands: a register number /// The DW_CFA_offset instruction takes two operands: a register number
/// (encoded with the opcode) and an unsigned LEB128 constant representing a /// (encoded with the opcode) and an unsigned LEB128 constant representing a
/// factored offset. The required action is to change the rule for the register /// factored offset. The required action is to change the rule for the
/// indicated by the register number to be an offset(N) rule where the value of N /// register indicated by the register number to be an offset(N) rule
/// is factored offset * data_alignment_factor. /// where the value of N is factored offset * data_alignment_factor.
Offset { Offset {
register_number: usize, register_number: usize,
factored_offset: ULeb128, factored_offset: ULeb128,
}, },
/// The DW_CFA_offset_extended instruction takes two unsigned LEB128 /// The DW_CFA_offset_extended instruction takes two unsigned LEB128
/// operands representing a register number and a factored offset. This /// operands representing a register number and a factored offset. This
/// instruction is identical to DW_CFA_offset except for the encoding and size of /// instruction is identical to DW_CFA_offset except for the encoding and
/// the register operand. /// size of the register operand.
OffsetExtended { OffsetExtended {
register_number: ULeb128, register_number: ULeb128,
factored_offset: ULeb128, factored_offset: ULeb128,
@ -249,81 +264,85 @@ pub enum Instruction {
/// The DW_CFA_offset_extended_sf instruction takes two operands: an /// The DW_CFA_offset_extended_sf instruction takes two operands: an
/// unsigned LEB128 value representing a register number and a signed LEB128 /// unsigned LEB128 value representing a register number and a signed LEB128
/// factored offset. This instruction is identical to DW_CFA_offset_extended /// factored offset. This instruction is identical to DW_CFA_offset_extended
/// except that the second operand is signed and factored. The resulting offset is /// except that the second operand is signed and factored. The resulting
/// factored_offset * data_alignment_factor. /// offset is factored_offset * data_alignment_factor.
OffsetExtendedSf { OffsetExtendedSf {
register_number: ULeb128, register_number: ULeb128,
factored_offste: ULeb128, factored_offste: ULeb128,
}, },
/// The DW_CFA_val_offset instruction takes two unsigned LEB128 operands /// The DW_CFA_val_offset instruction takes two unsigned LEB128 operands
/// representing a register number and a factored offset. The required action is to /// representing a register number and a factored offset. The required
/// change the rule for the register indicated by the register number to be a /// action is to change the rule for the register indicated by the
/// val_offset(N) rule where the value of N is factored_offset * /// register number to be a val_offset(N) rule where the value of N is
/// data_alignment_factor. /// factored_offset * data_alignment_factor.
ValOffset { ValOffset {
register_number: ULeb128, register_number: ULeb128,
factored_offste: ULeb128, factored_offste: ULeb128,
}, },
/// The DW_CFA_val_offset_sf instruction takes two operands: an unsigned /// The DW_CFA_val_offset_sf instruction takes two operands: an unsigned
/// LEB128 value representing a register number and a signed LEB128 factored /// LEB128 value representing a register number and a signed LEB128 factored
/// offset. This instruction is identical to DW_CFA_val_offset except that the /// offset. This instruction is identical to DW_CFA_val_offset except that
/// second operand is signed and factored. The resulting offset is factored_offset * /// the second operand is signed and factored. The resulting offset is
/// data_alignment_factor. /// factored_offset * data_alignment_factor.
ValOffsetSf { ValOffsetSf {
register_number: ULeb128, register_number: ULeb128,
factored_offste: ULeb128, factored_offste: ULeb128,
}, },
/// The DW_CFA_register instruction takes two unsigned LEB128 operands /// The DW_CFA_register instruction takes two unsigned LEB128 operands
/// representing register numbers. The required action is to set the rule for the /// representing register numbers. The required action is to set the rule
/// first register to be register(R) where R is the second register. /// for the first register to be register(R) where R is the second
/// register.
Register { Register {
target_register: ULeb128, target_register: ULeb128,
from_register: ULeb128, from_register: ULeb128,
}, },
/// The DW_CFA_expression instruction takes two operands: an unsigned /// The DW_CFA_expression instruction takes two operands: an unsigned
/// LEB128 value representing a register number, and a DW_FORM_block value /// LEB128 value representing a register number, and a DW_FORM_block value
/// representing a DWARF expression. The required action is to change the rule /// representing a DWARF expression. The required action is to change the
/// for the register indicated by the register number to be an expression(E) rule /// rule for the register indicated by the register number to be an
/// where E is the DWARF expression. That is, the DWARF expression computes /// expression(E) rule where E is the DWARF expression. That is, the
/// the address. The value of the CFA is pushed on the DWARF evaluation stack /// DWARF expression computes the address. The value of the CFA is
/// prior to execution of the DWARF expression. /// pushed on the DWARF evaluation stack prior to execution of the DWARF
/// See Section 6.4.2 on page 176 regarding restrictions on the DWARF expression /// expression. See Section 6.4.2 on page 176 regarding restrictions on
/// operators that can be used. /// the DWARF expression operators that can be used.
Expression { register: ULeb128, expr: Expr }, Expression { register: ULeb128, expr: Expr },
/// The DW_CFA_val_expression instruction takes two operands: an unsigned /// The DW_CFA_val_expression instruction takes two operands: an unsigned
/// LEB128 value representing a register number, and a DW_FORM_block value /// LEB128 value representing a register number, and a DW_FORM_block value
/// representing a DWARF expression. The required action is to change the rule /// representing a DWARF expression. The required action is to change the
/// for the register indicated by the register number to be a val_expression(E) /// rule for the register indicated by the register number to be a
/// rule where E is the DWARF expression. That is, the DWARF expression /// val_expression(E) rule where E is the DWARF expression. That is, the
/// computes the value of the given register. The value of the CFA is pushed on /// DWARF expression computes the value of the given register. The value
/// the DWARF evaluation stack prior to execution of the DWARF expression. /// of the CFA is pushed on the DWARF evaluation stack prior to
/// See Section 6.4.2 on page 176 regarding restrictions on the DWARF expression /// execution of the DWARF expression. See Section 6.4.2 on page 176
/// operators that can be used. /// regarding restrictions on the DWARF expression operators that can be
/// used.
ValExpression { register: ULeb128, expr: Expr }, ValExpression { register: ULeb128, expr: Expr },
/// The DW_CFA_restore instruction takes a single operand (encoded with the /// The DW_CFA_restore instruction takes a single operand (encoded with the
/// opcode) that represents a register number. The required action is to change /// opcode) that represents a register number. The required action is to
/// the rule for the indicated register to the rule assigned it by the /// change the rule for the indicated register to the rule assigned it
/// initial_instructions in the CIE. /// by the initial_instructions in the CIE.
Restore(usize), Restore(usize),
/// The DW_CFA_restore_extended instruction takes a single unsigned LEB128 /// The DW_CFA_restore_extended instruction takes a single unsigned LEB128
/// operand that represents a register number. This instruction is identical to /// operand that represents a register number. This instruction is identical
/// DW_CFA_restore except for the encoding and size of the register operand. /// to DW_CFA_restore except for the encoding and size of the register
/// operand.
RestoreExtended(ULeb128), RestoreExtended(ULeb128),
// //
//-------- 6.4.2.4 Row State Instructions //-------- 6.4.2.4 Row State Instructions
// //
/// The DW_CFA_remember_state instruction takes no operands. The required /// The DW_CFA_remember_state instruction takes no operands. The required
/// action is to push the set of rules for every register onto an implicit stack. /// action is to push the set of rules for every register onto an implicit
/// stack.
RememberState, RememberState,
/// The DW_CFA_restore_state instruction takes no operands. The required /// The DW_CFA_restore_state instruction takes no operands. The required
/// action is to pop the set of rules off the implicit stack and place them in the /// action is to pop the set of rules off the implicit stack and place them
/// current row. /// in the current row.
RestoreState, RestoreState,
// //
//-------- 6.4.2.5 Padding Instruction //-------- 6.4.2.5 Padding Instruction
// //
/// The DW_CFA_nop instruction has no operands and no required actions. It is /// The DW_CFA_nop instruction has no operands and no required actions. It
/// used as padding to make a CIE or FDE an appropriate size. /// is used as padding to make a CIE or FDE an appropriate size.
Nop, Nop,
} }
@ -474,29 +493,34 @@ fn parse_augmentation_data(string: &str, data: &[u8]) -> Result<()> {
assert_eq!(codes.next(), Some(b'z')); assert_eq!(codes.next(), Some(b'z'));
trace!("aug data {:x?}", data.0); trace!("aug data {:x?}", data.0);
let mut aug_data = AugmentationData {pointer_encoding: None}; let mut aug_data = AugmentationData {
pointer_encoding: None,
};
for code in codes { for code in codes {
match code { match code {
// If present, it indicates the presence of one argument in the Augmentation Data of the CIE, // If present, it indicates the presence of one argument in the Augmentation Data of the
// and a corresponding argument in the Augmentation Data of the FDE. // CIE, and a corresponding argument in the Augmentation Data of the FDE.
// The argument in the Augmentation Data of the CIE is 1-byte and represents the pointer encoding // The argument in the Augmentation Data of the CIE is 1-byte and represents the pointer
// used for the argument in the Augmentation Data of the FDE, which is the address of a language-specific // encoding used for the argument in the Augmentation Data of the FDE, which
// data area (LSDA). The size of the LSDA pointer is specified by the pointer encoding used. // is the address of a language-specific data area (LSDA). The size of the
// LSDA pointer is specified by the pointer encoding used.
b'L' => { b'L' => {
let encoding = read_u8(data)?; let encoding = read_u8(data)?;
aug_data.lsda_pointer_encoding = Some(encoding); aug_data.lsda_pointer_encoding = Some(encoding);
} }
// If present, it indicates the presence of two arguments in the Augmentation Data of the CIE. // If present, it indicates the presence of two arguments in the Augmentation Data of
// The first argument is 1-byte and represents the pointer encoding used for the second argument, // the CIE. The first argument is 1-byte and represents the pointer encoding
// which is the address of a personality routine handler. The personality routine is used to handle // used for the second argument, which is the address of a personality
// language and vendor-specific tasks. The system unwind library interface accesses the language-specific // routine handler. The personality routine is used to handle language and
// exception handling semantics via the pointer to the personality routine. The personality routine does not // vendor-specific tasks. The system unwind library interface accesses the
// have an ABI-specific name. The size of the personality routine pointer is specified by the pointer encoding used. // language-specific exception handling semantics via the pointer to the
b'P' => { // personality routine. The personality routine does not
// have an ABI-specific name. The size of the personality routine pointer is specified
} // by the pointer encoding used.
// If present, The Augmentation Data shall include a 1 byte argument that represents the pointer encoding for the address pointers used in the FDE. b'P' => {}
// If present, The Augmentation Data shall include a 1 byte argument that represents the
// pointer encoding for the address pointers used in the FDE.
b'R' => { b'R' => {
let encoding = read_u8(data)?; let encoding = read_u8(data)?;
aug_data.pointer_encoding = Some(encoding); aug_data.pointer_encoding = Some(encoding);
@ -512,9 +536,10 @@ pub(super) struct InstrIter {
} }
impl InstrIter { impl InstrIter {
/// Create a new `InstrIter` that will parse DWARF call frame information from `data`. /// Create a new `InstrIter` that will parse DWARF call frame information
/// # Safety /// from `data`. # Safety
/// `data` must be a pointer to valid DWARF call frame information with a null terminator. /// `data` must be a pointer to valid DWARF call frame information with a
/// null terminator.
pub(super) unsafe fn new(data: *const u8) -> Self { pub(super) unsafe fn new(data: *const u8) -> Self {
// SAFETY: uses random ass pointer // SAFETY: uses random ass pointer
Self { data } Self { data }
@ -523,10 +548,11 @@ impl InstrIter {
fn advance(&mut self) -> Option<u8> { fn advance(&mut self) -> Option<u8> {
// SAFETY: First, we assume that `data` currently points at a valid location. // SAFETY: First, we assume that `data` currently points at a valid location.
// After we read from it, we increment it. This has implications. We must assume // After we read from it, we increment it. This has implications. We must assume
// that the dwarf parsing code in this module never calls `advance` more than it has to. // that the dwarf parsing code in this module never calls `advance` more than it
// This means that really `advance` should be unsafe, but marking it as unsafe would only make // has to. This means that really `advance` should be unsafe, but
// the code in here harder to read and not provide practical safety improvements. // marking it as unsafe would only make the code in here harder to read
// We do eagerly move the data pointer outside the bounds of the allocation, but only one // and not provide practical safety improvements. We do eagerly move the
// data pointer outside the bounds of the allocation, but only one
// past the end, which is fine. // past the end, which is fine.
unsafe { unsafe {
let first = self.data.read(); let first = self.data.read();

View file

@ -3,7 +3,8 @@
extern crate alloc; extern crate alloc;
use core::{ffi, sync::atomic::AtomicPtr}; use core::ffi;
use core::sync::atomic::AtomicPtr;
// Get the macros into our local prelude. // Get the macros into our local prelude.
#[macro_use] #[macro_use]
@ -36,8 +37,8 @@ pub unsafe extern "C" fn _UnwindRaiseException(
stdext::abort(); stdext::abort();
} }
// This is normally provided by the language runtime through the unwind info block. // This is normally provided by the language runtime through the unwind info
// We don't want to access that usually because Rust messes with it :(. // block. We don't want to access that usually because Rust messes with it :(.
static PERSONALITY_ROUTINE: AtomicPtr<()> = AtomicPtr::new(core::ptr::null_mut()); static PERSONALITY_ROUTINE: AtomicPtr<()> = AtomicPtr::new(core::ptr::null_mut());
pub unsafe fn set_personality_routine(routine: uw::PersonalityRoutine) { pub unsafe fn set_personality_routine(routine: uw::PersonalityRoutine) {

View file

@ -50,7 +50,8 @@ pub(crate) fn with_last_os_error_str<R>(f: impl FnOnce(&str) -> R) -> R {
// SAFETY: Our buffer length is passed correctly // SAFETY: Our buffer length is passed correctly
let error = unsafe { libc::strerror_r(errno(), buf.as_mut_ptr().cast(), buf.len()) }; let error = unsafe { libc::strerror_r(errno(), buf.as_mut_ptr().cast(), buf.len()) };
// SAFETY: strerror_r writes the string to buf, even if it didnt write anything, we did zero init it. // SAFETY: strerror_r writes the string to buf, even if it didnt write anything,
// we did zero init it.
let cstr = if error != 0 { let cstr = if error != 0 {
ffi::CStr::from_bytes_with_nul(b"<strerror_r returned an error>\n").unwrap() ffi::CStr::from_bytes_with_nul(b"<strerror_r returned an error>\n").unwrap()
} else { } else {

View file

@ -7,14 +7,17 @@ pub enum _Unwind_Reason_Code {
/// Nested foreign exceptions, or re-throwing a foreign exception, result in /// Nested foreign exceptions, or re-throwing a foreign exception, result in
/// undefined behavior. /// undefined behavior.
_URC_FOREIGN_EXCEPTION_CAUGHT = 1, _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
/// The personality routine encountered an error during phase 1, other than the specific error codes defined. /// The personality routine encountered an error during phase 1, other than
/// the specific error codes defined.
_URC_FATAL_PHASE1_ERROR = 3, _URC_FATAL_PHASE1_ERROR = 3,
/// The personality routine encountered an error during phase 2, for instance a stack corruption. /// The personality routine encountered an error during phase 2, for
/// instance a stack corruption.
_URC_FATAL_PHASE2_ERROR = 2, _URC_FATAL_PHASE2_ERROR = 2,
_URC_NORMAL_STOP = 4, _URC_NORMAL_STOP = 4,
/// The unwinder encountered the end of the stack during phase 1, without finding a handler. /// The unwinder encountered the end of the stack during phase 1, without
/// The unwind runtime will not have modified the stack. /// finding a handler. The unwind runtime will not have modified the
/// The C++ runtime will normally call uncaught_exception() in this case /// stack. The C++ runtime will normally call uncaught_exception() in
/// this case
_URC_END_OF_STACK = 5, _URC_END_OF_STACK = 5,
_URC_HANDLER_FOUND = 6, _URC_HANDLER_FOUND = 6,
_URC_INSTALL_CONTEXT = 7, _URC_INSTALL_CONTEXT = 7,
@ -32,8 +35,10 @@ pub struct _Unwind_Exception {
pub type _Unwind_Exception_Cleanup_Fn = pub type _Unwind_Exception_Cleanup_Fn =
fn(reason: _Unwind_Reason_Code, exc: *const _Unwind_Exception); fn(reason: _Unwind_Reason_Code, exc: *const _Unwind_Exception);
/// The _Unwind_Context type is an opaque type used to refer to a system-specific data structure used by the system unwinder. /// The _Unwind_Context type is an opaque type used to refer to a
/// This context is created and destroyed by the system, and passed to the personality routine during unwinding /// system-specific data structure used by the system unwinder. This context is
/// created and destroyed by the system, and passed to the personality routine
/// during unwinding
pub struct _Unwind_Context {} pub struct _Unwind_Context {}
pub type PersonalityRoutine = fn( pub type PersonalityRoutine = fn(