Expose PCs table to map coverage bitmap entries to the corresponding code (#1812)

This table allows users to map between coverage bitmap entries and the
corresponding code in memory.
This commit is contained in:
Marco Vanotti 2024-01-25 10:51:13 -05:00 committed by GitHub
parent 59945fbcc9
commit e6184936ce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 75 additions and 6 deletions

View File

@ -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

View File

@ -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::<PcTableEntry>(),
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(),
))
}
}