fix cases
This commit is contained in:
@@ -36,7 +36,7 @@ impl<'a, S: Scannable + ?Sized> Scanner<'a, S> {
|
|||||||
let upper_limit = self.range.end;
|
let upper_limit = self.range.end;
|
||||||
while let Some(address) = scan_for_aob(self.bin, self.cursor..upper_limit, aob) {
|
while let Some(address) = scan_for_aob(self.bin, self.cursor..upper_limit, aob) {
|
||||||
self.cursor = address + 1;
|
self.cursor = address + 1;
|
||||||
if exec(self.bin, address, self.pat, saves, self.range.clone()) {
|
if exec(self.bin, address, self.pat, saves, self.range.clone()).is_some() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,7 +46,7 @@ impl<'a, S: Scannable + ?Sized> Scanner<'a, S> {
|
|||||||
while self.range.contains(&self.cursor) {
|
while self.range.contains(&self.cursor) {
|
||||||
let current_cursor = self.cursor;
|
let current_cursor = self.cursor;
|
||||||
self.cursor += 1;
|
self.cursor += 1;
|
||||||
if exec(self.bin, current_cursor, self.pat, saves, self.range.clone()) {
|
if exec(self.bin, current_cursor, self.pat, saves, self.range.clone()).is_some() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ pub fn exec<Binary: Scannable + ?Sized>(
|
|||||||
pattern: Pattern,
|
pattern: Pattern,
|
||||||
saves: &mut [usize],
|
saves: &mut [usize],
|
||||||
range: Range<usize>,
|
range: Range<usize>,
|
||||||
) -> bool {
|
) -> Option<usize> {
|
||||||
|
|
||||||
let mut cursor = address;
|
let mut cursor = address;
|
||||||
let mut pc = 0;
|
let mut pc = 0;
|
||||||
@@ -87,8 +87,8 @@ pub fn exec<Binary: Scannable + ?Sized>(
|
|||||||
|
|
||||||
// Compare bytes
|
// Compare bytes
|
||||||
Atom::Byte(pat_byte) => {
|
Atom::Byte(pat_byte) => {
|
||||||
let Some(byte) = read::<_, u8>(bin, cursor) else { return false; };
|
let Some(byte) = read::<_, u8>(bin, cursor) else { return None; };
|
||||||
if byte & mask != pat_byte & mask { return false; }
|
if byte & mask != pat_byte & mask { return None; }
|
||||||
cursor += 1;
|
cursor += 1;
|
||||||
mask = 0xFF;
|
mask = 0xFF;
|
||||||
}
|
}
|
||||||
@@ -105,9 +105,8 @@ pub fn exec<Binary: Scannable + ?Sized>(
|
|||||||
let skip = if skip == 0 { SKIP_VA } else { skip };
|
let skip = if skip == 0 { SKIP_VA } else { skip };
|
||||||
|
|
||||||
// start running the pattern from pc...
|
// start running the pattern from pc...
|
||||||
if !exec(bin, cursor, &pattern[pc..], saves, range.clone()) {
|
exec(bin, cursor, &pattern[pc..], saves, range.clone())?;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
cursor = cursor.wrapping_add(skip as usize);
|
cursor = cursor.wrapping_add(skip as usize);
|
||||||
mask = 0xff;
|
mask = 0xff;
|
||||||
ext_range = 0;
|
ext_range = 0;
|
||||||
@@ -119,7 +118,7 @@ pub fn exec<Binary: Scannable + ?Sized>(
|
|||||||
match pattern.get(pc) {
|
match pattern.get(pc) {
|
||||||
Some(Atom::Push(_)) => counter += 1,
|
Some(Atom::Push(_)) => counter += 1,
|
||||||
Some(Atom::Pop) => counter -= 1,
|
Some(Atom::Pop) => counter -= 1,
|
||||||
None => return true,
|
None => return Some(cursor),
|
||||||
_ => (/**/)
|
_ => (/**/)
|
||||||
}
|
}
|
||||||
pc += 1;
|
pc += 1;
|
||||||
@@ -127,7 +126,7 @@ pub fn exec<Binary: Scannable + ?Sized>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Atom::Pop => {
|
Atom::Pop => {
|
||||||
return true;
|
return Some(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
Atom::Fuzzy(pat_mask) => {
|
Atom::Fuzzy(pat_mask) => {
|
||||||
@@ -158,60 +157,60 @@ pub fn exec<Binary: Scannable + ?Sized>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Atom::Jump1 => {
|
Atom::Jump1 => {
|
||||||
let Some(sbyte) = read::<_, i8>(bin, cursor) else { return false };
|
let Some(sbyte) = read::<_, i8>(bin, cursor) else { return None };
|
||||||
cursor = cursor.wrapping_add(sbyte as usize).wrapping_add(1);
|
cursor = cursor.wrapping_add(sbyte as usize).wrapping_add(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Atom::Jump4 => {
|
Atom::Jump4 => {
|
||||||
let Some(sdword) = read::<_, i32>(bin, cursor) else { return false };
|
let Some(sdword) = read::<_, i32>(bin, cursor) else { return None };
|
||||||
cursor = cursor.wrapping_add(sdword as usize).wrapping_add(4);
|
cursor = cursor.wrapping_add(sdword as usize).wrapping_add(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
Atom::Ptr => {
|
Atom::Ptr => {
|
||||||
let Some(sptr) = read::<_, usize>(bin, cursor) else { return false };
|
let Some(sptr) = read::<_, usize>(bin, cursor) else { return None };
|
||||||
cursor = sptr;
|
cursor = sptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Atom::Pir(slot) => {
|
Atom::Pir(slot) => {
|
||||||
let Some(sdword) = read::<_, i32>(bin, cursor) else { return false };
|
let Some(sdword) = read::<_, i32>(bin, cursor) else { return None };
|
||||||
let base = saves.get(slot as usize).cloned().unwrap_or(cursor);
|
let base = saves.get(slot as usize).cloned().unwrap_or(cursor);
|
||||||
cursor = base.wrapping_add(sdword as usize);
|
cursor = base.wrapping_add(sdword as usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
Atom::Check(slot) => {
|
Atom::Check(slot) => {
|
||||||
if let Some(&rva) = saves.get(slot as usize) {
|
if let Some(&rva) = saves.get(slot as usize) {
|
||||||
if rva != cursor { return false; }
|
if rva != cursor { return None; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Atom::Aligned(align) => {
|
Atom::Aligned(align) => {
|
||||||
if cursor & ((1 << align) - 1) != 0 {
|
if cursor & ((1 << align) - 1) != 0 {
|
||||||
return false;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Atom::ReadU8(slot) => {
|
Atom::ReadU8(slot) => {
|
||||||
let Some(value) = read::<_, u8>(bin, cursor) else { return false };
|
let Some(value) = read::<_, u8>(bin, cursor) else { return None };
|
||||||
if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ }
|
if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ }
|
||||||
}
|
}
|
||||||
Atom::ReadI8(slot) => {
|
Atom::ReadI8(slot) => {
|
||||||
let Some(value) = read::<_, i8>(bin, cursor) else { return false };
|
let Some(value) = read::<_, i8>(bin, cursor) else { return None };
|
||||||
if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ }
|
if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ }
|
||||||
}
|
}
|
||||||
Atom::ReadU16(slot) => {
|
Atom::ReadU16(slot) => {
|
||||||
let Some(value) = read::<_, u16>(bin, cursor) else { return false };
|
let Some(value) = read::<_, u16>(bin, cursor) else { return None };
|
||||||
if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ }
|
if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ }
|
||||||
}
|
}
|
||||||
Atom::ReadI16(slot) => {
|
Atom::ReadI16(slot) => {
|
||||||
let Some(value) = read::<_, i16>(bin, cursor) else { return false };
|
let Some(value) = read::<_, i16>(bin, cursor) else { return None };
|
||||||
if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ }
|
if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ }
|
||||||
}
|
}
|
||||||
Atom::ReadU32(slot) => {
|
Atom::ReadU32(slot) => {
|
||||||
let Some(value) = read::<_, u32>(bin, cursor) else { return false };
|
let Some(value) = read::<_, u32>(bin, cursor) else { return None };
|
||||||
if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ }
|
if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ }
|
||||||
}
|
}
|
||||||
Atom::ReadI32(slot) => {
|
Atom::ReadI32(slot) => {
|
||||||
let Some(value) = read::<_, i32>(bin, cursor) else { return false };
|
let Some(value) = read::<_, i32>(bin, cursor) else { return None };
|
||||||
if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ }
|
if let Some(slot) = saves.get_mut(slot as usize) { *slot = value as _ }
|
||||||
}
|
}
|
||||||
Atom::Zero(slot) => {
|
Atom::Zero(slot) => {
|
||||||
@@ -220,35 +219,40 @@ pub fn exec<Binary: Scannable + ?Sized>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Atom::Case(next) => {
|
Atom::Case(next) => {
|
||||||
if exec(bin, cursor, pattern, saves, range.clone()) {
|
if let Some(nc) = exec(bin, cursor, &pattern[pc..], saves, range.clone()) {
|
||||||
|
cursor = nc;
|
||||||
|
|
||||||
// same as Push/Pop except we add the next from the break to the pc.
|
// same as Push/Pop except we add the next from the break to the pc.
|
||||||
let mut counter = 1;
|
let mut counter = 1;
|
||||||
loop {
|
loop {
|
||||||
pc += 1;
|
|
||||||
match pattern.get(pc) {
|
match pattern.get(pc) {
|
||||||
Some(Atom::Case(_)) => counter += 1,
|
Some(Atom::Case(_)) => counter += 1,
|
||||||
Some(Atom::Break(next)) => {
|
Some(Atom::Break(next)) => {
|
||||||
counter -= 1;
|
counter -= 1;
|
||||||
if counter == 0 {
|
if counter == 0 {
|
||||||
pc += *next as usize
|
pc += *next as usize + 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => return true,
|
None => return Some(cursor),
|
||||||
_ => (/**/)
|
_ => (/**/)
|
||||||
}
|
}
|
||||||
|
pc += 1;
|
||||||
}
|
}
|
||||||
|
// panic!("{pc}, {:X?} == {:02X}", pattern.get(pc), bin.chunk_at(cursor).unwrap([1]));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// if the case fails go to the location defined by next
|
// if the case fails go to the location defined by next
|
||||||
pc += next as usize;
|
pc += next as usize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Atom::Break(_next) => {
|
Atom::Break(_next) => {
|
||||||
return true;
|
return Some(cursor);
|
||||||
}
|
}
|
||||||
Atom::Nop => {}
|
Atom::Nop => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
Some(cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -260,13 +264,13 @@ pub fn exec_many<Binary: Scannable + ?Sized >(
|
|||||||
saves: &mut [usize],
|
saves: &mut [usize],
|
||||||
range: Range<usize>,
|
range: Range<usize>,
|
||||||
limit: u32,
|
limit: u32,
|
||||||
) -> bool {
|
) -> Option<usize> {
|
||||||
let mut aob = <[u8; 0x10] as Pod>::uninit();
|
let mut aob = <[u8; 0x10] as Pod>::uninit();
|
||||||
let aob = make_aob(pattern, &mut aob);
|
let aob = make_aob(pattern, &mut aob);
|
||||||
|
|
||||||
let Some(chunk) = bin.chunk_at(address) else {
|
let Some(chunk) = bin.chunk_at(address) else {
|
||||||
// pattern fails before we even try (out of bounds)
|
// pattern fails before we even try (out of bounds)
|
||||||
return false;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
match !aob.is_empty() {
|
match !aob.is_empty() {
|
||||||
@@ -275,21 +279,21 @@ pub fn exec_many<Binary: Scannable + ?Sized >(
|
|||||||
let mut cursor = address;
|
let mut cursor = address;
|
||||||
while let Some(address) = scan_for_aob(bin, cursor..upper_limit, aob) {
|
while let Some(address) = scan_for_aob(bin, cursor..upper_limit, aob) {
|
||||||
cursor = address;
|
cursor = address;
|
||||||
if exec(bin, cursor, pattern, saves, range.clone()) {
|
if let Some(cursor) = exec(bin, cursor, pattern, saves, range.clone()) {
|
||||||
return true;
|
return Some(cursor);
|
||||||
}
|
}
|
||||||
cursor += 1;
|
cursor += 1;
|
||||||
}
|
}
|
||||||
false
|
None
|
||||||
}
|
}
|
||||||
false => {
|
false => {
|
||||||
// try to reduce the limit just in-case we can squeeze some perf out of it
|
// try to reduce the limit just in-case we can squeeze some perf out of it
|
||||||
for i in 0..(limit as usize).min(chunk.len()) {
|
for i in 0..(limit as usize).min(chunk.len()) {
|
||||||
if exec(bin, address + i, pattern, saves, range.clone()) {
|
if let Some(cursor) = exec(bin, address + i, pattern, saves, range.clone()) {
|
||||||
return true;
|
return Some(cursor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,16 @@
|
|||||||
#[test]
|
#[test]
|
||||||
pub fn test_pattern() {
|
pub fn test_pattern() {
|
||||||
|
|
||||||
let pattern = x::pattern!("E8 [0-4] BB ");
|
let pattern = x::pattern!("E8 ( AA | CC | DD ) E8 ");
|
||||||
let buffer: &[u8] = &[ 0xAA, 0xE8, 0xBB, 0xE8, 0x00, 0xBB, ];
|
use x::xpat::Atom::*;
|
||||||
|
let pattern = &[Save(0), Byte(0xE8),
|
||||||
|
Case(2), Byte(0xCC), Break(8),
|
||||||
|
Case(2), Byte(0xAA), Break(5),
|
||||||
|
Case(2), Byte(0xCC), Break(2), Nop, Byte(0xDD), Byte(0xE8)];
|
||||||
|
let buffer: &[u8] = &[ 0xE8, 0xDD, 0xE8 ];
|
||||||
|
|
||||||
let mut scanner = x::Scanner::new(buffer, pattern, ..);
|
let mut scanner = x::Scanner::new(buffer, pattern, ..);
|
||||||
let mut saves = [0usize;8];
|
let mut saves = [0usize;8];
|
||||||
|
|
||||||
assert!(scanner.next(&mut saves));
|
assert!(scanner.next(&mut saves));
|
||||||
assert_eq!(saves[0], 1);
|
|
||||||
assert!(scanner.next(&mut saves));
|
|
||||||
assert_eq!(saves[0], 3);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user