1use std::{
4 collections::VecDeque,
5 fs::File,
6 io::{self, BufRead, BufReader},
7 path::{Path, PathBuf},
8 sync::{Arc, Mutex, Once},
9 time::{SystemTime, UNIX_EPOCH},
10};
11
12use libafl::{HasNamedMetadata, inputs::Input, mutators::Tokens, state::HasRand};
13use libafl_bolts::rands::Rand;
14
15use crate::common::cli::ReplayOptions;
16
17pub fn read_file_as_vecs<P: AsRef<Path>>(file_path: P) -> io::Result<Vec<Vec<u8>>> {
27 let path = file_path.as_ref();
28
29 if path.as_os_str().is_empty() {
30 return Ok(Vec::new());
31 }
32 let file = File::open(path)?;
33 let reader = BufReader::new(file);
34 let mut result = Vec::new();
35
36 for line in reader.lines() {
37 let line = line?;
38 result.push(line.into_bytes());
39 }
40
41 Ok(result)
42}
43
44pub fn save_queue<I>(
53 save_queue_dir: &Path,
54 input_queue: &Arc<Mutex<VecDeque<I>>>,
55) -> Option<PathBuf>
56where
57 I: Input,
58{
59 if save_queue_dir.as_os_str().is_empty() {
60 log::debug!("Crash directory is not set. Skipping saving inputs.");
61 return None;
62 }
63
64 let queue = match input_queue.lock() {
65 Ok(queue) => queue,
66 Err(e) => {
67 log::error!("Failed to lock input queue: {}", e);
68 return None;
69 }
70 };
71
72 if queue.is_empty() {
73 log::debug!("No inputs to save");
74 return None;
75 }
76
77 let timestamp = SystemTime::now()
78 .duration_since(UNIX_EPOCH)
79 .expect("SystemTime before UNIX EPOCH!")
80 .as_secs();
81
82 let save_subdir = save_queue_dir.join(format!("crash_{}", timestamp));
83
84 if let Err(e) = std::fs::create_dir_all(&save_subdir) {
85 log::error!("Failed to create crash subdirectory: {}", e);
86 return None;
87 }
88
89 for (idx, input) in queue.iter().enumerate() {
90 let file_path = save_subdir.join(format!("{}.inp", idx));
91 if let Err(e) = input.to_file(file_path) {
92 log::error!("Failed to write input to file: {}", e);
93 continue;
94 }
95 }
96
97 log::debug!(
98 "Saved {} inputs to directory: {:?}",
99 queue.len(),
100 save_subdir
101 );
102
103 Some(save_subdir)
104}
105
106pub fn replay<I, F, R>(
121 harness: &mut F,
122 replay_cfg: &ReplayOptions,
123) -> Result<(), Box<dyn std::error::Error>>
124where
125 I: Input,
126 F: FnMut(&I) -> R,
127{
128 let mut count = 0;
129
130 let end = replay_cfg.get_end();
131
132 for (index, file) in replay_cfg.get_replay_files().iter().enumerate() {
133 if index < replay_cfg.start || index >= end {
134 continue;
135 }
136
137 if replay_cfg.debug {
138 println!("Replaying file: {}", file.display());
139 }
140
141 let input = I::from_file(file).unwrap();
143 (*harness)(&input);
144
145 count += 1;
146 if count % 100 == 0 {
147 println!("Send {} messages", count);
148 }
149 }
150
151 println!("Send {} messages", count);
152
153 Ok(())
154}
155
156pub fn show_seed<I>(filename: &PathBuf)
158where
159 I: Input,
160{
161 if let Ok(input) = I::from_file(filename) {
162 println!("Input from file {}: {:?}", filename.display(), input);
163 } else {
164 println!("Failed to read input from file {}", filename.display());
165 }
166}
167
168static INIT: Once = Once::new();
169
170pub fn setup_logger() {
172 INIT.call_once(|| {
173 let _ = env_logger::try_init();
174 });
175}
176
177pub fn get_random_from_tokens<S>(state: &mut S, name: &str) -> Option<Vec<u8>>
186where
187 S: HasRand + HasNamedMetadata,
188{
189 let Some(meta) = state.named_metadata_map().get::<Tokens>(name) else {
190 return None;
191 };
192
193 if meta.tokens().len() == 0 {
194 return None;
195 }
196
197 let tokens_len = meta.tokens().len();
198 let token_idx = state.rand_mut().below_or_zero(tokens_len);
201
202 let Some(meta) = state.named_metadata_map().get::<Tokens>(name) else {
204 return None;
205 };
206 Some(meta.tokens()[token_idx].clone())
207}