diff --git a/libafl_targets/src/sancov_cmp.c b/libafl_targets/src/sancov_cmp.c index a00a954e02..c39553e75e 100644 --- a/libafl_targets/src/sancov_cmp.c +++ b/libafl_targets/src/sancov_cmp.c @@ -182,12 +182,6 @@ void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1, #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" -void __sanitizer_cov_pcs_init(const uintptr_t *pcs_beg, - const uintptr_t *pcs_end) { - // unused - // TODO implement -} - void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) { // unused // TODO implement diff --git a/libafl_targets/src/sancov_cmp.rs b/libafl_targets/src/sancov_cmp.rs index fbb60a983c..0d71e17176 100644 --- a/libafl_targets/src/sancov_cmp.rs +++ b/libafl_targets/src/sancov_cmp.rs @@ -1,4 +1,10 @@ //! Sanitizer Coverage comparison functions + +use core::{mem, ptr, slice}; + +static mut PCS_BEG: *const usize = ptr::null(); +static mut PCS_END: *const usize = ptr::null(); + extern "C" { /// Trace an 8 bit `cmp` @@ -23,3 +29,72 @@ extern "C" { pub fn __sanitizer_cov_trace_switch(val: u64, cases: *const u64); } + +#[no_mangle] +unsafe extern "C" fn __sanitizer_cov_pcs_init(pcs_beg: *const usize, pcs_end: *const usize) { + // "The Unsafe Code Guidelines also notably defines that usize and isize are respectively compatible with uintptr_t and intptr_t defined in C." + assert!( + PCS_BEG.is_null(), + "__sanitizer_cov_pcs_init can be called only once." + ); + assert!( + PCS_END.is_null(), + "__sanitizer_cov_pcs_init can be called only once." + ); + + PCS_BEG = pcs_beg; + PCS_END = pcs_end; +} + +/// An entry to the `sanitizer_cov` `pc_table` +#[repr(C, packed)] +#[derive(Debug, PartialEq, Eq)] +pub struct PcTableEntry { + addr: usize, + flags: usize, +} + +impl PcTableEntry { + /// Returns whether the PC corresponds to a function entry point. + #[must_use] + pub fn is_function_entry(&self) -> bool { + self.flags == 0x1 + } + + /// Returns the address associated with this PC. + #[must_use] + pub fn addr(&self) -> usize { + self.addr + } +} + +/// Returns a slice containing the PC table. +#[must_use] +pub fn sanitizer_cov_pc_table() -> Option<&'static [PcTableEntry]> { + // SAFETY: Once PCS_BEG and PCS_END have been initialized, will not be written to again. So + // there's no TOCTOU issue. + unsafe { + if PCS_BEG.is_null() || PCS_END.is_null() { + return None; + } + let len = PCS_END.offset_from(PCS_BEG); + assert!( + len > 0, + "Invalid PC Table bounds - start: {PCS_BEG:x?} end: {PCS_END:x?}" + ); + assert_eq!( + len % 2, + 0, + "PC Table size is not evens - start: {PCS_BEG:x?} end: {PCS_END:x?}" + ); + assert_eq!( + (PCS_BEG as usize) % mem::align_of::(), + 0, + "Unaligned PC Table - start: {PCS_BEG:x?} end: {PCS_END:x?}" + ); + Some(slice::from_raw_parts( + PCS_BEG as *const PcTableEntry, + (len / 2).try_into().unwrap(), + )) + } +}