use btf_rs::{Btf, Type};
use super::MAX_BTF_ID_PROBE;
#[derive(Debug, Clone)]
pub struct PayloadTypeChoice {
pub target_type_id: u32,
pub reason: String,
}
pub fn discover_payload_btf_id(
btf: &Btf,
payload_size: usize,
allocator_name: &str,
) -> PayloadTypeChoice {
if payload_size == 0 {
return PayloadTypeChoice {
target_type_id: 0,
reason: "payload_size == 0".into(),
};
}
let mut size_matches: Vec<(u32, String)> = Vec::new();
const CONSECUTIVE_FAIL_CAP: u32 = 64;
let mut tid: u32 = 1;
let mut consecutive_fail: u32 = 0;
while tid < MAX_BTF_ID_PROBE {
match btf.resolve_type_by_id(tid) {
Ok(ty) => {
consecutive_fail = 0;
if let Type::Struct(s) = ty
&& s.size() == payload_size
&& let Ok(name) = btf.resolve_name(&s)
&& !name.is_empty()
{
size_matches.push((tid, name));
}
}
Err(_) => {
consecutive_fail += 1;
if consecutive_fail >= CONSECUTIVE_FAIL_CAP {
break;
}
}
}
tid += 1;
}
match size_matches.len() {
0 => PayloadTypeChoice {
target_type_id: 0,
reason: format!("no candidate of size {payload_size}"),
},
1 => PayloadTypeChoice {
target_type_id: size_matches[0].0,
reason: String::new(),
},
n => {
let name_stem = allocator_name
.strip_suffix("_allocator")
.unwrap_or(allocator_name);
if !name_stem.is_empty() {
let stems: &[&str] = &[name_stem, name_stem.strip_prefix("scx_").unwrap_or("")];
for stem in stems {
if stem.is_empty() {
continue;
}
let hits: Vec<u32> = size_matches
.iter()
.filter(|(_, sn)| sn == stem)
.map(|(id, _)| *id)
.collect();
if hits.len() == 1 {
return PayloadTypeChoice {
target_type_id: hits[0],
reason: String::new(),
};
}
}
}
type Pat = fn(&str) -> bool;
let patterns: &[Pat] = &[
|n: &str| n == "task_ctx",
|n: &str| n.ends_with("_arena_ctx"),
|n: &str| n.ends_with("_task_ctx"),
|n: &str| n.ends_with("_ctx"),
];
for pat in patterns {
let hits: Vec<u32> = size_matches
.iter()
.filter(|(_, n)| pat(n))
.map(|(id, _)| *id)
.collect();
match hits.len() {
0 => continue,
1 => {
return PayloadTypeChoice {
target_type_id: hits[0],
reason: String::new(),
};
}
_ => {
continue;
}
}
}
PayloadTypeChoice {
target_type_id: 0,
reason: format!("ambiguous: {n} candidates"),
}
}
}
}