Arch independent helpers in libafl_qemu (#1355)
* Add more features to libafl_qemu to remove some of the heavy lifting from the fuzzers * Refactor qemu_coverage * Minor tweaks to fix other fuzzers * Autofix * Add CallingConvention to write_function_argument * Replay reverted clippy fixes --------- Co-authored-by: Your Name <you@example.com>
This commit is contained in:
parent
109755208e
commit
2002bbca35
@ -51,7 +51,7 @@ use libafl_qemu::{
|
|||||||
emu::Emulator,
|
emu::Emulator,
|
||||||
filter_qemu_args,
|
filter_qemu_args,
|
||||||
hooks::QemuHooks,
|
hooks::QemuHooks,
|
||||||
MmapPerms, QemuForkExecutor, Regs,
|
GuestReg, MmapPerms, QemuForkExecutor, Regs,
|
||||||
};
|
};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use nix::{self, unistd::dup};
|
use nix::{self, unistd::dup};
|
||||||
@ -318,7 +318,7 @@ fn fuzz(
|
|||||||
emu.write_mem(input_addr, buf);
|
emu.write_mem(input_addr, buf);
|
||||||
|
|
||||||
emu.write_reg(Regs::Rdi, input_addr).unwrap();
|
emu.write_reg(Regs::Rdi, input_addr).unwrap();
|
||||||
emu.write_reg(Regs::Rsi, len).unwrap();
|
emu.write_reg(Regs::Rsi, len as GuestReg).unwrap();
|
||||||
emu.write_reg(Regs::Rip, test_one_input_ptr).unwrap();
|
emu.write_reg(Regs::Rip, test_one_input_ptr).unwrap();
|
||||||
emu.write_reg(Regs::Rsp, stack_ptr).unwrap();
|
emu.write_reg(Regs::Rsp, stack_ptr).unwrap();
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ use libafl_qemu::{
|
|||||||
emu::Emulator,
|
emu::Emulator,
|
||||||
filter_qemu_args,
|
filter_qemu_args,
|
||||||
hooks::QemuHooks,
|
hooks::QemuHooks,
|
||||||
|
GuestReg,
|
||||||
//snapshot::QemuSnapshotHelper,
|
//snapshot::QemuSnapshotHelper,
|
||||||
MmapPerms,
|
MmapPerms,
|
||||||
QemuExecutor,
|
QemuExecutor,
|
||||||
@ -330,7 +331,7 @@ fn fuzz(
|
|||||||
emu.write_mem(input_addr, buf);
|
emu.write_mem(input_addr, buf);
|
||||||
|
|
||||||
emu.write_reg(Regs::Rdi, input_addr).unwrap();
|
emu.write_reg(Regs::Rdi, input_addr).unwrap();
|
||||||
emu.write_reg(Regs::Rsi, len).unwrap();
|
emu.write_reg(Regs::Rsi, len as GuestReg).unwrap();
|
||||||
emu.write_reg(Regs::Rip, test_one_input_ptr).unwrap();
|
emu.write_reg(Regs::Rip, test_one_input_ptr).unwrap();
|
||||||
emu.write_reg(Regs::Rsp, stack_ptr).unwrap();
|
emu.write_reg(Regs::Rsp, stack_ptr).unwrap();
|
||||||
|
|
||||||
|
@ -13,12 +13,11 @@ debug = true
|
|||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = []
|
std = []
|
||||||
be = []
|
be = ["libafl_qemu/be"]
|
||||||
64bit = []
|
|
||||||
arm = ["libafl_qemu/arm"]
|
arm = ["libafl_qemu/arm"]
|
||||||
x86_64 = ["libafl_qemu/x86_64", "64bit"]
|
x86_64 = ["libafl_qemu/x86_64"]
|
||||||
i386 = ["libafl_qemu/i386"]
|
i386 = ["libafl_qemu/i386"]
|
||||||
aarch64 = ["libafl_qemu/aarch64", "64bit"]
|
aarch64 = ["libafl_qemu/aarch64"]
|
||||||
mips = ["libafl_qemu/mips"]
|
mips = ["libafl_qemu/mips"]
|
||||||
ppc = ["libafl_qemu/ppc", "be"]
|
ppc = ["libafl_qemu/ppc", "be"]
|
||||||
|
|
||||||
|
@ -28,17 +28,11 @@ use libafl::{
|
|||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
use libafl_qemu::{
|
use libafl_qemu::{
|
||||||
drcov::QemuDrCovHelper, elf::EasyElf, emu::Emulator, MmapPerms, QemuExecutor, QemuHooks,
|
drcov::QemuDrCovHelper, elf::EasyElf, emu::Emulator, ArchExtras, CallingConvention, GuestAddr,
|
||||||
QemuInstrumentationFilter, Regs,
|
GuestReg, MmapPerms, QemuExecutor, QemuHooks, QemuInstrumentationFilter, Regs,
|
||||||
};
|
};
|
||||||
use rangemap::RangeMap;
|
use rangemap::RangeMap;
|
||||||
|
|
||||||
#[cfg(feature = "64bit")]
|
|
||||||
type GuestReg = u64;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "64bit"))]
|
|
||||||
type GuestReg = u32;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Version;
|
pub struct Version;
|
||||||
|
|
||||||
@ -141,60 +135,10 @@ pub fn fuzz() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let read_reg = |emu: &Emulator, reg: Regs| -> GuestReg {
|
let pc: GuestReg = emu.read_reg(Regs::Pc).unwrap();
|
||||||
let val: GuestReg = emu.read_reg(reg).unwrap();
|
println!("Break at {pc:#x}");
|
||||||
|
|
||||||
#[cfg(feature = "be")]
|
|
||||||
return GuestReg::from_be(val);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "be"))]
|
|
||||||
return GuestReg::from_le(val);
|
|
||||||
};
|
|
||||||
|
|
||||||
let write_reg = |emu: &Emulator, reg: Regs, val: GuestReg| {
|
|
||||||
#[cfg(feature = "be")]
|
|
||||||
let val = GuestReg::to_be(val);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "be"))]
|
|
||||||
let val = GuestReg::to_le(val);
|
|
||||||
|
|
||||||
emu.write_reg(reg, val).unwrap();
|
|
||||||
};
|
|
||||||
|
|
||||||
println!("Break at {:#x}", read_reg(&emu, Regs::Pc));
|
|
||||||
|
|
||||||
#[cfg(feature = "arm")]
|
|
||||||
let ret_addr: u32 = read_reg(&emu, Regs::Lr);
|
|
||||||
|
|
||||||
#[cfg(feature = "aarch64")]
|
|
||||||
let ret_addr: u64 = read_reg(&emu, Regs::Lr);
|
|
||||||
|
|
||||||
#[cfg(feature = "x86_64")]
|
|
||||||
let stack_ptr: u64 = read_reg(&emu, Regs::Rsp);
|
|
||||||
|
|
||||||
#[cfg(feature = "x86_64")]
|
|
||||||
let ret_addr: u64 = {
|
|
||||||
let mut ret_addr = [0; 8];
|
|
||||||
unsafe { emu.read_mem(stack_ptr, &mut ret_addr) };
|
|
||||||
u64::from_le_bytes(ret_addr)
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "i386")]
|
|
||||||
let stack_ptr: u32 = read_reg(&emu, Regs::Esp);
|
|
||||||
|
|
||||||
#[cfg(feature = "i386")]
|
|
||||||
let ret_addr: u32 = {
|
|
||||||
let mut ret_addr = [0; 4];
|
|
||||||
unsafe { emu.read_mem(stack_ptr, &mut ret_addr) };
|
|
||||||
u32::from_le_bytes(ret_addr)
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "mips")]
|
|
||||||
let ret_addr: u32 = read_reg(&emu, Regs::Ra);
|
|
||||||
|
|
||||||
#[cfg(feature = "ppc")]
|
|
||||||
let ret_addr: u32 = read_reg(&emu, Regs::Lr);
|
|
||||||
|
|
||||||
|
let ret_addr: GuestAddr = emu.read_return_address().unwrap();
|
||||||
println!("Return address = {ret_addr:#x}");
|
println!("Return address = {ret_addr:#x}");
|
||||||
|
|
||||||
emu.remove_breakpoint(test_one_input_ptr);
|
emu.remove_breakpoint(test_one_input_ptr);
|
||||||
@ -203,6 +147,21 @@ pub fn fuzz() {
|
|||||||
let input_addr = emu.map_private(0, 4096, MmapPerms::ReadWrite).unwrap();
|
let input_addr = emu.map_private(0, 4096, MmapPerms::ReadWrite).unwrap();
|
||||||
println!("Placing input at {input_addr:#x}");
|
println!("Placing input at {input_addr:#x}");
|
||||||
|
|
||||||
|
let stack_ptr: GuestAddr = emu.read_reg(Regs::Sp).unwrap();
|
||||||
|
|
||||||
|
let reset = |buf: &[u8], len: GuestReg| -> Result<(), String> {
|
||||||
|
unsafe {
|
||||||
|
emu.write_mem(input_addr, buf);
|
||||||
|
emu.write_reg(Regs::Pc, test_one_input_ptr)?;
|
||||||
|
emu.write_reg(Regs::Sp, stack_ptr)?;
|
||||||
|
emu.write_return_address(ret_addr)?;
|
||||||
|
emu.write_function_argument(CallingConvention::Cdecl, 0, input_addr)?;
|
||||||
|
emu.write_function_argument(CallingConvention::Cdecl, 1, len)?;
|
||||||
|
emu.run();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut harness = |input: &BytesInput| {
|
let mut harness = |input: &BytesInput| {
|
||||||
let target = input.target_bytes();
|
let target = input.target_bytes();
|
||||||
let buf = target
|
let buf = target
|
||||||
@ -211,65 +170,7 @@ pub fn fuzz() {
|
|||||||
.next()
|
.next()
|
||||||
.expect("Failed to get chunk");
|
.expect("Failed to get chunk");
|
||||||
let len = buf.len() as GuestReg;
|
let len = buf.len() as GuestReg;
|
||||||
|
reset(buf, len).unwrap();
|
||||||
unsafe {
|
|
||||||
emu.write_mem(input_addr, buf);
|
|
||||||
|
|
||||||
#[cfg(feature = "arm")]
|
|
||||||
{
|
|
||||||
write_reg(&emu, Regs::R0, input_addr);
|
|
||||||
write_reg(&emu, Regs::R1, len);
|
|
||||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
|
||||||
write_reg(&emu, Regs::Lr, ret_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "aarch64")]
|
|
||||||
{
|
|
||||||
write_reg(&emu, Regs::X0, input_addr);
|
|
||||||
write_reg(&emu, Regs::X1, len);
|
|
||||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
|
||||||
write_reg(&emu, Regs::Lr, ret_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "x86_64")]
|
|
||||||
{
|
|
||||||
write_reg(&emu, Regs::Rdi, input_addr);
|
|
||||||
write_reg(&emu, Regs::Rsi, len);
|
|
||||||
write_reg(&emu, Regs::Rip, test_one_input_ptr);
|
|
||||||
write_reg(&emu, Regs::Rsp, stack_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "i386")]
|
|
||||||
{
|
|
||||||
let input_addr_bytes = input_addr.to_le_bytes();
|
|
||||||
emu.write_mem(stack_ptr + (size_of::<u32>() as u32), &input_addr_bytes);
|
|
||||||
|
|
||||||
let len_bytes = len.to_le_bytes();
|
|
||||||
emu.write_mem(stack_ptr + ((2 * size_of::<u32>()) as u32), &len_bytes);
|
|
||||||
|
|
||||||
write_reg(&emu, Regs::Eip, test_one_input_ptr);
|
|
||||||
write_reg(&emu, Regs::Esp, stack_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "mips")]
|
|
||||||
{
|
|
||||||
write_reg(&emu, Regs::A0, input_addr);
|
|
||||||
write_reg(&emu, Regs::A1, len);
|
|
||||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
|
||||||
write_reg(&emu, Regs::Ra, ret_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ppc")]
|
|
||||||
{
|
|
||||||
write_reg(&emu, Regs::R3, input_addr);
|
|
||||||
write_reg(&emu, Regs::R4, len);
|
|
||||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
|
||||||
write_reg(&emu, Regs::Lr, ret_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
emu.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
ExitKind::Ok
|
ExitKind::Ok
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,12 +7,11 @@ edition = "2021"
|
|||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = []
|
std = []
|
||||||
be = []
|
be = ["libafl_qemu/be"]
|
||||||
64bit = []
|
|
||||||
arm = ["libafl_qemu/arm"]
|
arm = ["libafl_qemu/arm"]
|
||||||
x86_64 = ["libafl_qemu/x86_64", "64bit"]
|
x86_64 = ["libafl_qemu/x86_64"]
|
||||||
i386 = ["libafl_qemu/i386"]
|
i386 = ["libafl_qemu/i386"]
|
||||||
aarch64 = ["libafl_qemu/aarch64", "64bit"]
|
aarch64 = ["libafl_qemu/aarch64"]
|
||||||
mips = ["libafl_qemu/mips"]
|
mips = ["libafl_qemu/mips"]
|
||||||
ppc = ["libafl_qemu/ppc", "be"]
|
ppc = ["libafl_qemu/ppc", "be"]
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
//! A libfuzzer-like fuzzer using qemu for binary-only coverage
|
//! A libfuzzer-like fuzzer using qemu for binary-only coverage
|
||||||
//!
|
//!
|
||||||
#[cfg(feature = "i386")]
|
|
||||||
use core::mem::size_of;
|
|
||||||
use core::{ptr::addr_of_mut, time::Duration};
|
use core::{ptr::addr_of_mut, time::Duration};
|
||||||
use std::{env, path::PathBuf, process};
|
use std::{env, path::PathBuf, process};
|
||||||
|
|
||||||
@ -36,16 +34,11 @@ use libafl_qemu::{
|
|||||||
edges::{edges_map_mut_slice, QemuEdgeCoverageHelper, MAX_EDGES_NUM},
|
edges::{edges_map_mut_slice, QemuEdgeCoverageHelper, MAX_EDGES_NUM},
|
||||||
elf::EasyElf,
|
elf::EasyElf,
|
||||||
emu::Emulator,
|
emu::Emulator,
|
||||||
MmapPerms, QemuExecutor, QemuHooks, QemuInstrumentationFilter, Regs,
|
ArchExtras, CallingConvention, GuestAddr, GuestReg, MmapPerms, QemuExecutor, QemuHooks,
|
||||||
|
QemuInstrumentationFilter, Regs,
|
||||||
};
|
};
|
||||||
use rangemap::RangeMap;
|
use rangemap::RangeMap;
|
||||||
|
|
||||||
#[cfg(feature = "64bit")]
|
|
||||||
type GuestReg = u64;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "64bit"))]
|
|
||||||
type GuestReg = u32;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Version;
|
pub struct Version;
|
||||||
|
|
||||||
@ -148,60 +141,10 @@ pub fn fuzz() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let read_reg = |emu: &Emulator, reg: Regs| -> GuestReg {
|
let pc: GuestReg = emu.read_reg(Regs::Pc).unwrap();
|
||||||
let val: GuestReg = emu.read_reg(reg).unwrap();
|
println!("Break at {pc:#x}");
|
||||||
|
|
||||||
#[cfg(feature = "be")]
|
|
||||||
return GuestReg::from_be(val);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "be"))]
|
|
||||||
return GuestReg::from_le(val);
|
|
||||||
};
|
|
||||||
|
|
||||||
let write_reg = |emu: &Emulator, reg: Regs, val: GuestReg| {
|
|
||||||
#[cfg(feature = "be")]
|
|
||||||
let val = GuestReg::to_be(val);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "be"))]
|
|
||||||
let val = GuestReg::to_le(val);
|
|
||||||
|
|
||||||
emu.write_reg(reg, val).unwrap();
|
|
||||||
};
|
|
||||||
|
|
||||||
println!("Break at {:#x}", read_reg(&emu, Regs::Pc));
|
|
||||||
|
|
||||||
#[cfg(feature = "arm")]
|
|
||||||
let ret_addr: u32 = read_reg(&emu, Regs::Lr);
|
|
||||||
|
|
||||||
#[cfg(feature = "aarch64")]
|
|
||||||
let ret_addr: u64 = read_reg(&emu, Regs::Lr);
|
|
||||||
|
|
||||||
#[cfg(feature = "x86_64")]
|
|
||||||
let stack_ptr: u64 = read_reg(&emu, Regs::Rsp);
|
|
||||||
|
|
||||||
#[cfg(feature = "x86_64")]
|
|
||||||
let ret_addr: u64 = {
|
|
||||||
let mut ret_addr = [0; 8];
|
|
||||||
unsafe { emu.read_mem(stack_ptr, &mut ret_addr) };
|
|
||||||
u64::from_le_bytes(ret_addr)
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "i386")]
|
|
||||||
let stack_ptr: u32 = read_reg(&emu, Regs::Esp);
|
|
||||||
|
|
||||||
#[cfg(feature = "i386")]
|
|
||||||
let ret_addr: u32 = {
|
|
||||||
let mut ret_addr = [0; 4];
|
|
||||||
unsafe { emu.read_mem(stack_ptr, &mut ret_addr) };
|
|
||||||
u32::from_le_bytes(ret_addr)
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "mips")]
|
|
||||||
let ret_addr: u32 = read_reg(&emu, Regs::Ra);
|
|
||||||
|
|
||||||
#[cfg(feature = "ppc")]
|
|
||||||
let ret_addr: u32 = read_reg(&emu, Regs::Lr);
|
|
||||||
|
|
||||||
|
let ret_addr: GuestAddr = emu.read_return_address().unwrap();
|
||||||
println!("Return address = {ret_addr:#x}");
|
println!("Return address = {ret_addr:#x}");
|
||||||
|
|
||||||
emu.remove_breakpoint(test_one_input_ptr);
|
emu.remove_breakpoint(test_one_input_ptr);
|
||||||
@ -210,6 +153,21 @@ pub fn fuzz() {
|
|||||||
let input_addr = emu.map_private(0, 4096, MmapPerms::ReadWrite).unwrap();
|
let input_addr = emu.map_private(0, 4096, MmapPerms::ReadWrite).unwrap();
|
||||||
println!("Placing input at {input_addr:#x}");
|
println!("Placing input at {input_addr:#x}");
|
||||||
|
|
||||||
|
let stack_ptr: GuestAddr = emu.read_reg(Regs::Sp).unwrap();
|
||||||
|
|
||||||
|
let reset = |buf: &[u8], len: GuestReg| -> Result<(), String> {
|
||||||
|
unsafe {
|
||||||
|
emu.write_mem(input_addr, buf);
|
||||||
|
emu.write_reg(Regs::Pc, test_one_input_ptr)?;
|
||||||
|
emu.write_reg(Regs::Sp, stack_ptr)?;
|
||||||
|
emu.write_return_address(ret_addr)?;
|
||||||
|
emu.write_function_argument(CallingConvention::Cdecl, 0, input_addr)?;
|
||||||
|
emu.write_function_argument(CallingConvention::Cdecl, 1, len)?;
|
||||||
|
emu.run();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut harness = |input: &BytesInput| {
|
let mut harness = |input: &BytesInput| {
|
||||||
let target = input.target_bytes();
|
let target = input.target_bytes();
|
||||||
let buf = target
|
let buf = target
|
||||||
@ -218,65 +176,7 @@ pub fn fuzz() {
|
|||||||
.next()
|
.next()
|
||||||
.expect("Failed to get chunk");
|
.expect("Failed to get chunk");
|
||||||
let len = buf.len() as GuestReg;
|
let len = buf.len() as GuestReg;
|
||||||
|
reset(buf, len).unwrap();
|
||||||
unsafe {
|
|
||||||
emu.write_mem(input_addr, buf);
|
|
||||||
|
|
||||||
#[cfg(feature = "arm")]
|
|
||||||
{
|
|
||||||
write_reg(&emu, Regs::R0, input_addr);
|
|
||||||
write_reg(&emu, Regs::R1, len);
|
|
||||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
|
||||||
write_reg(&emu, Regs::Lr, ret_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "aarch64")]
|
|
||||||
{
|
|
||||||
write_reg(&emu, Regs::X0, input_addr);
|
|
||||||
write_reg(&emu, Regs::X1, len);
|
|
||||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
|
||||||
write_reg(&emu, Regs::Lr, ret_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "x86_64")]
|
|
||||||
{
|
|
||||||
write_reg(&emu, Regs::Rdi, input_addr);
|
|
||||||
write_reg(&emu, Regs::Rsi, len);
|
|
||||||
write_reg(&emu, Regs::Rip, test_one_input_ptr);
|
|
||||||
write_reg(&emu, Regs::Rsp, stack_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "i386")]
|
|
||||||
{
|
|
||||||
let input_addr_bytes = input_addr.to_le_bytes();
|
|
||||||
emu.write_mem(stack_ptr + (size_of::<u32>() as u32), &input_addr_bytes);
|
|
||||||
|
|
||||||
let len_bytes = len.to_le_bytes();
|
|
||||||
emu.write_mem(stack_ptr + ((2 * size_of::<u32>()) as u32), &len_bytes);
|
|
||||||
|
|
||||||
write_reg(&emu, Regs::Eip, test_one_input_ptr);
|
|
||||||
write_reg(&emu, Regs::Esp, stack_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "mips")]
|
|
||||||
{
|
|
||||||
write_reg(&emu, Regs::A0, input_addr);
|
|
||||||
write_reg(&emu, Regs::A1, len);
|
|
||||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
|
||||||
write_reg(&emu, Regs::Ra, ret_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "ppc")]
|
|
||||||
{
|
|
||||||
write_reg(&emu, Regs::R3, input_addr);
|
|
||||||
write_reg(&emu, Regs::R4, len);
|
|
||||||
write_reg(&emu, Regs::Pc, test_one_input_ptr);
|
|
||||||
write_reg(&emu, Regs::Lr, ret_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
emu.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
ExitKind::Ok
|
ExitKind::Ok
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1867,13 +1867,13 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_read_tokens() {
|
fn test_read_tokens() {
|
||||||
let _res = fs::remove_file("test.tkns");
|
let _res = fs::remove_file("test.tkns");
|
||||||
let data = r###"
|
let data = r#"
|
||||||
# comment
|
# comment
|
||||||
token1@123="AAA"
|
token1@123="AAA"
|
||||||
token1="A\x41A"
|
token1="A\x41A"
|
||||||
"A\AA"
|
"A\AA"
|
||||||
token2="B"
|
token2="B"
|
||||||
"###;
|
"#;
|
||||||
fs::write("test.tkns", data).expect("Unable to write test.tkns");
|
fs::write("test.tkns", data).expect("Unable to write test.tkns");
|
||||||
let tokens = Tokens::from_file("test.tkns").unwrap();
|
let tokens = Tokens::from_file("test.tkns").unwrap();
|
||||||
log::info!("Token file entries: {:?}", tokens.tokens());
|
log::info!("Token file entries: {:?}", tokens.tokens());
|
||||||
|
@ -385,14 +385,13 @@ impl Allocator {
|
|||||||
metadatas.sort_by(|a, b| a.address.cmp(&b.address));
|
metadatas.sort_by(|a, b| a.address.cmp(&b.address));
|
||||||
let mut offset_to_closest = i64::max_value();
|
let mut offset_to_closest = i64::max_value();
|
||||||
let mut closest = None;
|
let mut closest = None;
|
||||||
|
let ptr: i64 = ptr.try_into().unwrap();
|
||||||
for metadata in metadatas {
|
for metadata in metadatas {
|
||||||
|
let address: i64 = metadata.address.try_into().unwrap();
|
||||||
let new_offset = if hint_base == metadata.address {
|
let new_offset = if hint_base == metadata.address {
|
||||||
(ptr as i64 - metadata.address as i64).abs()
|
(ptr - address).abs()
|
||||||
} else {
|
} else {
|
||||||
std::cmp::min(
|
std::cmp::min(offset_to_closest, (ptr - address).abs())
|
||||||
offset_to_closest,
|
|
||||||
(ptr as i64 - metadata.address as i64).abs(),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
if new_offset < offset_to_closest {
|
if new_offset < offset_to_closest {
|
||||||
offset_to_closest = new_offset;
|
offset_to_closest = new_offset;
|
||||||
|
@ -251,14 +251,13 @@ impl AsanErrors {
|
|||||||
cs.set_skipdata(true).expect("failed to set skipdata");
|
cs.set_skipdata(true).expect("failed to set skipdata");
|
||||||
|
|
||||||
let start_pc = error.pc - 4 * 5;
|
let start_pc = error.pc - 4 * 5;
|
||||||
for insn in cs
|
for insn in &*cs
|
||||||
.disasm_count(
|
.disasm_count(
|
||||||
unsafe { std::slice::from_raw_parts(start_pc as *mut u8, 4 * 11) },
|
unsafe { std::slice::from_raw_parts(start_pc as *mut u8, 4 * 11) },
|
||||||
start_pc as u64,
|
start_pc as u64,
|
||||||
11,
|
11,
|
||||||
)
|
)
|
||||||
.expect("failed to disassemble instructions")
|
.expect("failed to disassemble instructions")
|
||||||
.iter()
|
|
||||||
{
|
{
|
||||||
if insn.address() as usize == error.pc {
|
if insn.address() as usize == error.pc {
|
||||||
output
|
output
|
||||||
@ -276,7 +275,9 @@ impl AsanErrors {
|
|||||||
|
|
||||||
#[allow(clippy::non_ascii_literal)]
|
#[allow(clippy::non_ascii_literal)]
|
||||||
writeln!(output, "{:━^100}", " ALLOCATION INFO ").unwrap();
|
writeln!(output, "{:━^100}", " ALLOCATION INFO ").unwrap();
|
||||||
let offset: i64 = fault_address as i64 - (error.metadata.address + 0x1000) as i64;
|
let fault_address: i64 = fault_address.try_into().unwrap();
|
||||||
|
let metadata_address: i64 = error.metadata.address.try_into().unwrap();
|
||||||
|
let offset: i64 = fault_address - (metadata_address + 0x1000);
|
||||||
let direction = if offset > 0 { "right" } else { "left" };
|
let direction = if offset > 0 { "right" } else { "left" };
|
||||||
writeln!(
|
writeln!(
|
||||||
output,
|
output,
|
||||||
@ -505,14 +506,13 @@ impl AsanErrors {
|
|||||||
cs.set_skipdata(true).expect("failed to set skipdata");
|
cs.set_skipdata(true).expect("failed to set skipdata");
|
||||||
|
|
||||||
let start_pc = pc;
|
let start_pc = pc;
|
||||||
for insn in cs
|
for insn in &*cs
|
||||||
.disasm_count(
|
.disasm_count(
|
||||||
unsafe { std::slice::from_raw_parts(start_pc as *mut u8, 4 * 11) },
|
unsafe { std::slice::from_raw_parts(start_pc as *mut u8, 4 * 11) },
|
||||||
start_pc as u64,
|
start_pc as u64,
|
||||||
11,
|
11,
|
||||||
)
|
)
|
||||||
.expect("failed to disassemble instructions")
|
.expect("failed to disassemble instructions")
|
||||||
.iter()
|
|
||||||
{
|
{
|
||||||
if insn.address() as usize == pc {
|
if insn.address() as usize == pc {
|
||||||
output
|
output
|
||||||
|
@ -150,7 +150,7 @@ impl CoverageRuntime {
|
|||||||
; mov QWORD [rsp-0x98], rbx
|
; mov QWORD [rsp-0x98], rbx
|
||||||
|
|
||||||
// Load the previous_pc
|
// Load the previous_pc
|
||||||
; mov rax, QWORD prev_loc_ptr as *mut u64 as _
|
; mov rax, QWORD prev_loc_ptr as _
|
||||||
; mov rax, QWORD [rax]
|
; mov rax, QWORD [rax]
|
||||||
|
|
||||||
// Calculate the edge id
|
// Calculate the edge id
|
||||||
@ -158,7 +158,7 @@ impl CoverageRuntime {
|
|||||||
; xor rax, rbx
|
; xor rax, rbx
|
||||||
|
|
||||||
// Load the map byte address
|
// Load the map byte address
|
||||||
; mov rbx, QWORD map_addr_ptr as *mut [u8; MAP_SIZE] as _
|
; mov rbx, QWORD map_addr_ptr as _
|
||||||
; add rax, rbx
|
; add rax, rbx
|
||||||
|
|
||||||
// Update the map byte
|
// Update the map byte
|
||||||
@ -168,7 +168,7 @@ impl CoverageRuntime {
|
|||||||
; mov BYTE [rax],bl
|
; mov BYTE [rax],bl
|
||||||
|
|
||||||
// Update the previous_pc value
|
// Update the previous_pc value
|
||||||
; mov rax, QWORD prev_loc_ptr as *mut u64 as _
|
; mov rax, QWORD prev_loc_ptr as _
|
||||||
; mov ebx, WORD (h64 >> 1) as i32
|
; mov ebx, WORD (h64 >> 1) as i32
|
||||||
; mov QWORD [rax], rbx
|
; mov QWORD [rax], rbx
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ use pyo3::prelude::*;
|
|||||||
pub use strum_macros::EnumIter;
|
pub use strum_macros::EnumIter;
|
||||||
pub use syscall_numbers::aarch64::*;
|
pub use syscall_numbers::aarch64::*;
|
||||||
|
|
||||||
|
use crate::CallingConvention;
|
||||||
|
|
||||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
pub enum Regs {
|
pub enum Regs {
|
||||||
@ -62,3 +64,42 @@ impl IntoPy<PyObject> for Regs {
|
|||||||
pub fn capstone() -> capstone::arch::arm64::ArchCapstoneBuilder {
|
pub fn capstone() -> capstone::arch::arm64::ArchCapstoneBuilder {
|
||||||
capstone::Capstone::new().arm64()
|
capstone::Capstone::new().arm64()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type GuestReg = u64;
|
||||||
|
|
||||||
|
impl crate::ArchExtras for crate::CPU {
|
||||||
|
fn read_return_address<T>(&self) -> Result<T, String>
|
||||||
|
where
|
||||||
|
T: From<GuestReg>,
|
||||||
|
{
|
||||||
|
self.read_reg(Regs::Lr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
self.write_reg(Regs::Lr, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_function_argument<T>(
|
||||||
|
&self,
|
||||||
|
conv: CallingConvention,
|
||||||
|
idx: i32,
|
||||||
|
val: T,
|
||||||
|
) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
if conv != CallingConvention::Cdecl {
|
||||||
|
return Err(format!("Unsupported calling convention: {conv:#?}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let val: GuestReg = val.into();
|
||||||
|
match idx {
|
||||||
|
0 => self.write_reg(Regs::X0, val),
|
||||||
|
1 => self.write_reg(Regs::X1, val),
|
||||||
|
_ => Err(format!("Unsupported argument: {idx:}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,6 +5,8 @@ use pyo3::prelude::*;
|
|||||||
pub use strum_macros::EnumIter;
|
pub use strum_macros::EnumIter;
|
||||||
pub use syscall_numbers::arm::*;
|
pub use syscall_numbers::arm::*;
|
||||||
|
|
||||||
|
use crate::CallingConvention;
|
||||||
|
|
||||||
/// Registers for the ARM instruction set.
|
/// Registers for the ARM instruction set.
|
||||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
@ -62,3 +64,42 @@ pub fn capstone_thumb() -> capstone::arch::arm::ArchCapstoneBuilder {
|
|||||||
.arm()
|
.arm()
|
||||||
.mode(capstone::arch::arm::ArchMode::Thumb)
|
.mode(capstone::arch::arm::ArchMode::Thumb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type GuestReg = u32;
|
||||||
|
|
||||||
|
impl crate::ArchExtras for crate::CPU {
|
||||||
|
fn read_return_address<T>(&self) -> Result<T, String>
|
||||||
|
where
|
||||||
|
T: From<GuestReg>,
|
||||||
|
{
|
||||||
|
self.read_reg(Regs::Lr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
self.write_reg(Regs::Lr, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_function_argument<T>(
|
||||||
|
&self,
|
||||||
|
conv: CallingConvention,
|
||||||
|
idx: i32,
|
||||||
|
val: T,
|
||||||
|
) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
if conv != CallingConvention::Cdecl {
|
||||||
|
return Err(format!("Unsupported calling convention: {conv:#?}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let val: GuestReg = val.into();
|
||||||
|
match idx {
|
||||||
|
0 => self.write_reg(Regs::R0, val),
|
||||||
|
1 => self.write_reg(Regs::R1, val),
|
||||||
|
_ => Err(format!("Unsupported argument: {idx:}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -395,7 +395,7 @@ impl AsanGiovese {
|
|||||||
if self.snapshot_shadow {
|
if self.snapshot_shadow {
|
||||||
let set = self.dirty_shadow.lock().unwrap();
|
let set = self.dirty_shadow.lock().unwrap();
|
||||||
|
|
||||||
for &page in set.iter() {
|
for &page in &*set {
|
||||||
let data = Self::get_shadow_page(emu, page).to_vec();
|
let data = Self::get_shadow_page(emu, page).to_vec();
|
||||||
self.saved_shadow.insert(page, data);
|
self.saved_shadow.insert(page, data);
|
||||||
}
|
}
|
||||||
@ -425,7 +425,7 @@ impl AsanGiovese {
|
|||||||
if self.snapshot_shadow {
|
if self.snapshot_shadow {
|
||||||
let mut set = self.dirty_shadow.lock().unwrap();
|
let mut set = self.dirty_shadow.lock().unwrap();
|
||||||
|
|
||||||
for &page in set.iter() {
|
for &page in &*set {
|
||||||
let original = self.saved_shadow.get(&page);
|
let original = self.saved_shadow.get(&page);
|
||||||
if let Some(data) = original {
|
if let Some(data) = original {
|
||||||
let cur = Self::get_shadow_page(emu, page);
|
let cur = Self::get_shadow_page(emu, page);
|
||||||
@ -472,7 +472,7 @@ pub fn init_with_asan(
|
|||||||
|e: &str| "LD_PRELOAD=".to_string() + &asan_lib + " " + &e["LD_PRELOAD=".len()..];
|
|e: &str| "LD_PRELOAD=".to_string() + &asan_lib + " " + &e["LD_PRELOAD=".len()..];
|
||||||
|
|
||||||
let mut added = false;
|
let mut added = false;
|
||||||
for (k, v) in env.iter_mut() {
|
for (k, v) in &mut *env {
|
||||||
if k == "QEMU_SET_ENV" {
|
if k == "QEMU_SET_ENV" {
|
||||||
let mut new_v = vec![];
|
let mut new_v = vec![];
|
||||||
for e in v.split(',') {
|
for e in v.split(',') {
|
||||||
|
@ -10,10 +10,10 @@ use libafl::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
capstone,
|
capstone,
|
||||||
emu::Emulator,
|
emu::{ArchExtras, Emulator},
|
||||||
helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||||
hooks::QemuHooks,
|
hooks::QemuHooks,
|
||||||
GuestAddr, Regs,
|
GuestAddr,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait CallTraceCollector: 'static + Debug {
|
pub trait CallTraceCollector: 'static + Debug {
|
||||||
@ -242,51 +242,7 @@ where
|
|||||||
S: UsesInput,
|
S: UsesInput,
|
||||||
QT: QemuHelperTuple<S>,
|
QT: QemuHelperTuple<S>,
|
||||||
{
|
{
|
||||||
#[cfg(cpu_target = "x86_64")]
|
let ret_addr: GuestAddr = hooks.emulator().read_return_address().unwrap();
|
||||||
let ret_addr = {
|
|
||||||
let emu = hooks.emulator();
|
|
||||||
let stack_ptr: GuestAddr = emu.read_reg(Regs::Rsp).unwrap();
|
|
||||||
let mut ret_addr = [0; 8];
|
|
||||||
unsafe { emu.read_mem(stack_ptr, &mut ret_addr) };
|
|
||||||
GuestAddr::from_le_bytes(ret_addr)
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(cpu_target = "i386")]
|
|
||||||
let ret_addr = {
|
|
||||||
let emu = hooks.emulator();
|
|
||||||
let stack_ptr: GuestAddr = emu.read_reg(Regs::Esp).unwrap();
|
|
||||||
let mut ret_addr = [0; 4];
|
|
||||||
unsafe { emu.read_mem(stack_ptr, &mut ret_addr) };
|
|
||||||
GuestAddr::from_le_bytes(ret_addr)
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(any(cpu_target = "arm", cpu_target = "aarch64"))]
|
|
||||||
let ret_addr = {
|
|
||||||
let emu = hooks.emulator();
|
|
||||||
let ret_addr: GuestAddr = emu.read_reg(Regs::Lr).unwrap();
|
|
||||||
ret_addr
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(cpu_target = "mips")]
|
|
||||||
let ret_addr = {
|
|
||||||
let emu = hooks.emulator();
|
|
||||||
let ret_addr: GuestAddr = emu.read_reg(Regs::Ra).unwrap();
|
|
||||||
ret_addr
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(cpu_target = "ppc")]
|
|
||||||
let ret_addr = {
|
|
||||||
let emu = hooks.emulator();
|
|
||||||
let ret_addr: GuestAddr = emu.read_reg(Regs::Lr).unwrap();
|
|
||||||
ret_addr
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(cpu_target = "hexagon")]
|
|
||||||
let ret_addr = {
|
|
||||||
let emu = hooks.emulator();
|
|
||||||
let ret_addr: GuestAddr = emu.read_reg(Regs::Lr).unwrap();
|
|
||||||
ret_addr
|
|
||||||
};
|
|
||||||
|
|
||||||
// log::info!("RET @ 0x{:#x}", ret_addr);
|
// log::info!("RET @ 0x{:#x}", ret_addr);
|
||||||
|
|
||||||
|
@ -102,8 +102,8 @@ where
|
|||||||
if self.full_trace {
|
if self.full_trace {
|
||||||
if DRCOV_IDS.lock().unwrap().as_ref().unwrap().len() > self.drcov_len {
|
if DRCOV_IDS.lock().unwrap().as_ref().unwrap().len() > self.drcov_len {
|
||||||
let mut drcov_vec = Vec::<DrCovBasicBlock>::new();
|
let mut drcov_vec = Vec::<DrCovBasicBlock>::new();
|
||||||
for id in DRCOV_IDS.lock().unwrap().as_ref().unwrap().iter() {
|
for id in DRCOV_IDS.lock().unwrap().as_ref().unwrap() {
|
||||||
'pcs_full: for (pc, idm) in DRCOV_MAP.lock().unwrap().as_ref().unwrap().iter() {
|
'pcs_full: for (pc, idm) in DRCOV_MAP.lock().unwrap().as_ref().unwrap() {
|
||||||
let mut module_found = false;
|
let mut module_found = false;
|
||||||
for module in self.module_mapping.iter() {
|
for module in self.module_mapping.iter() {
|
||||||
let (range, (_, _)) = module;
|
let (range, (_, _)) = module;
|
||||||
@ -141,7 +141,7 @@ where
|
|||||||
} else {
|
} else {
|
||||||
if DRCOV_MAP.lock().unwrap().as_ref().unwrap().len() > self.drcov_len {
|
if DRCOV_MAP.lock().unwrap().as_ref().unwrap().len() > self.drcov_len {
|
||||||
let mut drcov_vec = Vec::<DrCovBasicBlock>::new();
|
let mut drcov_vec = Vec::<DrCovBasicBlock>::new();
|
||||||
'pcs: for (pc, _) in DRCOV_MAP.lock().unwrap().as_ref().unwrap().iter() {
|
'pcs: for (pc, _) in DRCOV_MAP.lock().unwrap().as_ref().unwrap() {
|
||||||
let mut module_found = false;
|
let mut module_found = false;
|
||||||
for module in self.module_mapping.iter() {
|
for module in self.module_mapping.iter() {
|
||||||
let (range, (_, _)) = module;
|
let (range, (_, _)) = module;
|
||||||
|
@ -41,7 +41,7 @@ impl<'a> EasyElf<'a> {
|
|||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn resolve_symbol(&self, name: &str, load_addr: GuestAddr) -> Option<GuestAddr> {
|
pub fn resolve_symbol(&self, name: &str, load_addr: GuestAddr) -> Option<GuestAddr> {
|
||||||
for sym in self.elf.syms.iter() {
|
for sym in &self.elf.syms {
|
||||||
if let Some(sym_name) = self.elf.strtab.get_at(sym.st_name) {
|
if let Some(sym_name) = self.elf.strtab.get_at(sym.st_name) {
|
||||||
if sym_name == name {
|
if sym_name == name {
|
||||||
return if sym.st_value == 0 {
|
return if sym.st_value == 0 {
|
||||||
|
@ -17,6 +17,8 @@ use num_enum::{IntoPrimitive, TryFromPrimitive};
|
|||||||
use num_traits::Num;
|
use num_traits::Num;
|
||||||
use strum_macros::EnumIter;
|
use strum_macros::EnumIter;
|
||||||
|
|
||||||
|
use crate::GuestReg;
|
||||||
|
|
||||||
pub type GuestAddr = libafl_qemu_sys::target_ulong;
|
pub type GuestAddr = libafl_qemu_sys::target_ulong;
|
||||||
pub type GuestUsize = libafl_qemu_sys::target_ulong;
|
pub type GuestUsize = libafl_qemu_sys::target_ulong;
|
||||||
pub type GuestIsize = libafl_qemu_sys::target_long;
|
pub type GuestIsize = libafl_qemu_sys::target_long;
|
||||||
@ -485,6 +487,28 @@ pub struct CPU {
|
|||||||
ptr: CPUStatePtr,
|
ptr: CPUStatePtr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum CallingConvention {
|
||||||
|
Cdecl,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ArchExtras {
|
||||||
|
fn read_return_address<T>(&self) -> Result<T, String>
|
||||||
|
where
|
||||||
|
T: From<GuestReg>;
|
||||||
|
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>;
|
||||||
|
fn write_function_argument<T>(
|
||||||
|
&self,
|
||||||
|
conv: CallingConvention,
|
||||||
|
idx: i32,
|
||||||
|
val: T,
|
||||||
|
) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>;
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::unused_self)]
|
#[allow(clippy::unused_self)]
|
||||||
impl CPU {
|
impl CPU {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -617,8 +641,15 @@ impl CPU {
|
|||||||
pub fn write_reg<R, T>(&self, reg: R, val: T) -> Result<(), String>
|
pub fn write_reg<R, T>(&self, reg: R, val: T) -> Result<(), String>
|
||||||
where
|
where
|
||||||
R: Into<i32>,
|
R: Into<i32>,
|
||||||
|
T: Into<GuestReg>,
|
||||||
{
|
{
|
||||||
let reg = reg.into();
|
let reg = reg.into();
|
||||||
|
#[cfg(feature = "be")]
|
||||||
|
let val = GuestReg::to_be(val.into());
|
||||||
|
|
||||||
|
#[cfg(not(feature = "be"))]
|
||||||
|
let val = GuestReg::to_le(val.into());
|
||||||
|
|
||||||
let success = unsafe { libafl_qemu_write_reg(self.ptr, reg, addr_of!(val) as *const u8) };
|
let success = unsafe { libafl_qemu_write_reg(self.ptr, reg, addr_of!(val) as *const u8) };
|
||||||
if success == 0 {
|
if success == 0 {
|
||||||
Err(format!("Failed to write to register {reg}"))
|
Err(format!("Failed to write to register {reg}"))
|
||||||
@ -630,6 +661,7 @@ impl CPU {
|
|||||||
pub fn read_reg<R, T>(&self, reg: R) -> Result<T, String>
|
pub fn read_reg<R, T>(&self, reg: R) -> Result<T, String>
|
||||||
where
|
where
|
||||||
R: Into<i32>,
|
R: Into<i32>,
|
||||||
|
T: From<GuestReg>,
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
let reg = reg.into();
|
let reg = reg.into();
|
||||||
@ -638,7 +670,11 @@ impl CPU {
|
|||||||
if success == 0 {
|
if success == 0 {
|
||||||
Err(format!("Failed to read register {reg}"))
|
Err(format!("Failed to read register {reg}"))
|
||||||
} else {
|
} else {
|
||||||
Ok(val.assume_init())
|
#[cfg(feature = "be")]
|
||||||
|
return Ok(GuestReg::from_be(val.assume_init()).into());
|
||||||
|
|
||||||
|
#[cfg(not(feature = "be"))]
|
||||||
|
return Ok(GuestReg::from_le(val.assume_init()).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -739,11 +775,7 @@ impl Emulator {
|
|||||||
envp.push(null());
|
envp.push(null());
|
||||||
unsafe {
|
unsafe {
|
||||||
#[cfg(emulation_mode = "usermode")]
|
#[cfg(emulation_mode = "usermode")]
|
||||||
qemu_user_init(
|
qemu_user_init(argc, argv.as_ptr(), envp.as_ptr());
|
||||||
argc,
|
|
||||||
argv.as_ptr() as *const *const u8,
|
|
||||||
envp.as_ptr() as *const *const u8,
|
|
||||||
);
|
|
||||||
#[cfg(emulation_mode = "systemmode")]
|
#[cfg(emulation_mode = "systemmode")]
|
||||||
{
|
{
|
||||||
qemu_init(
|
qemu_init(
|
||||||
@ -861,7 +893,7 @@ impl Emulator {
|
|||||||
|
|
||||||
pub fn write_reg<R, T>(&self, reg: R, val: T) -> Result<(), String>
|
pub fn write_reg<R, T>(&self, reg: R, val: T) -> Result<(), String>
|
||||||
where
|
where
|
||||||
T: Num + PartialOrd + Copy,
|
T: Num + PartialOrd + Copy + Into<GuestReg>,
|
||||||
R: Into<i32>,
|
R: Into<i32>,
|
||||||
{
|
{
|
||||||
self.current_cpu().unwrap().write_reg(reg, val)
|
self.current_cpu().unwrap().write_reg(reg, val)
|
||||||
@ -869,7 +901,7 @@ impl Emulator {
|
|||||||
|
|
||||||
pub fn read_reg<R, T>(&self, reg: R) -> Result<T, String>
|
pub fn read_reg<R, T>(&self, reg: R) -> Result<T, String>
|
||||||
where
|
where
|
||||||
T: Num + PartialOrd + Copy,
|
T: Num + PartialOrd + Copy + From<GuestReg>,
|
||||||
R: Into<i32>,
|
R: Into<i32>,
|
||||||
{
|
{
|
||||||
self.current_cpu().unwrap().read_reg(reg)
|
self.current_cpu().unwrap().read_reg(reg)
|
||||||
@ -1154,6 +1186,40 @@ impl Emulator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ArchExtras for Emulator {
|
||||||
|
fn read_return_address<T>(&self) -> Result<T, String>
|
||||||
|
where
|
||||||
|
T: From<GuestReg>,
|
||||||
|
{
|
||||||
|
self.current_cpu()
|
||||||
|
.ok_or("Failed to get current CPU")?
|
||||||
|
.read_return_address::<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
self.current_cpu()
|
||||||
|
.ok_or("Failed to get current CPU")?
|
||||||
|
.write_return_address::<T>(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_function_argument<T>(
|
||||||
|
&self,
|
||||||
|
conv: CallingConvention,
|
||||||
|
idx: i32,
|
||||||
|
val: T,
|
||||||
|
) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
self.current_cpu()
|
||||||
|
.ok_or("Failed to get current CPU")?
|
||||||
|
.write_function_argument::<T>(conv, idx, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "python")]
|
#[cfg(feature = "python")]
|
||||||
pub mod pybind {
|
pub mod pybind {
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
@ -3,6 +3,8 @@ use num_enum::{IntoPrimitive, TryFromPrimitive};
|
|||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
pub use strum_macros::EnumIter;
|
pub use strum_macros::EnumIter;
|
||||||
|
|
||||||
|
use crate::CallingConvention;
|
||||||
|
|
||||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
pub enum Regs {
|
pub enum Regs {
|
||||||
@ -66,3 +68,37 @@ impl Regs {
|
|||||||
pub const Fp: Regs = Regs::R30;
|
pub const Fp: Regs = Regs::R30;
|
||||||
pub const Lr: Regs = Regs::R31;
|
pub const Lr: Regs = Regs::R31;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type GuestReg = u32;
|
||||||
|
|
||||||
|
impl crate::ArchExtras for crate::CPU {
|
||||||
|
fn read_return_address<T>(&self) -> Result<T, String>
|
||||||
|
where
|
||||||
|
T: From<GuestReg>,
|
||||||
|
{
|
||||||
|
self.read_reg(Regs::Lr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
self.write_reg(Regs::Lr, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_function_argument<T>(
|
||||||
|
&self,
|
||||||
|
conv: CallingConvention,
|
||||||
|
idx: i32,
|
||||||
|
val: T,
|
||||||
|
) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
if conv != CallingConvention::Cdecl {
|
||||||
|
return Err(format!("Unsupported calling convention: {conv:#?}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(format!("Unsupported argument: {idx:}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::mem::size_of;
|
||||||
|
|
||||||
use capstone::arch::BuildsCapstone;
|
use capstone::arch::BuildsCapstone;
|
||||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||||
#[cfg(feature = "python")]
|
#[cfg(feature = "python")]
|
||||||
@ -5,6 +7,8 @@ use pyo3::prelude::*;
|
|||||||
pub use strum_macros::EnumIter;
|
pub use strum_macros::EnumIter;
|
||||||
pub use syscall_numbers::x86::*;
|
pub use syscall_numbers::x86::*;
|
||||||
|
|
||||||
|
use crate::{CallingConvention, GuestAddr};
|
||||||
|
|
||||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
pub enum Regs {
|
pub enum Regs {
|
||||||
@ -41,3 +45,62 @@ pub fn capstone() -> capstone::arch::x86::ArchCapstoneBuilder {
|
|||||||
.x86()
|
.x86()
|
||||||
.mode(capstone::arch::x86::ArchMode::Mode32)
|
.mode(capstone::arch::x86::ArchMode::Mode32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type GuestReg = u32;
|
||||||
|
|
||||||
|
impl crate::ArchExtras for crate::CPU {
|
||||||
|
fn read_return_address<T>(&self) -> Result<T, String>
|
||||||
|
where
|
||||||
|
T: From<GuestReg>,
|
||||||
|
{
|
||||||
|
let stack_ptr: GuestReg = self.read_reg(Regs::Esp)?;
|
||||||
|
let mut ret_addr = [0; size_of::<GuestReg>()];
|
||||||
|
unsafe { self.read_mem(stack_ptr, &mut ret_addr) };
|
||||||
|
Ok(GuestReg::from_le_bytes(ret_addr).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
let stack_ptr: GuestReg = self.read_reg(Regs::Esp)?;
|
||||||
|
let val: GuestReg = val.into();
|
||||||
|
let ret_addr = val.to_le_bytes();
|
||||||
|
unsafe { self.write_mem(stack_ptr, &ret_addr) };
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_function_argument<T>(
|
||||||
|
&self,
|
||||||
|
conv: CallingConvention,
|
||||||
|
idx: i32,
|
||||||
|
val: T,
|
||||||
|
) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
if conv != CallingConvention::Cdecl {
|
||||||
|
return Err(format!("Unsupported calling convention: {conv:#?}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
match idx {
|
||||||
|
0..=1 => {
|
||||||
|
let val: GuestReg = val.into();
|
||||||
|
let stack_ptr: GuestAddr = self.read_reg(Regs::Sp)?;
|
||||||
|
/*
|
||||||
|
* Stack is full and descending. SP points to return address, arguments
|
||||||
|
* are in reverse order above that.
|
||||||
|
*/
|
||||||
|
let size: GuestAddr = size_of::<GuestReg>() as GuestAddr;
|
||||||
|
let offset = size * (idx as GuestAddr + 1);
|
||||||
|
|
||||||
|
let arg = val.to_le_bytes();
|
||||||
|
unsafe {
|
||||||
|
self.write_mem(stack_ptr + offset, &arg);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err(format!("Unsupported argument: {idx:}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,6 +4,8 @@ use pyo3::prelude::*;
|
|||||||
pub use strum_macros::EnumIter;
|
pub use strum_macros::EnumIter;
|
||||||
pub use syscall_numbers::mips::*;
|
pub use syscall_numbers::mips::*;
|
||||||
|
|
||||||
|
use crate::CallingConvention;
|
||||||
|
|
||||||
/// Registers for the MIPS instruction set.
|
/// Registers for the MIPS instruction set.
|
||||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
@ -62,3 +64,42 @@ impl IntoPy<PyObject> for Regs {
|
|||||||
pub fn capstone() -> capstone::arch::mips::ArchCapstoneBuilder {
|
pub fn capstone() -> capstone::arch::mips::ArchCapstoneBuilder {
|
||||||
capstone::Capstone::new().mips()
|
capstone::Capstone::new().mips()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type GuestReg = u32;
|
||||||
|
|
||||||
|
impl crate::ArchExtras for crate::CPU {
|
||||||
|
fn read_return_address<T>(&self) -> Result<T, String>
|
||||||
|
where
|
||||||
|
T: From<GuestReg>,
|
||||||
|
{
|
||||||
|
self.read_reg(Regs::Ra)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
self.write_reg(Regs::Ra, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_function_argument<T>(
|
||||||
|
&self,
|
||||||
|
conv: CallingConvention,
|
||||||
|
idx: i32,
|
||||||
|
val: T,
|
||||||
|
) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
if conv != CallingConvention::Cdecl {
|
||||||
|
return Err(format!("Unsupported calling convention: {conv:#?}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let val: GuestReg = val.into();
|
||||||
|
match idx {
|
||||||
|
0 => self.write_reg(Regs::A0, val),
|
||||||
|
1 => self.write_reg(Regs::A1, val),
|
||||||
|
_ => Err(format!("Unsupported argument: {idx:}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,6 +4,8 @@ use pyo3::prelude::*;
|
|||||||
pub use strum_macros::EnumIter;
|
pub use strum_macros::EnumIter;
|
||||||
pub use syscall_numbers::powerpc::*;
|
pub use syscall_numbers::powerpc::*;
|
||||||
|
|
||||||
|
use crate::CallingConvention;
|
||||||
|
|
||||||
/// Registers for the MIPS instruction set.
|
/// Registers for the MIPS instruction set.
|
||||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
@ -87,6 +89,7 @@ pub enum Regs {
|
|||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
impl Regs {
|
impl Regs {
|
||||||
pub const Pc: Regs = Regs::Nip;
|
pub const Pc: Regs = Regs::Nip;
|
||||||
|
pub const Sp: Regs = Regs::R1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "python")]
|
#[cfg(feature = "python")]
|
||||||
@ -101,3 +104,42 @@ impl IntoPy<PyObject> for Regs {
|
|||||||
pub fn capstone() -> capstone::arch::ppc::ArchCapstoneBuilder {
|
pub fn capstone() -> capstone::arch::ppc::ArchCapstoneBuilder {
|
||||||
capstone::Capstone::new().ppc()
|
capstone::Capstone::new().ppc()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type GuestReg = u32;
|
||||||
|
|
||||||
|
impl crate::ArchExtras for crate::CPU {
|
||||||
|
fn read_return_address<T>(&self) -> Result<T, String>
|
||||||
|
where
|
||||||
|
T: From<GuestReg>,
|
||||||
|
{
|
||||||
|
self.read_reg(Regs::Lr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
self.write_reg(Regs::Lr, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_function_argument<T>(
|
||||||
|
&self,
|
||||||
|
conv: CallingConvention,
|
||||||
|
idx: i32,
|
||||||
|
val: T,
|
||||||
|
) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
if conv != CallingConvention::Cdecl {
|
||||||
|
return Err(format!("Unsupported calling convention: {conv:#?}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let val: GuestReg = val.into();
|
||||||
|
match idx {
|
||||||
|
0 => self.write_reg(Regs::R3, val),
|
||||||
|
1 => self.write_reg(Regs::R4, val),
|
||||||
|
_ => Err(format!("Unsupported argument: {idx:}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -211,7 +211,7 @@ impl QemuSnapshotHelper {
|
|||||||
{
|
{
|
||||||
let new_maps = self.new_maps.get_mut().unwrap();
|
let new_maps = self.new_maps.get_mut().unwrap();
|
||||||
|
|
||||||
for acc in self.accesses.iter_mut() {
|
for acc in &mut self.accesses {
|
||||||
unsafe { &mut (*acc.get()) }.dirty.retain(|page| {
|
unsafe { &mut (*acc.get()) }.dirty.retain(|page| {
|
||||||
if let Some(info) = self.pages.get_mut(page) {
|
if let Some(info) = self.pages.get_mut(page) {
|
||||||
// TODO avoid duplicated memcpy
|
// TODO avoid duplicated memcpy
|
||||||
@ -251,7 +251,7 @@ impl QemuSnapshotHelper {
|
|||||||
self.reset_maps(emulator);
|
self.reset_maps(emulator);
|
||||||
|
|
||||||
// This one is after that we remapped potential regions mapped at snapshot time but unmapped during execution
|
// This one is after that we remapped potential regions mapped at snapshot time but unmapped during execution
|
||||||
for acc in self.accesses.iter_mut() {
|
for acc in &mut self.accesses {
|
||||||
for page in unsafe { &(*acc.get()).dirty } {
|
for page in unsafe { &(*acc.get()).dirty } {
|
||||||
for entry in self
|
for entry in self
|
||||||
.maps
|
.maps
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::mem::size_of;
|
||||||
|
|
||||||
use capstone::arch::BuildsCapstone;
|
use capstone::arch::BuildsCapstone;
|
||||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||||
#[cfg(feature = "python")]
|
#[cfg(feature = "python")]
|
||||||
@ -5,6 +7,8 @@ use pyo3::prelude::*;
|
|||||||
pub use strum_macros::EnumIter;
|
pub use strum_macros::EnumIter;
|
||||||
pub use syscall_numbers::x86_64::*;
|
pub use syscall_numbers::x86_64::*;
|
||||||
|
|
||||||
|
use crate::CallingConvention;
|
||||||
|
|
||||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
pub enum Regs {
|
pub enum Regs {
|
||||||
@ -50,3 +54,49 @@ pub fn capstone() -> capstone::arch::x86::ArchCapstoneBuilder {
|
|||||||
.x86()
|
.x86()
|
||||||
.mode(capstone::arch::x86::ArchMode::Mode64)
|
.mode(capstone::arch::x86::ArchMode::Mode64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type GuestReg = u64;
|
||||||
|
|
||||||
|
impl crate::ArchExtras for crate::CPU {
|
||||||
|
fn read_return_address<T>(&self) -> Result<T, String>
|
||||||
|
where
|
||||||
|
T: From<GuestReg>,
|
||||||
|
{
|
||||||
|
let stack_ptr: GuestReg = self.read_reg(Regs::Rsp)?;
|
||||||
|
let mut ret_addr = [0; size_of::<GuestReg>()];
|
||||||
|
unsafe { self.read_mem(stack_ptr, &mut ret_addr) };
|
||||||
|
Ok(GuestReg::from_le_bytes(ret_addr).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_return_address<T>(&self, val: T) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
let stack_ptr: GuestReg = self.read_reg(Regs::Rsp)?;
|
||||||
|
let val: GuestReg = val.into();
|
||||||
|
let ret_addr = val.to_le_bytes();
|
||||||
|
unsafe { self.write_mem(stack_ptr, &ret_addr) };
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_function_argument<T>(
|
||||||
|
&self,
|
||||||
|
conv: CallingConvention,
|
||||||
|
idx: i32,
|
||||||
|
val: T,
|
||||||
|
) -> Result<(), String>
|
||||||
|
where
|
||||||
|
T: Into<GuestReg>,
|
||||||
|
{
|
||||||
|
if conv != CallingConvention::Cdecl {
|
||||||
|
return Err(format!("Unsupported calling convention: {conv:#?}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let val: GuestReg = val.into();
|
||||||
|
match idx {
|
||||||
|
0 => self.write_reg(Regs::Rdi, val),
|
||||||
|
1 => self.write_reg(Regs::Rsi, val),
|
||||||
|
_ => Err(format!("Unsupported argument: {idx:}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -165,7 +165,7 @@ mod observers {
|
|||||||
let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher();
|
let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher();
|
||||||
for map in unsafe { &COUNTERS_MAPS } {
|
for map in unsafe { &COUNTERS_MAPS } {
|
||||||
let slice = map.as_slice();
|
let slice = map.as_slice();
|
||||||
let ptr = slice.as_ptr() as *const u8;
|
let ptr = slice.as_ptr();
|
||||||
let map_size = slice.len() / core::mem::size_of::<u8>();
|
let map_size = slice.len() / core::mem::size_of::<u8>();
|
||||||
unsafe {
|
unsafe {
|
||||||
hasher.write(from_raw_parts(ptr, map_size));
|
hasher.write(from_raw_parts(ptr, map_size));
|
||||||
|
@ -22,11 +22,11 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) {
|
|||||||
{
|
{
|
||||||
#[cfg(feature = "sancov_pcguard_edges")]
|
#[cfg(feature = "sancov_pcguard_edges")]
|
||||||
{
|
{
|
||||||
(EDGES_MAP_PTR as *mut u8).add(pos).write(1);
|
EDGES_MAP_PTR.add(pos).write(1);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "sancov_pcguard_hitcounts")]
|
#[cfg(feature = "sancov_pcguard_hitcounts")]
|
||||||
{
|
{
|
||||||
let addr = (EDGES_MAP_PTR as *mut u8).add(pos);
|
let addr = EDGES_MAP_PTR.add(pos);
|
||||||
let val = addr.read().wrapping_add(1);
|
let val = addr.read().wrapping_add(1);
|
||||||
addr.write(val);
|
addr.write(val);
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,7 @@ fn postprocess(pda: &[Transition], stack_limit: usize) -> Automaton {
|
|||||||
//let mut culled_pda_unique = HashSet::new();
|
//let mut culled_pda_unique = HashSet::new();
|
||||||
|
|
||||||
for final_state in &finals {
|
for final_state in &finals {
|
||||||
for transition in pda.iter() {
|
for transition in pda {
|
||||||
if transition.dest == *final_state && transition.stack.len() > 0 {
|
if transition.dest == *final_state && transition.stack.len() > 0 {
|
||||||
blocklist.insert(transition.dest);
|
blocklist.insert(transition.dest);
|
||||||
} else {
|
} else {
|
||||||
@ -267,7 +267,7 @@ fn postprocess(pda: &[Transition], stack_limit: usize) -> Automaton {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Running FSA construction in exact approximation mode and postprocessing it like so
|
// Running FSA construction in exact approximation mode and postprocessing it like so
|
||||||
for transition in pda.iter() {
|
for transition in pda {
|
||||||
num_transition += 1;
|
num_transition += 1;
|
||||||
let state = transition.source;
|
let state = transition.source;
|
||||||
if state >= memoized.len() {
|
if state >= memoized.len() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user