const CAST_BTF_MAGIC: u16 = 0xEB9F;
const CAST_BTF_VERSION: u8 = 1;
const CAST_BTF_HEADER_LEN: u32 = 24;
const CAST_BTF_KIND_INT: u32 = 1;
const CAST_BTF_KIND_PTR: u32 = 2;
const CAST_BTF_KIND_STRUCT: u32 = 4;
const CAST_BTF_KIND_FWD: u32 = 7;
const CAST_BTF_KIND_TYPEDEF: u32 = 8;
const CAST_BTF_KIND_CONST: u32 = 10;
const CAST_BTF_KIND_TYPE_TAG: u32 = 18;
const CAST_BTF_KIND_ENUM: u32 = 6;
const CAST_BTF_KIND_ENUM64: u32 = 19;
const CAST_BTF_KIND_FLOAT: u32 = 16;
pub(crate) fn cast_build_btf(types: &[CastSynType], strings: &[u8]) -> Vec<u8> {
let mut type_section = Vec::new();
for ty in types {
match ty {
CastSynType::Int {
name_off,
size,
encoding,
offset,
bits,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = (CAST_BTF_KIND_INT << 24) & 0x1f00_0000;
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&size.to_le_bytes());
let int_data = (*encoding << 24) | ((*offset & 0xff) << 16) | (*bits & 0xff);
type_section.extend_from_slice(&int_data.to_le_bytes());
}
CastSynType::Struct {
name_off,
size,
members,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let vlen = members.len() as u32;
let info = ((CAST_BTF_KIND_STRUCT << 24) & 0x1f00_0000) | (vlen & 0xffff);
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&size.to_le_bytes());
for m in members {
type_section.extend_from_slice(&m.name_off.to_le_bytes());
type_section.extend_from_slice(&m.type_id.to_le_bytes());
let bit_off = m.byte_offset * 8;
type_section.extend_from_slice(&bit_off.to_le_bytes());
}
}
CastSynType::Typedef { name_off, type_id } => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = (CAST_BTF_KIND_TYPEDEF << 24) & 0x1f00_0000;
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&type_id.to_le_bytes());
}
CastSynType::Const { type_id } => {
let name_off: u32 = 0;
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = (CAST_BTF_KIND_CONST << 24) & 0x1f00_0000;
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&type_id.to_le_bytes());
}
CastSynType::TypeTag { name_off, type_id } => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = (CAST_BTF_KIND_TYPE_TAG << 24) & 0x1f00_0000;
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&type_id.to_le_bytes());
}
CastSynType::Ptr { type_id } => {
let name_off: u32 = 0;
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = (CAST_BTF_KIND_PTR << 24) & 0x1f00_0000;
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&type_id.to_le_bytes());
}
CastSynType::Fwd { name_off, is_union } => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let kind_flag = if *is_union { 1u32 << 31 } else { 0 };
let info = ((CAST_BTF_KIND_FWD << 24) & 0x1f00_0000) | kind_flag;
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&0u32.to_le_bytes());
}
CastSynType::BitfieldStruct {
name_off,
size,
members,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let vlen = members.len() as u32;
let info =
((CAST_BTF_KIND_STRUCT << 24) & 0x1f00_0000) | (vlen & 0xffff) | (1u32 << 31);
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&size.to_le_bytes());
for m in members {
type_section.extend_from_slice(&m.name_off.to_le_bytes());
type_section.extend_from_slice(&m.type_id.to_le_bytes());
let off_word = (m.bitfield_size << 24) | (m.bit_offset & 0x00ff_ffff);
type_section.extend_from_slice(&off_word.to_le_bytes());
}
}
CastSynType::Enum {
name_off,
size,
signed,
members,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let vlen = members.len() as u32;
let kf = if *signed { 1u32 << 31 } else { 0 };
let info = ((CAST_BTF_KIND_ENUM << 24) & 0x1f00_0000) | (vlen & 0xffff) | kf;
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&size.to_le_bytes());
for (m_name_off, val) in members {
type_section.extend_from_slice(&m_name_off.to_le_bytes());
type_section.extend_from_slice(&val.to_le_bytes());
}
}
CastSynType::Enum64 {
name_off,
size,
signed,
members,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let vlen = members.len() as u32;
let kf = if *signed { 1u32 << 31 } else { 0 };
let info = ((CAST_BTF_KIND_ENUM64 << 24) & 0x1f00_0000) | (vlen & 0xffff) | kf;
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&size.to_le_bytes());
for (m_name_off, val) in members {
type_section.extend_from_slice(&m_name_off.to_le_bytes());
let lo = (*val & 0xffff_ffff) as u32;
let hi = (*val >> 32) as u32;
type_section.extend_from_slice(&lo.to_le_bytes());
type_section.extend_from_slice(&hi.to_le_bytes());
}
}
CastSynType::Float { name_off, size } => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = (CAST_BTF_KIND_FLOAT << 24) & 0x1f00_0000;
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&size.to_le_bytes());
}
}
}
let type_len = type_section.len() as u32;
let str_len = strings.len() as u32;
let mut blob = Vec::new();
blob.extend_from_slice(&CAST_BTF_MAGIC.to_le_bytes());
blob.push(CAST_BTF_VERSION);
blob.push(0); blob.extend_from_slice(&CAST_BTF_HEADER_LEN.to_le_bytes());
blob.extend_from_slice(&0u32.to_le_bytes()); blob.extend_from_slice(&type_len.to_le_bytes());
blob.extend_from_slice(&type_len.to_le_bytes()); blob.extend_from_slice(&str_len.to_le_bytes());
blob.extend_from_slice(&type_section);
blob.extend_from_slice(strings);
blob
}
#[derive(Clone, Copy)]
pub(crate) struct CastSynMember {
pub(crate) name_off: u32,
pub(crate) type_id: u32,
pub(crate) byte_offset: u32,
}
#[derive(Clone, Copy)]
pub(crate) struct CastSynBitMember {
pub(crate) name_off: u32,
pub(crate) type_id: u32,
pub(crate) bit_offset: u32,
pub(crate) bitfield_size: u32,
}
pub(crate) enum CastSynType {
Int {
name_off: u32,
size: u32,
encoding: u32,
offset: u32,
bits: u32,
},
Struct {
name_off: u32,
size: u32,
members: Vec<CastSynMember>,
},
Typedef { name_off: u32, type_id: u32 },
Const { type_id: u32 },
TypeTag { name_off: u32, type_id: u32 },
Ptr { type_id: u32 },
Fwd { name_off: u32, is_union: bool },
BitfieldStruct {
name_off: u32,
size: u32,
members: Vec<CastSynBitMember>,
},
Enum {
name_off: u32,
size: u32,
signed: bool,
members: Vec<(u32, u32)>,
},
Enum64 {
name_off: u32,
size: u32,
signed: bool,
members: Vec<(u32, u64)>,
},
Float { name_off: u32, size: u32 },
}