use super::*;
use std::io::Write;
fn push_name(s: &mut Vec<u8>, name: &str) -> u32 {
let off = s.len() as u32;
s.extend_from_slice(name.as_bytes());
s.push(0);
off
}
const BTF_MAGIC: u16 = 0xEB9F;
const BTF_VERSION: u8 = 1;
const BTF_HEADER_LEN: u32 = 24;
const BTF_KIND_INT: u32 = 1;
const BTF_KIND_PTR: u32 = 2;
const BTF_KIND_ARRAY: u32 = 3;
const BTF_KIND_STRUCT: u32 = 4;
const BTF_KIND_UNION: u32 = 5;
const BTF_KIND_FWD: u32 = 7;
const BTF_KIND_TYPEDEF: u32 = 8;
const BTF_KIND_VOLATILE: u32 = 9;
const BTF_KIND_CONST: u32 = 10;
const BTF_KIND_FUNC: u32 = 12;
const BTF_KIND_FUNC_PROTO: u32 = 13;
const BTF_KIND_VAR: u32 = 14;
const BTF_KIND_DATASEC: u32 = 15;
const KIND_FLAG_BIT: u32 = 1 << 31;
#[derive(Clone, Copy)]
struct SynMember {
name_off: u32,
type_id: u32,
byte_offset: u32,
}
#[derive(Clone, Copy)]
struct SynParam {
name_off: u32,
type_id: u32,
}
#[derive(Clone, Copy)]
struct SynMemberBits {
name_off: u32,
type_id: u32,
bit_offset: u32,
bitfield_size_bits: u32,
}
#[allow(dead_code)] enum SynType {
Int {
name_off: u32,
size: u32,
encoding: u32,
offset: u32,
bits: u32,
},
Ptr {
type_id: u32,
},
Array {
type_id: u32,
index_type_id: u32,
nelems: u32,
},
Struct {
name_off: u32,
size: u32,
members: Vec<SynMember>,
},
Union {
name_off: u32,
size: u32,
members: Vec<SynMember>,
},
StructBitfields {
name_off: u32,
size: u32,
members: Vec<SynMemberBits>,
},
Fwd {
name_off: u32,
kind_flag: u32,
},
Typedef {
name_off: u32,
type_id: u32,
},
Volatile {
type_id: u32,
},
Const {
type_id: u32,
},
Func {
name_off: u32,
type_id: u32,
linkage: u32,
},
FuncProto {
return_type_id: u32,
params: Vec<SynParam>,
},
Var {
name_off: u32,
type_id: u32,
linkage: u32,
},
Datasec {
name_off: u32,
size: u32,
entries: Vec<SynVarSecinfo>,
},
}
#[derive(Clone, Copy)]
struct SynVarSecinfo {
type_id: u32,
offset: u32,
size: u32,
}
fn build_btf(types: &[SynType], strings: &[u8]) -> Vec<u8> {
let mut type_section = Vec::new();
for ty in types {
match ty {
SynType::Int {
name_off,
size,
encoding,
offset,
bits,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = (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());
}
SynType::Ptr { type_id } => {
let name_off: u32 = 0;
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = (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());
}
SynType::Array {
type_id,
index_type_id,
nelems,
} => {
let name_off: u32 = 0;
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = (BTF_KIND_ARRAY << 24) & 0x1f00_0000;
type_section.extend_from_slice(&info.to_le_bytes());
let size_type: u32 = 0;
type_section.extend_from_slice(&size_type.to_le_bytes());
type_section.extend_from_slice(&type_id.to_le_bytes());
type_section.extend_from_slice(&index_type_id.to_le_bytes());
type_section.extend_from_slice(&nelems.to_le_bytes());
}
SynType::Struct {
name_off,
size,
members,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let vlen = members.len() as u32;
let info = ((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());
}
}
SynType::Union {
name_off,
size,
members,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let vlen = members.len() as u32;
let info = ((BTF_KIND_UNION << 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());
}
}
SynType::StructBitfields {
name_off,
size,
members,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let vlen = members.len() as u32;
let info =
(((BTF_KIND_STRUCT << 24) & 0x1f00_0000) | (vlen & 0xffff)) | KIND_FLAG_BIT;
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 packed =
((m.bitfield_size_bits & 0xff) << 24) | (m.bit_offset & 0x00ff_ffff);
type_section.extend_from_slice(&packed.to_le_bytes());
}
}
SynType::Fwd {
name_off,
kind_flag,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = ((BTF_KIND_FWD << 24) & 0x1f00_0000) | ((*kind_flag & 0x1) << 31);
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&0u32.to_le_bytes());
}
SynType::Typedef { name_off, type_id } => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = (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());
}
SynType::Volatile { type_id } => {
let name_off: u32 = 0;
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = (BTF_KIND_VOLATILE << 24) & 0x1f00_0000;
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&type_id.to_le_bytes());
}
SynType::Const { type_id } => {
let name_off: u32 = 0;
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = (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());
}
SynType::Func {
name_off,
type_id,
linkage,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = ((BTF_KIND_FUNC << 24) & 0x1f00_0000) | (*linkage & 0xffff);
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&type_id.to_le_bytes());
}
SynType::FuncProto {
return_type_id,
params,
} => {
let name_off: u32 = 0;
type_section.extend_from_slice(&name_off.to_le_bytes());
let vlen = params.len() as u32;
let info = ((BTF_KIND_FUNC_PROTO << 24) & 0x1f00_0000) | (vlen & 0xffff);
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&return_type_id.to_le_bytes());
for p in params {
type_section.extend_from_slice(&p.name_off.to_le_bytes());
type_section.extend_from_slice(&p.type_id.to_le_bytes());
}
}
SynType::Var {
name_off,
type_id,
linkage,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = (BTF_KIND_VAR << 24) & 0x1f00_0000;
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&type_id.to_le_bytes());
type_section.extend_from_slice(&linkage.to_le_bytes());
}
SynType::Datasec {
name_off,
size,
entries,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let vlen = entries.len() as u32;
let info = ((BTF_KIND_DATASEC << 24) & 0x1f00_0000) | (vlen & 0xffff);
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&size.to_le_bytes());
for e in entries {
type_section.extend_from_slice(&e.type_id.to_le_bytes());
type_section.extend_from_slice(&e.offset.to_le_bytes());
type_section.extend_from_slice(&e.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.write_all(&BTF_MAGIC.to_le_bytes()).unwrap();
blob.push(BTF_VERSION);
blob.push(0); blob.write_all(&BTF_HEADER_LEN.to_le_bytes()).unwrap();
blob.write_all(&0u32.to_le_bytes()).unwrap(); blob.write_all(&type_len.to_le_bytes()).unwrap();
blob.write_all(&type_len.to_le_bytes()).unwrap(); blob.write_all(&str_len.to_le_bytes()).unwrap();
blob.extend_from_slice(&type_section);
blob.extend_from_slice(strings);
blob
}
fn btf_with_source_and_target(field_off: u32, target_off: u32) -> (Vec<u8>, u32, u32) {
let mut strings: Vec<u8> = vec![0];
let n_int = push_name(&mut strings, "u64");
let n_t = push_name(&mut strings, "T");
let n_q = push_name(&mut strings, "Q");
let n_f = push_name(&mut strings, "f");
let n_x = push_name(&mut strings, "x");
let types = vec![
SynType::Int {
name_off: n_int,
size: 8,
encoding: 0,
offset: 0,
bits: 64,
},
SynType::Struct {
name_off: n_t,
size: field_off + 8,
members: vec![SynMember {
name_off: n_f,
type_id: 1,
byte_offset: field_off,
}],
},
SynType::Struct {
name_off: n_q,
size: target_off + 8,
members: vec![SynMember {
name_off: n_x,
type_id: 1,
byte_offset: target_off,
}],
},
];
(build_btf(&types, &strings), 2, 3)
}
fn btf_source_and_two_targets(field_off: u32) -> (Vec<u8>, u32) {
let mut strings: Vec<u8> = vec![0];
let n_int = push_name(&mut strings, "u64");
let n_t = push_name(&mut strings, "T");
let n_q1 = push_name(&mut strings, "Q1");
let n_q2 = push_name(&mut strings, "Q2");
let n_f = push_name(&mut strings, "f");
let n_x = push_name(&mut strings, "x");
let types = vec![
SynType::Int {
name_off: n_int,
size: 8,
encoding: 0,
offset: 0,
bits: 64,
},
SynType::Struct {
name_off: n_t,
size: field_off + 8,
members: vec![SynMember {
name_off: n_f,
type_id: 1,
byte_offset: field_off,
}],
},
SynType::Struct {
name_off: n_q1,
size: 8,
members: vec![SynMember {
name_off: n_x,
type_id: 1,
byte_offset: 0,
}],
},
SynType::Struct {
name_off: n_q2,
size: 8,
members: vec![SynMember {
name_off: n_x,
type_id: 1,
byte_offset: 0,
}],
},
];
(build_btf(&types, &strings), 2)
}
fn mk_insn(code: u8, dst: u8, src: u8, off: i16, imm: i32) -> BpfInsn {
BpfInsn::new(code, dst, src, off, imm)
}
fn ldx(size: u8, dst: u8, src: u8, off: i16) -> BpfInsn {
mk_insn(BPF_CLASS_LDX | size | BPF_MODE_MEM, dst, src, off, 0)
}
fn stx(size: u8, dst: u8, src: u8, off: i16) -> BpfInsn {
mk_insn(BPF_CLASS_STX | size | BPF_MODE_MEM, dst, src, off, 0)
}
fn mov_x(dst: u8, src: u8) -> BpfInsn {
mk_insn(BPF_CLASS_ALU64 | BPF_OP_MOV | BPF_SRC_X, dst, src, 0, 0)
}
fn mov_k(dst: u8, imm: i32) -> BpfInsn {
mk_insn(BPF_CLASS_ALU64 | BPF_OP_MOV, dst, 0, 0, imm)
}
fn call() -> BpfInsn {
mk_insn(BPF_CLASS_JMP | BPF_OP_CALL, 0, 0, 0, 1)
}
fn kfunc_call(kfunc_btf_id: u32) -> BpfInsn {
mk_insn(
BPF_CLASS_JMP | BPF_OP_CALL,
0,
BPF_PSEUDO_KFUNC_CALL,
0,
kfunc_btf_id as i32,
)
}
fn exit() -> BpfInsn {
mk_insn(BPF_CLASS_JMP | BPF_OP_EXIT, 0, 0, 0, 0)
}
fn addr_space_cast(dst: u8, src: u8, imm: i32) -> BpfInsn {
mk_insn(BPF_CLASS_ALU64 | BPF_OP_MOV | BPF_SRC_X, dst, src, 1, imm)
}
fn btf_kptr_base(slot_off: u32) -> (Vec<u8>, u32, u32, u32) {
let mut strings: Vec<u8> = vec![0];
let n_u64 = push_name(&mut strings, "u64");
let n_t = push_name(&mut strings, "T");
let n_p = push_name(&mut strings, "P");
let n_x = push_name(&mut strings, "x");
let n_slot = push_name(&mut strings, "slot");
let types = vec![
SynType::Int {
name_off: n_u64,
size: 8,
encoding: 0,
offset: 0,
bits: 64,
},
SynType::Struct {
name_off: n_t,
size: 8,
members: vec![SynMember {
name_off: n_x,
type_id: 1,
byte_offset: 0,
}],
},
SynType::Ptr { type_id: 2 },
SynType::Struct {
name_off: n_p,
size: slot_off + 8,
members: vec![SynMember {
name_off: n_slot,
type_id: 1,
byte_offset: slot_off,
}],
},
];
let blob = build_btf(&types, &strings);
(blob, 2, 4, 3)
}
fn ld_imm64(dst: u8, imm: i32) -> [BpfInsn; 2] {
let lo = mk_insn(BPF_CLASS_LD | BPF_SIZE_DW | BPF_MODE_IMM, dst, 0, 0, imm);
let hi = mk_insn(0, 0, 0, 0, 0);
[lo, hi]
}
mod atomic_stack;
mod bss_jumps_funcentry;
mod btf_stack_kfunc_edge;
mod cast_tracking;
mod conflict_oob_finalize;
mod frameaddr_kfunc_stx_edge;
mod helper_map_crossfn;
mod kptr_addrspace;
mod register_alu_cast_misc;
mod stress;
mod stx_flow;