use anyhow::{Context, Result};
use btf_rs::Btf;
use super::{
find_struct, member_byte_offset, member_byte_offset_with_member, resolve_member_struct,
};
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
pub struct TaskStorageOffsets {
pub smap_buckets: usize,
pub smap_bucket_log: usize,
pub bucket_size: usize,
pub bucket_list: usize,
pub hlist_head_first: usize,
pub hlist_node_next: usize,
pub elem_local_storage: usize,
pub elem_sdata: usize,
pub sdata_data: usize,
pub ls_owner: usize,
}
pub(crate) fn resolve_task_storage_offsets(btf: &Btf) -> Result<TaskStorageOffsets> {
let (smap_struct, _) = find_struct(btf, "bpf_local_storage_map")?;
let smap_buckets = member_byte_offset(btf, &smap_struct, "buckets")?;
let smap_bucket_log = member_byte_offset(btf, &smap_struct, "bucket_log")?;
let (bucket_struct, _) = find_struct(btf, "bpf_local_storage_map_bucket")?;
let bucket_size = bucket_struct.size();
let (bucket_list, list_member) = member_byte_offset_with_member(btf, &bucket_struct, "list")?;
let hlist_head_struct = resolve_member_struct(btf, &list_member)
.context("btf: resolve type of bpf_local_storage_map_bucket.list")?;
let hlist_head_first = member_byte_offset(btf, &hlist_head_struct, "first")?;
let (hlist_node_struct, _) = find_struct(btf, "hlist_node")?;
let hlist_node_next = member_byte_offset(btf, &hlist_node_struct, "next")?;
if hlist_node_next != 0 {
anyhow::bail!(
"hlist_node.next at offset {} (expected 0): walker advances \
chain via `elem + hlist_node_next` and the map_node-at-0 \
invariant assumes the link reads from elem base. A kernel \
that reorders hlist_node must teach the walker an explicit \
link offset before this resolver returns Ok.",
hlist_node_next,
);
}
let (elem_struct, _) = find_struct(btf, "bpf_local_storage_elem")?;
let map_node_off = member_byte_offset(btf, &elem_struct, "map_node")?;
if map_node_off != 0 {
anyhow::bail!(
"bpf_local_storage_elem.map_node at offset {} (expected 0): \
walker assumes elem_kva == node_kva. A kernel that reorders \
bpf_local_storage_elem must teach the walker container_of math \
before this resolver returns Ok.",
map_node_off,
);
}
let elem_local_storage = member_byte_offset(btf, &elem_struct, "local_storage")?;
let (elem_sdata, _) = member_byte_offset_with_member(btf, &elem_struct, "sdata")?;
let (sdata_struct, _) = find_struct(btf, "bpf_local_storage_data")?;
let sdata_data = member_byte_offset(btf, &sdata_struct, "data")?;
let (ls_struct, _) = find_struct(btf, "bpf_local_storage")?;
let ls_owner = member_byte_offset(btf, &ls_struct, "owner")?;
Ok(TaskStorageOffsets {
smap_buckets,
smap_bucket_log,
bucket_size,
bucket_list,
hlist_head_first,
hlist_node_next,
elem_local_storage,
elem_sdata,
sdata_data,
ls_owner,
})
}