use std::mem::transmute;
pub(crate) type Rva = u32;
pub(crate) fn fast_hex64(buffer: &mut [u8; 16], u: u64) -> &[u8] {
let mut x = u128::from(u);
x = (x & 0xFFFF_FFFF_0000_0000) << 32 | x;
x = ((x & 0xFFFF_0000_0000_0000_FFFF_0000) << 32) | ((x & 0xFFFF_0000_0000_0000_FFFF) << 16);
x = ((x & 0x00FF_0000_00FF_0000_00FF_0000_00FF_0000) >> 16)
| ((x & 0xFF00_0000_FF00_0000_FF00_0000_FF00_0000) >> 8);
x = ((x & 0x00F0_00F0_00F0_00F0_00F0_00F0_00F0_00F0) << 4)
| (x & 0x000F_000F_000F_000F_000F_000F_000F_000F);
let mask = ((x + 0x0606_0606_0606_0606_0606_0606_0606_0606) >> 4)
& 0x0101_0101_0101_0101_0101_0101_0101_0101;
x |= 0x3030_3030_3030_3030_3030_3030_3030_3030;
x += 0x27 * mask;
buffer.copy_from_slice(&x.to_be_bytes());
buffer
}
pub(crate) fn fast_hex32(buffer: &mut [u8; 8], u: u32) -> &[u8] {
let mut x = u64::from(u);
x = (x & 0xFFFF_0000) << 16 | x;
x = ((x & 0x0000_FF00_0000_FF00) << 16) | ((x & 0x0000_00FF_0000_00FF) << 8);
x = ((x & 0xF000_F000_F000_F000) >> 4) | ((x & 0x0F00_0F00_0F00_0F00) >> 8);
let mask = ((x + 0x0606_0606_0606_0606) >> 4) & 0x0101_0101_0101_0101;
x |= 0x3030_3030_3030_3030;
x += 0x27 * mask;
buffer.copy_from_slice(&x.to_be_bytes());
buffer
}
#[derive(Debug, PartialEq)]
pub(crate) struct ParsedFullSymbolName<'s> {
pub module_name: &'s str,
pub function_name: &'s str,
pub offset: u64,
}
pub(crate) fn parse_full_name(full: &str) -> Option<ParsedFullSymbolName<'_>> {
let (module_name, rest) = full.split_once('!')?;
if rest.contains('!') {
return None;
}
let (function_name, offset) = match rest.split_once('+') {
Some((function_name, offset)) => {
if !offset.starts_with("0x") {
return None;
}
(
function_name,
u64::from_str_radix(offset.trim_start_matches("0x"), 16).ok()?,
)
}
None => (rest, 0),
};
Some(ParsedFullSymbolName {
module_name,
function_name,
offset,
})
}
pub(crate) unsafe fn elyxir_of_life<'s>(s: &'s str) -> &'static str {
unsafe { transmute::<&'s str, &'static str>(s) }
}
#[cfg(test)]
mod tests {
use super::{fast_hex32, fast_hex64};
use crate::misc::{ParsedFullSymbolName, parse_full_name};
#[test]
fn hex32() {
let mut buffer = [0; 8];
let out = fast_hex32(&mut buffer, 0xdead_beef);
assert_eq!(out, b"deadbeef");
let out = fast_hex32(&mut buffer, 0xdead);
assert_eq!(out, b"0000dead");
let out = fast_hex32(&mut buffer, 0x0);
assert_eq!(out, b"00000000");
}
#[test]
fn hex64() {
let mut buffer = [0; 16];
let out = fast_hex64(&mut buffer, 0xdead_beef_baad_c0de);
assert_eq!(out, b"deadbeefbaadc0de");
let out = fast_hex64(&mut buffer, 0xdead_beef);
assert_eq!(out, b"00000000deadbeef");
let out = fast_hex64(&mut buffer, 0x0);
assert_eq!(out, b"0000000000000000");
}
#[test]
fn parse() {
assert_eq!(
parse_full_name("yo.dll!func").unwrap(),
ParsedFullSymbolName {
module_name: "yo.dll",
function_name: "func",
offset: 0
}
);
assert_eq!(
parse_full_name("yo!func+0x1337").unwrap(),
ParsedFullSymbolName {
module_name: "yo",
function_name: "func",
offset: 0x1337
}
);
assert!(parse_full_name("yo!!func").is_none());
assert!(parse_full_name("yo!func+1337").is_none());
assert_eq!(
parse_full_name("foo.dll!Microsoft::WRL::Details::ModuleBase::GetMidEntryPointer+0x0")
.unwrap(),
ParsedFullSymbolName {
module_name: "foo.dll",
function_name: "Microsoft::WRL::Details::ModuleBase::GetMidEntryPointer",
offset: 0
}
);
}
}