configurable interrupt sources

This commit is contained in:
Alwin Berger 2024-09-09 10:56:39 +02:00
parent 288abeb6bf
commit 740ce09d31
4 changed files with 107 additions and 59 deletions

View File

@ -1,33 +1,34 @@
kernel,main_function,input_symbol,input_size,return_function,select_task kernel,main_function,input_symbol,input_size,return_function,select_task,interrupts
mpeg2,mpeg2_main,mpeg2_oldorgframe,90112,mpeg2_return,NONE mpeg2,mpeg2_main,mpeg2_oldorgframe,90112,mpeg2_return,NONE,0#1000
audiobeam,audiobeam_main,audiobeam_input,11520,audiobeam_return,NONE audiobeam,audiobeam_main,audiobeam_input,11520,audiobeam_return,NONE,0#1000
epic,epic_main,epic_image,4096,epic_return,NONE epic,epic_main,epic_image,4096,epic_return,NONE,0#1000
dijkstra,dijkstra_main,dijkstra_AdjMatrix,10000,dijkstra_return,NONE dijkstra,dijkstra_main,dijkstra_AdjMatrix,10000,dijkstra_return,NONE,0#1000
fft,fft_main,fft_twidtable,2046,fft_return,NONE fft,fft_main,fft_twidtable,2046,fft_return,NONE,0#1000
bsort,bsort_main,bsort_Array,400,bsort_return,NONE bsort,bsort_main,bsort_Array,400,bsort_return,NONE,0#1000
insertsort,insertsort_main,insertsort_a,400,insertsort_return,NONE insertsort,insertsort_main,insertsort_a,400,insertsort_return,NONE,0#1000
g723_enc,g723_enc_main,g723_enc_INPUT,1024,g723_enc_return,NONE g723_enc,g723_enc_main,g723_enc_INPUT,1024,g723_enc_return,NONE,0#1000
rijndael_dec,rijndael_dec_main,rijndael_dec_data,32768,rijndael_dec_return,NONE rijndael_dec,rijndael_dec_main,rijndael_dec_data,32768,rijndael_dec_return,NONE,0#1000
rijndael_enc,rijndael_enc_main,rijndael_enc_data,31369,rijndael_enc_return,NONE rijndael_enc,rijndael_enc_main,rijndael_enc_data,31369,rijndael_enc_return,NONE,0#1000
huff_dec,huff_dec_main,huff_dec_encoded,419,huff_dec_return,NONE huff_dec,huff_dec_main,huff_dec_encoded,419,huff_dec_return,NONE,0#1000
huff_enc,huff_enc_main,huff_enc_plaintext,600,huff_enc_return,NONE huff_enc,huff_enc_main,huff_enc_plaintext,600,huff_enc_return,NONE,0#1000
gsm_enc,gsm_enc_main,gsm_enc_pcmdata,6400,gsm_enc_return,NONE gsm_enc,gsm_enc_main,gsm_enc_pcmdata,6400,gsm_enc_return,NONE,0#1000
tmr,main,FUZZ_INPUT,32,trigger_Qemu_break,NONE tmr,main,FUZZ_INPUT,32,trigger_Qemu_break,NONE,0#1000
tacle_rtos,prvStage0,FUZZ_INPUT,604,trigger_Qemu_break,NONE tacle_rtos,prvStage0,FUZZ_INPUT,604,trigger_Qemu_break,NONE,0#1000
lift,main_lift,FUZZ_INPUT,100,trigger_Qemu_break,NONE lift,main_lift,FUZZ_INPUT,100,trigger_Qemu_break,NONE,0#1000
waters,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129 waters,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129,0#1000
watersv2,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129 watersv2,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129,0#1000
waterspart,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129 waterspart,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129,0#1000
waterspartv2,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129 waterspartv2,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129,0#1000
waters_int,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129 waters_int,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129,0#1000
watersv2_int,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129 watersv2_int,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129,0#1000
waterspart_int,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129 waterspart_int,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129,0#1000
waterspartv2_int,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129 waterspartv2_int,main_waters,FUZZ_INPUT,4096,trigger_Qemu_break,1129,0#1000
micro_branchless,main_branchless,FUZZ_INPUT,4,trigger_Qemu_break,NONE micro_branchless,main_branchless,FUZZ_INPUT,4,trigger_Qemu_break,NONE,0#1000
micro_int,main_int,FUZZ_INPUT,16,trigger_Qemu_break,NONE micro_int,main_int,FUZZ_INPUT,16,trigger_Qemu_break,NONE,0#1000
micro_longint,main_micro_longint,FUZZ_INPUT,16,trigger_Qemu_break,NONE micro_longint,main_micro_longint,FUZZ_INPUT,16,trigger_Qemu_break,NONE,0#1000
minimal,main_minimal,FUZZ_INPUT,4096,trigger_Qemu_break,NONE minimal,main_minimal,FUZZ_INPUT,4096,trigger_Qemu_break,NONE,0#1000
gen3,main_minimal,FUZZ_INPUT,4096,trigger_Qemu_break,NONE gen3,main_minimal,FUZZ_INPUT,4096,trigger_Qemu_break,NONE,0#1000
interact,main_interact,FUZZ_INPUT,4096,trigger_Qemu_break,NONE interact,main_interact,FUZZ_INPUT,4096,trigger_Qemu_break,NONE,0#1000
interact_int,main_interact,FUZZ_INPUT,4096,trigger_Qemu_break,NONE interact_int,main_interact,FUZZ_INPUT,4096,trigger_Qemu_break,NONE,0#1000
release,main_release,FUZZ_INPUT,4096,trigger_Qemu_break,T3 release,main_release,FUZZ_INPUT,4096,trigger_Qemu_break,T3,0#10000;1#1000;2#2000;3#3000

1 kernel main_function input_symbol input_size return_function select_task interrupts
2 mpeg2 mpeg2_main mpeg2_oldorgframe 90112 mpeg2_return NONE 0#1000
3 audiobeam audiobeam_main audiobeam_input 11520 audiobeam_return NONE 0#1000
4 epic epic_main epic_image 4096 epic_return NONE 0#1000
5 dijkstra dijkstra_main dijkstra_AdjMatrix 10000 dijkstra_return NONE 0#1000
6 fft fft_main fft_twidtable 2046 fft_return NONE 0#1000
7 bsort bsort_main bsort_Array 400 bsort_return NONE 0#1000
8 insertsort insertsort_main insertsort_a 400 insertsort_return NONE 0#1000
9 g723_enc g723_enc_main g723_enc_INPUT 1024 g723_enc_return NONE 0#1000
10 rijndael_dec rijndael_dec_main rijndael_dec_data 32768 rijndael_dec_return NONE 0#1000
11 rijndael_enc rijndael_enc_main rijndael_enc_data 31369 rijndael_enc_return NONE 0#1000
12 huff_dec huff_dec_main huff_dec_encoded 419 huff_dec_return NONE 0#1000
13 huff_enc huff_enc_main huff_enc_plaintext 600 huff_enc_return NONE 0#1000
14 gsm_enc gsm_enc_main gsm_enc_pcmdata 6400 gsm_enc_return NONE 0#1000
15 tmr main FUZZ_INPUT 32 trigger_Qemu_break NONE 0#1000
16 tacle_rtos prvStage0 FUZZ_INPUT 604 trigger_Qemu_break NONE 0#1000
17 lift main_lift FUZZ_INPUT 100 trigger_Qemu_break NONE 0#1000
18 waters main_waters FUZZ_INPUT 4096 trigger_Qemu_break 1129 0#1000
19 watersv2 main_waters FUZZ_INPUT 4096 trigger_Qemu_break 1129 0#1000
20 waterspart main_waters FUZZ_INPUT 4096 trigger_Qemu_break 1129 0#1000
21 waterspartv2 main_waters FUZZ_INPUT 4096 trigger_Qemu_break 1129 0#1000
22 waters_int main_waters FUZZ_INPUT 4096 trigger_Qemu_break 1129 0#1000
23 watersv2_int main_waters FUZZ_INPUT 4096 trigger_Qemu_break 1129 0#1000
24 waterspart_int main_waters FUZZ_INPUT 4096 trigger_Qemu_break 1129 0#1000
25 waterspartv2_int main_waters FUZZ_INPUT 4096 trigger_Qemu_break 1129 0#1000
26 micro_branchless main_branchless FUZZ_INPUT 4 trigger_Qemu_break NONE 0#1000
27 micro_int main_int FUZZ_INPUT 16 trigger_Qemu_break NONE 0#1000
28 micro_longint main_micro_longint FUZZ_INPUT 16 trigger_Qemu_break NONE 0#1000
29 minimal main_minimal FUZZ_INPUT 4096 trigger_Qemu_break NONE 0#1000
30 gen3 main_minimal FUZZ_INPUT 4096 trigger_Qemu_break NONE 0#1000
31 interact main_interact FUZZ_INPUT 4096 trigger_Qemu_break NONE 0#1000
32 interact_int main_interact FUZZ_INPUT 4096 trigger_Qemu_break NONE 0#1000
33 release main_release FUZZ_INPUT 4096 trigger_Qemu_break T3 0#10000;1#1000;2#2000;3#3000
34

View File

@ -90,3 +90,26 @@ pub fn set_env_from_config(kernel : &PathBuf, path : &PathBuf) {
} }
} }
} }
pub fn get_interrupt_config(kernel : &PathBuf, path : &PathBuf) -> Vec<(usize,u32)>{
let is_csv = path.as_path().extension().map_or(false, |x| x=="csv");
if !is_csv {
panic!("Interrupt config must be inside a CSV file");
} else {
let mut reader = csv::Reader::from_path(path).expect("CSV read from config failed");
let p = kernel.as_path();
let stem = p.file_stem().expect("Kernel filename error").to_str().unwrap();
for r in reader.records() {
let rec = r.expect("CSV entry error");
if stem == &rec[0] {
let ret = rec[6].split(';').map(|x| {
let pair = x.split_once('#').expect("Interrupt config error");
(pair.0.parse().expect("Interrupt config error"), pair.1.parse().expect("Interrupt config error"))
}).collect();
println!("Interrupt config {:?}", ret);
return ret;
}
}
}
return Vec::new();
}

View File

@ -21,7 +21,7 @@ use crate::{
qemustate::QemuStateRestoreHelper qemustate::QemuStateRestoreHelper
}, },
systemstate::{self, feedbacks::{DumpSystraceFeedback, SystraceErrorFeedback}, helpers::{get_function_range, load_symbol, try_load_symbol, QemuSystemStateHelper}, observers::QemuSystemStateObserver, schedulers::{GenerationScheduler, LongestTraceScheduler}, stg::{stg_map_mut_slice, GraphMaximizerCorpusScheduler, STGEdge, STGNode, StgFeedback, MAX_STG_NUM}}, systemstate::{self, feedbacks::{DumpSystraceFeedback, SystraceErrorFeedback}, helpers::{get_function_range, load_symbol, try_load_symbol, QemuSystemStateHelper}, observers::QemuSystemStateObserver, schedulers::{GenerationScheduler, LongestTraceScheduler}, stg::{stg_map_mut_slice, GraphMaximizerCorpusScheduler, STGEdge, STGNode, StgFeedback, MAX_STG_NUM}},
systemstate::mutational::{input_bytes_to_interrupt_times, InterruptShiftStage, MINIMUM_INTER_ARRIVAL_TIME}, systemstate::mutational::{input_bytes_to_interrupt_times, InterruptShiftStage},
}; };
use std::time::SystemTime; use std::time::SystemTime;
use petgraph::dot::Dot; use petgraph::dot::Dot;
@ -164,6 +164,7 @@ log::set_max_level(log::LevelFilter::Info);
SimpleStderrLogger::set_logger().unwrap(); SimpleStderrLogger::set_logger().unwrap();
let cli = Cli::parse(); let cli = Cli::parse();
set_env_from_config(&cli.kernel, &cli.config); set_env_from_config(&cli.kernel, &cli.config);
let interrupt_config = crate::cli::get_interrupt_config(&cli.kernel, &cli.config);
unsafe {FUZZ_START_TIMESTAMP = SystemTime::now();} unsafe {FUZZ_START_TIMESTAMP = SystemTime::now();}
if cli.dump_name.is_none() && (cli.dump_times || cli.dump_cases || cli.dump_traces || cli.dump_graph) { if cli.dump_name.is_none() && (cli.dump_times || cli.dump_cases || cli.dump_traces || cli.dump_graph) {
panic!("Dump name not give but dump is requested"); panic!("Dump name not give but dump is requested");
@ -272,6 +273,18 @@ let api_ranges : Vec<_> = api_ranges.into_iter().collect();
#[cfg(feature = "observe_systemstate")] #[cfg(feature = "observe_systemstate")]
let isr_ranges : Vec<_> = isr_ranges.into_iter().collect(); let isr_ranges : Vec<_> = isr_ranges.into_iter().collect();
/// Setup the interrupt inputs. Noop if interrupts are not fuzzed
fn setup_interrupt_inputs(mut input : MultipartInput<BytesInput>, interrupt_config : &Vec<(usize,u32)>) -> MultipartInput<BytesInput> {
#[cfg(feature = "fuzz_int")]
for (i,_) in interrupt_config {
let name = format!("interrupts_{}",i);
if input.parts_by_name(&name).next().is_none() {
input.add_part(name, BytesInput::new([0; MAX_NUM_INTERRUPT*4].to_vec()));
}
}
input
}
// Client setup ================================================================================ // Client setup ================================================================================
let run_client = |state: Option<_>, mut mgr, _core_id| { let run_client = |state: Option<_>, mut mgr, _core_id| {
@ -331,10 +344,14 @@ let run_client = |state: Option<_>, mut mgr, _core_id| {
unsafe { unsafe {
#[cfg(feature = "fuzz_int")] #[cfg(feature = "fuzz_int")]
{ {
let time_bytes = input.parts_by_name("interrupts").next().map(|x| x.1.bytes()).unwrap_or(&[0u8; MAX_NUM_INTERRUPT*4]); for &c in &interrupt_config {
let t = input_bytes_to_interrupt_times(time_bytes); let (i,_) = c;
for i in 0..t.len() {libafl_interrupt_offsets[0][i]=t[i];} let name = format!("interrupts_{}",i);
libafl_num_interrupts[0]=t.len(); let input_bytes = input.parts_by_name(&name).next().map(|x| x.1.bytes()).unwrap_or(&[0u8; MAX_NUM_INTERRUPT*4]);
let t = input_bytes_to_interrupt_times(input_bytes, c);
for j in 0..t.len() {libafl_interrupt_offsets[i][j]=t[j];}
libafl_num_interrupts[i]=t.len();
}
// println!("Load: {:?}", libafl_interrupt_offsets[0..libafl_num_interrupts].to_vec()); // println!("Load: {:?}", libafl_interrupt_offsets[0..libafl_num_interrupts].to_vec());
} }
@ -502,7 +519,7 @@ let run_client = |state: Option<_>, mut mgr, _core_id| {
let stages = (systemstate::report::SchedulerStatsStage::default(),()); let stages = (systemstate::report::SchedulerStatsStage::default(),());
let mut stages = (StdMutationalStage::new(mutator), stages); let mut stages = (StdMutationalStage::new(mutator), stages);
#[cfg(feature = "fuzz_int")] #[cfg(feature = "fuzz_int")]
let mut stages = (InterruptShiftStage::new(), stages); let mut stages = (InterruptShiftStage::new(&interrupt_config), stages);
if let Commands::Showmap { input } = cli.command.clone() { if let Commands::Showmap { input } = cli.command.clone() {
let s = input.as_os_str(); let s = input.as_os_str();
@ -519,7 +536,7 @@ let run_client = |state: Option<_>, mut mgr, _core_id| {
Ok(x) => x, Ok(x) => x,
Err(_) => { Err(_) => {
println!("Interpreting input file as raw input"); println!("Interpreting input file as raw input");
MultipartInput::from([("interrupts",BytesInput::new([0; MAX_NUM_INTERRUPT].to_vec())),("bytes",BytesInput::new(input.as_os_str().as_encoded_bytes().to_vec()))]) setup_interrupt_inputs(MultipartInput::from([("bytes",BytesInput::new(input.as_os_str().as_encoded_bytes().to_vec()))]), &interrupt_config)
} }
}; };
fuzzer.evaluate_input(&mut state, &mut executor, &mut mgr, show_input) fuzzer.evaluate_input(&mut state, &mut executor, &mut mgr, show_input)
@ -533,7 +550,7 @@ let run_client = |state: Option<_>, mut mgr, _core_id| {
for _ in 0..100 { for _ in 0..100 {
let inp1 = BytesInput::new(vec![rng.gen::<u8>(); MAX_NUM_INTERRUPT*4]); let inp1 = BytesInput::new(vec![rng.gen::<u8>(); MAX_NUM_INTERRUPT*4]);
let inp2 = BytesInput::new(vec![rng.gen::<u8>(); MAX_INPUT_SIZE]); let inp2 = BytesInput::new(vec![rng.gen::<u8>(); MAX_INPUT_SIZE]);
let inp = MultipartInput::from([("interrupts",inp1),("bytes",inp2)]); let inp = setup_interrupt_inputs(MultipartInput::from([("bytes",inp2)]), &interrupt_config);
fuzzer.evaluate_input(&mut state, &mut executor, &mut mgr, inp).unwrap(); fuzzer.evaluate_input(&mut state, &mut executor, &mut mgr, inp).unwrap();
} }
} }
@ -576,7 +593,7 @@ let run_client = |state: Option<_>, mut mgr, _core_id| {
// libafl's generator is too slow // libafl's generator is too slow
let inp1 = BytesInput::new(vec![rng.gen::<u8>(); MAX_NUM_INTERRUPT*4]); let inp1 = BytesInput::new(vec![rng.gen::<u8>(); MAX_NUM_INTERRUPT*4]);
let inp2 = BytesInput::new(vec![rng.gen::<u8>(); MAX_INPUT_SIZE]); let inp2 = BytesInput::new(vec![rng.gen::<u8>(); MAX_INPUT_SIZE]);
let inp = MultipartInput::from([("interrupts",inp1),("bytes",inp2)]); let inp = setup_interrupt_inputs(MultipartInput::from([("bytes",inp2)]), &interrupt_config);
fuzzer.evaluate_input(&mut state, &mut executor, &mut mgr, inp).unwrap(); fuzzer.evaluate_input(&mut state, &mut executor, &mut mgr, inp).unwrap();
} }
}} else { }} else {

View File

@ -19,13 +19,13 @@ use std::borrow::Cow;
use super::stg::{STGEdge, STGNode}; use super::stg::{STGEdge, STGNode};
pub static mut MINIMUM_INTER_ARRIVAL_TIME : u32 = 1000 /*us*/ * QEMU_ISNS_PER_USEC; // pub static mut MINIMUM_INTER_ARRIVAL_TIME : u32 = 1000 /*us*/ * QEMU_ISNS_PER_USEC;
// one isn per 2**4 ns // one isn per 2**4 ns
// virtual insn/sec 62500000 = 1/16 GHz // virtual insn/sec 62500000 = 1/16 GHz
// 1ms = 62500 insn // 1ms = 62500 insn
// 1us = 62.5 insn // 1us = 62.5 insn
pub fn input_bytes_to_interrupt_times(buf: &[u8]) -> Vec<u32> { pub fn input_bytes_to_interrupt_times(buf: &[u8], config: (usize,u32)) -> Vec<u32> {
let len = buf.len(); let len = buf.len();
let mut start_tick : u32 = 0; let mut start_tick : u32 = 0;
let mut ret = Vec::with_capacity(DO_NUM_INTERRUPT); let mut ret = Vec::with_capacity(DO_NUM_INTERRUPT);
@ -45,8 +45,8 @@ pub fn input_bytes_to_interrupt_times(buf: &[u8]) -> Vec<u32> {
for i in 0..ret.len() { for i in 0..ret.len() {
if ret[i]==0 {continue;} if ret[i]==0 {continue;}
for j in i+1..ret.len()-1 { for j in i+1..ret.len()-1 {
if ret[j]-ret[i] < unsafe{MINIMUM_INTER_ARRIVAL_TIME} { if ret[j]-ret[i] < config.1 as u32 * QEMU_ISNS_PER_USEC {
ret[j] = u32::saturating_add(ret[i],unsafe{MINIMUM_INTER_ARRIVAL_TIME}); ret[j] = u32::saturating_add(ret[i],config.1 * QEMU_ISNS_PER_USEC);
} else {break;} } else {break;}
} }
} }
@ -70,11 +70,11 @@ fn is_candidate_for_new_branches(graph: &DiGraph<STGNode, STGEdge>, node: NodeIn
// TODO: this can be much more efficient, if the graph stored snapshots of the state and input progress was tracked // TODO: this can be much more efficient, if the graph stored snapshots of the state and input progress was tracked
/// Determines if a given node in the state transition graph (STG) is a candidate for introducing new branches. /// Determines if a given node in the state transition graph (STG) is a candidate for introducing new branches.
pub fn try_force_new_branches(interrupt_ticks : &[u32], fbs: &STGFeedbackState, meta: &STGNodeMetadata) -> Option<Vec<u32>> { pub fn try_force_new_branches(interrupt_ticks : &[u32], fbs: &STGFeedbackState, meta: &STGNodeMetadata, config: (usize, u32)) -> Option<Vec<u32>> {
let mut new = false; let mut new = false;
let mut new_interrupt_times = Vec::new(); let mut new_interrupt_times = Vec::new();
for (num,&interrupt_time) in interrupt_ticks.iter().enumerate() { for (num,&interrupt_time) in interrupt_ticks.iter().enumerate() {
let lower_bound = if num==0 {FIRST_INT} else {interrupt_ticks[num-1].saturating_add(unsafe{MINIMUM_INTER_ARRIVAL_TIME})}; let lower_bound = if num==0 {FIRST_INT} else {interrupt_ticks[num-1].saturating_add(config.1 * QEMU_ISNS_PER_USEC)};
let next = if interrupt_ticks.len()>num {interrupt_ticks[num+1]} else {u32::MAX}; let next = if interrupt_ticks.len()>num {interrupt_ticks[num+1]} else {u32::MAX};
for exec_interval in meta.intervals.iter().filter(|x| x.start_tick >= lower_bound as u64 && x.start_tick < next as u64) { for exec_interval in meta.intervals.iter().filter(|x| x.start_tick >= lower_bound as u64 && x.start_tick < next as u64) {
if !(exec_interval.start_capture.0==CaptureEvent::ISRStart) { // shortcut to skip interrupt handers without node lookup if !(exec_interval.start_capture.0==CaptureEvent::ISRStart) { // shortcut to skip interrupt handers without node lookup
@ -98,6 +98,7 @@ pub fn try_force_new_branches(interrupt_ticks : &[u32], fbs: &STGFeedbackState,
pub struct InterruptShiftStage<E, EM, Z> { pub struct InterruptShiftStage<E, EM, Z> {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(E, EM, Z)>, phantom: PhantomData<(E, EM, Z)>,
interrup_config: Vec<(usize,u32)>
} }
impl<E, EM, Z> InterruptShiftStage<E, EM, Z> impl<E, EM, Z> InterruptShiftStage<E, EM, Z>
@ -107,8 +108,8 @@ where
Z: Evaluator<E, EM>, Z: Evaluator<E, EM>,
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand, Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand,
{ {
pub fn new() -> Self { pub fn new(config : &Vec<(usize,u32)>) -> Self {
Self { phantom: PhantomData } Self { phantom: PhantomData, interrup_config: config.clone() }
} }
} }
@ -133,20 +134,26 @@ where
let mut myrand = StdRand::new(); let mut myrand = StdRand::new();
myrand.set_seed(state.rand_mut().next()); myrand.set_seed(state.rand_mut().next());
let mut loopcount = 0; let mut loopcount = 0;
let mut loopbound = 50; let mut loopbound = 50;
loop { loop {
let interrup_config = match myrand.choose(&self.interrup_config) {
Some(s) => s,
Option::None => return Ok(())
};
let name = format!("interrupts_{}", interrup_config.0);
// manager.log(state, LogSeverity::Info, format!("Mutation {}/{}", loopbound, loopcount))?; // manager.log(state, LogSeverity::Info, format!("Mutation {}/{}", loopbound, loopcount))?;
loopbound-=1; loopbound-=1;
let current_case = state.current_testcase()?; let current_case = state.current_testcase()?;
let old_input = current_case.input().as_ref().unwrap(); let old_input = current_case.input().as_ref().unwrap();
let old_interrupt_times = old_input.parts_by_name("interrupts").next(); let old_interrupt_times = old_input.parts_by_name(&name).next();
let mut new_input = old_input.clone(); let mut new_input = old_input.clone();
let mut new_interrupt_times : &mut I = if new_input.parts_by_name("interrupts").next().is_some() { let mut new_interrupt_times : &mut I = if new_input.parts_by_name(&name).next().is_some() {
new_input.parts_by_name_mut("interrupts").next().unwrap() new_input.parts_by_name_mut(&name).next().unwrap()
} else { } else {
new_input.add_part(String::from("interrupts"), I::default()); new_input.parts_by_name_mut("interrupts").next().unwrap() new_input.add_part(String::from(&name), I::default()); new_input.parts_by_name_mut(&name).next().unwrap()
}.1; }.1;
let mut do_rerun = false; let mut do_rerun = false;
// if state.rand_mut().between(1, 100) <= 50 // only attempt the mutation half of the time // if state.rand_mut().between(1, 100) <= 50 // only attempt the mutation half of the time
@ -156,7 +163,7 @@ where
let mut interrupt_offsets : [u32; MAX_NUM_INTERRUPT] = [u32::MAX; MAX_NUM_INTERRUPT]; let mut interrupt_offsets : [u32; MAX_NUM_INTERRUPT] = [u32::MAX; MAX_NUM_INTERRUPT];
let mut num_interrupts : usize = 0; let mut num_interrupts : usize = 0;
{ {
let t = input_bytes_to_interrupt_times(new_interrupt_times.bytes()); let t = input_bytes_to_interrupt_times(new_interrupt_times.bytes(), *interrup_config);
for i in 0..t.len() {interrupt_offsets[i]=t[i];} for i in 0..t.len() {interrupt_offsets[i]=t[i];}
num_interrupts=t.len(); num_interrupts=t.len();
} }
@ -180,7 +187,7 @@ where
let maxtick : u64 = hist.1.0; let maxtick : u64 = hist.1.0;
// let maxtick : u64 = (_input.exec_time().expect("No duration found").as_nanos() >> 4).try_into().unwrap(); // let maxtick : u64 = (_input.exec_time().expect("No duration found").as_nanos() >> 4).try_into().unwrap();
let mut numbers : Vec<u32> = vec![]; let mut numbers : Vec<u32> = vec![];
for i in 0..myrand.between(0,2*min(MAX_NUM_INTERRUPT, maxtick as usize / unsafe{MINIMUM_INTER_ARRIVAL_TIME as usize})) { for i in 0..myrand.between(0,2*min(MAX_NUM_INTERRUPT, maxtick as usize / (interrup_config.1 as usize * QEMU_ISNS_PER_USEC as usize))) {
prefix.push(u32::to_le_bytes(myrand.between(0, min(maxtick, u32::MAX as u64) as usize).try_into().expect("ticks > u32"))); prefix.push(u32::to_le_bytes(myrand.between(0, min(maxtick, u32::MAX as u64) as usize).try_into().expect("ticks > u32")));
} }
} }
@ -194,7 +201,7 @@ where
} }
}; };
if let Some(meta) = current_case.metadata_map().get::<STGNodeMetadata>() { if let Some(meta) = current_case.metadata_map().get::<STGNodeMetadata>() {
if let Some(t) = try_force_new_branches(&interrupt_offsets, feedbackstate, meta) { if let Some(t) = try_force_new_branches(&interrupt_offsets, feedbackstate, meta, *interrup_config) {
do_rerun = true; do_rerun = true;
for i in 0..t.len() { for i in 0..t.len() {
if i<num_interrupts { if i<num_interrupts {
@ -280,10 +287,10 @@ where
let mut lb = FIRST_INT; let mut lb = FIRST_INT;
let mut ub : u32 = marks[marks.len()-1].0.end_tick.try_into().expect("ticks > u32"); let mut ub : u32 = marks[marks.len()-1].0.end_tick.try_into().expect("ticks > u32");
if i > 0 { if i > 0 {
lb = u32::saturating_add(interrupt_offsets[i-1],unsafe{MINIMUM_INTER_ARRIVAL_TIME}); lb = u32::saturating_add(interrupt_offsets[i-1], interrup_config.1 * QEMU_ISNS_PER_USEC);
} }
if i < num_interrupts-1 { if i < num_interrupts-1 {
ub = u32::saturating_sub(interrupt_offsets[i+1],unsafe{MINIMUM_INTER_ARRIVAL_TIME}); ub = u32::saturating_sub(interrupt_offsets[i+1], interrup_config.1 * QEMU_ISNS_PER_USEC);
} }
// get old hit and handler // get old hit and handler
let old_hit = marks.iter().filter( let old_hit = marks.iter().filter(