mirror of
https://github.com/Noratrieb/uwuwind.git
synced 2026-01-14 08:35:09 +01:00
fmt
This commit is contained in:
parent
7a8a82b476
commit
591da9ff7d
8 changed files with 213 additions and 169 deletions
3
rustfmt.toml
Normal file
3
rustfmt.toml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
reorder_imports = true
|
||||||
|
imports_granularity = "Module"
|
||||||
|
wrap_comments = true
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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 FDE’s CIE is non-zero, the initial
|
/// the segment_selector_size field of this FDE’s 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 FDE’s 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 FDE’s 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
|
||||||
/// entry’s location value and adding the value of delta * code_alignment_factor.
|
/// taking the current entry’s 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();
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
19
src/uw.rs
19
src/uw.rs
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
pub mod fp;
|
pub mod fp;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue