avoid copy of function names

This commit is contained in:
Alwin Berger 2025-07-30 12:14:22 +00:00
parent 9bbc5e7c78
commit 49de014a31
7 changed files with 43 additions and 39 deletions

View File

@ -1,7 +1,7 @@
use hashbrown::HashMap;
use libafl_bolts::prelude::{SerdeAny, SerdeAnyMap};
use libafl_qemu::{elf::EasyElf, read_user_reg_unchecked, GuestAddr, GuestPhysAddr};
use std::{cmp::min, hash::{DefaultHasher, Hash, Hasher}, ops::Range};
use std::{borrow::Cow, cmp::min, hash::{DefaultHasher, Hash, Hasher}, ops::Range};
use crate::{
fuzzer::{DO_NUM_INTERRUPT, FIRST_INT},
@ -76,7 +76,7 @@ pub fn get_function_range(elf: &EasyElf, symbol: &str) -> Option<std::ops::Range
/// Check if an address is in any of the ranges
pub fn in_any_range<'a>(
ranges: &'a Vec<(String, Range<u32>)>,
ranges: &'a Vec<(Cow<'static, str>, Range<u32>)>,
addr: GuestAddr,
) -> Option<&'a std::ops::Range<GuestAddr>> {
for (_, r) in ranges {
@ -193,8 +193,8 @@ where
#[allow(unused)]
pub fn abb_profile(
mut intervals: Vec<ExecInterval>,
) -> HashMap<String, HashMap<u32, (usize, usize, u64, u64)>> {
let mut ret: HashMap<String, HashMap<u32, (usize, usize, u64, u64)>> = HashMap::new();
) -> HashMap<Cow<'static, str>, HashMap<u32, (usize, usize, u64, u64)>> {
let mut ret: HashMap<Cow<'static, str>, HashMap<u32, (usize, usize, u64, u64)>> = HashMap::new();
intervals.sort_by_key(|x| x.get_task_name_unchecked());
intervals
.chunk_by_mut(|x, y| x.get_task_name_unchecked() == y.get_task_name_unchecked())

View File

@ -9,6 +9,7 @@ use std::hash::Hash;
use hashbrown::HashMap;
use serde::{Deserialize, Serialize};
use itertools::Itertools;
use std::borrow::Cow;
pub mod helpers;
pub mod feedbacks;
@ -56,8 +57,8 @@ pub struct ExecInterval {
pub end_tick: u64,
pub start_state: u64,
pub end_state: u64,
pub start_capture: (CaptureEvent, String),
pub end_capture: (CaptureEvent, String),
pub start_capture: (CaptureEvent, Cow<'static, str>),
pub end_capture: (CaptureEvent, Cow<'static, str>),
pub level: u8,
// tick_spend_preempted: u64,
pub abb: Option<AtomicBasicBlock>
@ -93,11 +94,11 @@ impl ExecInterval {
return (self.start_state, self.abb.as_ref().expect("ABB not set").get_hash())
}
pub fn get_task_name(&self) -> Option<String> {
pub fn get_task_name(&self) -> Option<Cow<'static, str>> {
self.abb.as_ref().map(|x| x.instance_name.clone()).flatten()
}
pub fn get_task_name_unchecked(&self) -> String {
self.get_task_name().unwrap_or_else(|| "unknown".to_string())
pub fn get_task_name_unchecked(&self) -> Cow<'static, str> {
self.get_task_name().unwrap_or_else(|| Cow::Owned("unknown".to_owned()))
}
pub fn is_abb_end(&self) -> bool {
@ -117,7 +118,7 @@ pub struct AtomicBasicBlock {
ends: HashSet<GuestAddr>,
level: u8,
instance_id: usize,
instance_name: Option<String>,
instance_name: Option<Cow<'static, str>>,
}
impl PartialEq for AtomicBasicBlock {
@ -146,7 +147,7 @@ impl fmt::Display for AtomicBasicBlock {
for end in &self.ends {
ends_str.push_str(&format!("0x{:#x}, ", end));
}
write!(f, "ABB {} {{ level: {}, start: 0x{:#x}, ends: [{}]}}", &self.instance_name.as_ref().unwrap_or(&"".to_string()), self.level, self.start, ends_str.trim().trim_matches(','))
write!(f, "ABB {} {{ level: {}, start: 0x{:#x}, ends: [{}]}}", &self.instance_name.as_ref().unwrap_or(&Cow::Owned("".to_owned())), self.level, self.start, ends_str.trim().trim_matches(','))
}
}
impl fmt::Debug for AtomicBasicBlock {
@ -155,7 +156,7 @@ impl fmt::Debug for AtomicBasicBlock {
for end in &self.ends {
ends_str.push_str(&format!("{:#x}, ", end));
}
write!(f, "ABB {} {{ level: {}, start: 0x{:#x}, ends: [{}]}}", &self.instance_name.as_ref().unwrap_or(&"".to_string()), self.level, self.start, ends_str.trim().trim_matches(','))
write!(f, "ABB {} {{ level: {}, start: 0x{:#x}, ends: [{}]}}", &self.instance_name.as_ref().unwrap_or(&Cow::Owned("".to_owned())), self.level, self.start, ends_str.trim().trim_matches(','))
}
}

View File

@ -105,7 +105,7 @@ where
pub struct STGEdge
{
pub event: CaptureEvent,
pub name: String,
pub name: Cow<'static, str>,
pub worst: Option<(u64, Vec<(u32, u8)>)>,
}
@ -123,7 +123,7 @@ impl STGEdge {
short
}
pub fn color_print(&self) -> String {
let mut short = self.name.clone();
let mut short = self.name.to_string();
short.push_str(match self.event {
CaptureEvent::APIStart => "\", color=\"blue",
CaptureEvent::APIEnd => "\", color=\"black",
@ -553,7 +553,7 @@ where
}
// every path terminates at the end
if !fbs.graph.neighbors_directed(return_node_trace[return_node_trace.len()-1].0, Direction::Outgoing).any(|x| x == fbs.exitpoint) {
let mut e__ = STGEdge { event: CaptureEvent::End, name: String::from("End"), worst: None };
let mut e__ = STGEdge { event: CaptureEvent::End, name: Cow::Borrowed("End"), worst: None };
if let Some((time, accesses)) = instance_time.get_mut(&trace[trace.len()-1].abb.as_ref().unwrap().instance_id) {
e__.worst = Some((*time, accesses.clone()));
}

View File

@ -2,6 +2,7 @@
use libafl_qemu::GuestAddr;
use qemu_module::{FreeRTOSSystemStateHelper, MEM_READ};
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use crate::{
impl_emu_lookup,
@ -195,23 +196,23 @@ fn trigger_collection(
match event {
CaptureEvent::APIStart => {
let s = h.api_fn_addrs.get(&edge.1).unwrap();
systemstate.capture_point = (CaptureEvent::APIStart, s.to_string());
let s : &Cow<'static, str> = h.api_fn_addrs.get(&edge.1).unwrap();
systemstate.capture_point = (CaptureEvent::APIStart, s.clone());
}
CaptureEvent::APIEnd => {
let s = h.api_fn_addrs.get(&edge.0).unwrap();
systemstate.capture_point = (CaptureEvent::APIEnd, s.to_string());
let s : &Cow<'static, str> = h.api_fn_addrs.get(&edge.0).unwrap();
systemstate.capture_point = (CaptureEvent::APIEnd, s.clone());
}
CaptureEvent::ISRStart => {
let s = h.isr_fn_addrs.get(&edge.1).unwrap();
systemstate.capture_point = (CaptureEvent::ISRStart, s.to_string());
let s : &Cow<'static, str> = h.isr_fn_addrs.get(&edge.1).unwrap();
systemstate.capture_point = (CaptureEvent::ISRStart, s.clone());
}
CaptureEvent::ISREnd => {
let s = h.isr_fn_addrs.get(&edge.0).unwrap();
systemstate.capture_point = (CaptureEvent::ISREnd, s.to_string());
let s : &Cow<'static, str> = h.isr_fn_addrs.get(&edge.0).unwrap();
systemstate.capture_point = (CaptureEvent::ISREnd, s.clone());
}
CaptureEvent::End => {
systemstate.capture_point = (CaptureEvent::End, "".to_string());
systemstate.capture_point = (CaptureEvent::End, Cow::Borrowed(""));
}
CaptureEvent::Undefined => (),
}
@ -302,7 +303,7 @@ pub struct RawFreeRTOSSystemState {
read_invalid: bool,
input_counter: u32,
edge: (GuestAddr, GuestAddr),
capture_point: (CaptureEvent, String),
capture_point: (CaptureEvent, Cow<'static, str>),
mem_reads: Vec<(u32, u8)>,
}
/// List of system state dumps from EmulatorModules
@ -459,7 +460,7 @@ impl fmt::Display for FreeRTOSSystemState {
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub(crate)struct FreeRTOSSystemStateContext {
pub qemu_tick: u64,
pub capture_point: (CaptureEvent, String),
pub capture_point: (CaptureEvent, Cow<'static, str>),
pub edge: (GuestAddr, GuestAddr),
pub mem_reads: Vec<(u32, u8)>,
}

View File

@ -124,7 +124,7 @@ pub(crate) fn refine_system_states(
});
ret.1.push(FreeRTOSSystemStateContext {
qemu_tick: i.qemu_tick,
capture_point: (i.capture_point.0, i.capture_point.1.to_string()),
capture_point: (i.capture_point.0, i.capture_point.1),
edge: i.edge,
mem_reads: i.mem_reads,
});
@ -328,7 +328,7 @@ pub(crate) fn add_abb_info(
},
instance_id: id_count,
instance_name: if trace[i].level < 2 {
Some(curr_name.clone().clone())
Some(Cow::Owned(curr_name.to_owned()))
} else {
None
},
@ -352,7 +352,7 @@ pub(crate) fn add_abb_info(
2
},
instance_id: id_count,
instance_name: Some(curr_name.clone().clone()),
instance_name: Some(Cow::Owned(curr_name.to_owned())),
})));
id_count += 1;
open_abb_at_this_ret_addr_and_task.insert(
@ -390,7 +390,7 @@ pub(crate) fn add_abb_info(
},
instance_id: id_count,
instance_name: if trace[i].level < 1 {
Some(curr_name.clone().clone())
Some(Cow::Owned(curr_name.to_owned()))
} else {
None
},
@ -474,7 +474,7 @@ pub(crate) fn get_releases(
// A timed release is SysTickHandler isr block that moves a task from the delay list to the ready list.
if i.start_capture.0 == CaptureEvent::ISRStart
&& (i.start_capture.1 == "xPortSysTickHandler"
|| USR_ISR_SYMBOLS.contains(&i.start_capture.1.as_str()))
|| USR_ISR_SYMBOLS.contains(&&*i.start_capture.1))
{
// detect race-conditions, get start and end state from the nearest valid intervals
if states

View File

@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::ops::Range;
use freertos::FreeRTOSTraceMetadata;
@ -30,11 +31,11 @@ pub struct FreeRTOSSystemStateHelper {
// Address of the application code
pub app_range: Range<GuestAddr>,
// Address of API functions
pub api_fn_addrs: HashMap<GuestAddr, String>,
pub api_fn_ranges: Vec<(String, std::ops::Range<GuestAddr>)>,
pub api_fn_addrs: HashMap<GuestAddr, Cow<'static, str>>,
pub api_fn_ranges: Vec<(Cow<'static, str>, std::ops::Range<GuestAddr>)>,
// Address of interrupt routines
pub isr_fn_addrs: HashMap<GuestAddr, String>,
pub isr_fn_ranges: Vec<(String, std::ops::Range<GuestAddr>)>,
pub isr_fn_addrs: HashMap<GuestAddr, Cow<'static, str>>,
pub isr_fn_ranges: Vec<(Cow<'static, str>, std::ops::Range<GuestAddr>)>,
// Address of input memory
pub input_mem: Range<GuestAddr>,
// FreeRTOS specific addresses
@ -58,9 +59,9 @@ impl FreeRTOSSystemStateHelper {
) -> Self {
let app_range = target_ranges.get("APP_CODE").unwrap().clone();
let api_fn_ranges : Vec<_> = target_groups.get("API_FN").unwrap().iter().sorted_by_key(|x|x.1.start).map(|(n,r)| (n.clone(),r.clone())).collect();
let api_fn_ranges : Vec<_> = target_groups.get("API_FN").unwrap().iter().sorted_by_key(|x|x.1.start).map(|(n,r)| (Cow::Borrowed(Box::leak(n.clone().into_boxed_str())),r.clone())).collect();
let api_fn_addrs = api_fn_ranges.iter().map(|(n,r)| (r.start,n.clone())).collect();
let isr_fn_ranges : Vec<_> = target_groups.get("ISR_FN").unwrap().iter().sorted_by_key(|x|x.1.start).map(|(n,r)| (n.clone(),r.clone())).collect();
let isr_fn_ranges : Vec<_> = target_groups.get("ISR_FN").unwrap().iter().sorted_by_key(|x|x.1.start).map(|(n,r)| (Cow::Borrowed(Box::leak(n.clone().into_boxed_str())),r.clone())).collect();
let isr_fn_addrs = isr_fn_ranges.iter().map(|(n,r)| (r.start,n.clone())).collect();
let input_mem = target_symbols.get("FUZZ_INPUT").map(|x| *x..(*x+unsafe{MAX_INPUT_SIZE as GuestAddr})).unwrap();
@ -172,7 +173,7 @@ where
let pc = c.read_reg::<i32>(15).unwrap();
let last = current_systemstate_vec.last_mut().unwrap();
last.edge = (pc, 0);
last.capture_point =(CaptureEvent::End, "Breakpoint".to_string());
last.capture_point =(CaptureEvent::End, Cow::Borrowed("Breakpoint"));
// Find the first ISREnd of vPortSVCHandler (start of the first task) and drop anything before
unsafe {
let mut index = 0;

View File

@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::collections::hash_map::DefaultHasher;
use std::fmt;
use hashbrown::HashSet;
@ -81,7 +82,7 @@ pub trait SystemTraceData: Serialize + Sized + for<'a> Deserialize<'a> + Default
fn select_abb_profile(
&self,
select_task: Option<String>,
) -> HashMap<String, HashMap<u32, (usize, usize, u64, u64)>> {
) -> HashMap<Cow<'static, str>, HashMap<u32, (usize, usize, u64, u64)>> {
if let Some(select_task) = select_task.as_ref() {
// Task selected, only profile this task
let wjptybrt = self.worst_jobs_per_task_by_response_time();