/// The registers used for unwinding on Aarch64. We only need lr (x30), sp (x31), /// and fp (x29). /// /// We also have a [`PtrAuthMask`] which allows stripping off the pointer authentication /// hash bits from the return address when unwinding through libraries which use pointer /// authentication, e.g. in system libraries on macOS. #[derive(Clone, Copy, PartialEq, Eq)] pubstruct UnwindRegsAarch64 {
lr_mask: PtrAuthMask,
lr: u64,
sp: u64,
fp: u64,
}
/// Aarch64 CPUs support special instructions which interpret pointers as pair /// of the pointer address and an encrypted hash: The address is stored in the /// lower bits and the hash in the high bits. These are called "authenticated" /// pointers. Special instructions exist to verify pointers before dereferencing /// them. /// /// Return address can be such authenticated pointers. To return to an /// authenticated return address, the "retab" instruction is used instead of /// the regular "ret" instruction. /// /// Stack walkers need to strip the encrypted hash from return addresses because /// they need the raw code address. /// /// On macOS arm64, system libraries compiled with the arm64e target use pointer /// pointer authentication for return addresses. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pubstruct PtrAuthMask(pub u64);
impl PtrAuthMask { /// Create a no-op mask which treats all bits of the pointer as address bits, /// so no bits are stripped. pubfn new_no_strip() -> Self { Self(u64::MAX)
}
/// Create a mask for 24 bits hash + 40 bits pointer. This appears to be /// what macOS arm64e uses. It is unclear whether we can rely on this or /// whether it can change. /// /// On macOS arm64, this mask can be applied to both authenticated pointers /// and to non-authenticated pointers without data loss; non-authenticated /// don't appear to use the top 24 bits (they're always zero). pubfn new_24_40() -> Self { Self(u64::MAX >> 24)
}
/// Deduce a mask based on the highest known address. The leading zero bits /// in this address will be reserved for the hash. pubfn from_max_known_address(address: u64) -> Self { Self(u64::MAX >> address.leading_zeros())
}
/// Apply the mask to the given pointer. #[inline(always)] pubfn strip_ptr_auth(&self, ptr: u64) -> u64 {
ptr & self.0
}
}
impl UnwindRegsAarch64 { /// Create a set of unwind register values and do not apply any pointer /// authentication stripping. pubfn new(lr: u64, sp: u64, fp: u64) -> Self { Self {
lr_mask: PtrAuthMask::new_no_strip(),
lr,
sp,
fp,
}
}
/// Create a set of unwind register values with the given mask for return /// address pointer authentication stripping. pubfn new_with_ptr_auth_mask(
code_ptr_auth_mask: PtrAuthMask,
lr: u64,
sp: u64,
fp: u64,
) -> Self { Self {
lr_mask: code_ptr_auth_mask,
lr: code_ptr_auth_mask.strip_ptr_auth(lr),
sp,
fp,
}
}
/// Get the [`PtrAuthMask`] which we apply to the `lr` value. #[inline(always)] pubfn lr_mask(&self) -> PtrAuthMask { self.lr_mask
}
/// Get the stack pointer value. #[inline(always)] pubfn sp(&self) -> u64 { self.sp
}
/// Set the stack pointer value. #[inline(always)] pubfn set_sp(&mutself, sp: u64) { self.sp = sp
}
/// Get the frame pointer value (x29). #[inline(always)] pubfn fp(&self) -> u64 { self.fp
}
/// Set the frame pointer value (x29). #[inline(always)] pubfn set_fp(&mutself, fp: u64) { self.fp = fp
}
/// Get the lr register value. #[inline(always)] pubfn lr(&self) -> u64 { self.lr
}
/// Set the lr register value. #[inline(always)] pubfn set_lr(&mutself, lr: u64) { self.lr = self.lr_mask.strip_ptr_auth(lr)
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.