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
//!
//! 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
//! (where we will find the dwarves)
//!
//! first, we ask the dynamic linker to give us the `.eh_frame` for the current 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.
//! first, we ask the dynamic linker to give us the `.eh_frame` for the current
//! 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.
#![allow(non_camel_case_types)]
@ -23,7 +25,8 @@ struct dl_find_object {
dlfo_map_start: *const ffi::c_void,
dlfo_map_end: *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,
}
@ -164,7 +167,9 @@ impl fmt::Debug for Encoding {
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
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,
/// A 2 bytes unsigned value.
DW_EH_PE_udata2 = 0x02,
@ -172,7 +177,9 @@ enum ValueFormat {
DW_EH_PE_udata4 = 0x03,
/// An 8 bytes unsigned value.
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,
/// A 2 bytes signed value.
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
//! language). See https://dwarfstd.org/doc/DWARF5.pdf for more information if more information is desired.
//! for this we need a DWARF parser and a DWARF call frame information
//! 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 parse;

View file

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

View file

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

View file

@ -7,14 +7,17 @@ pub enum _Unwind_Reason_Code {
/// Nested foreign exceptions, or re-throwing a foreign exception, result in
/// undefined behavior.
_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,
/// 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_NORMAL_STOP = 4,
/// The unwinder encountered the end of the stack during phase 1, without finding a handler.
/// The unwind runtime will not have modified the stack.
/// The C++ runtime will normally call uncaught_exception() in this case
/// The unwinder encountered the end of the stack during phase 1, without
/// finding a handler. The unwind runtime will not have modified the
/// stack. The C++ runtime will normally call uncaught_exception() in
/// this case
_URC_END_OF_STACK = 5,
_URC_HANDLER_FOUND = 6,
_URC_INSTALL_CONTEXT = 7,
@ -32,8 +35,10 @@ pub struct _Unwind_Exception {
pub type _Unwind_Exception_Cleanup_Fn =
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.
/// This context is created and destroyed by the system, and passed to the personality routine during unwinding
/// The _Unwind_Context type is an opaque type used to refer to a
/// 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 type PersonalityRoutine = fn(