use super::*;
use goblin::elf::header as h;
use goblin::elf::section_header as sh;
use std::io::Write;
struct SecSpec {
name: &'static str,
sh_type: u32,
sh_flags: u64,
sh_addr: u64,
data: Vec<u8>,
sh_link: u32,
sh_info: u32,
sh_entsize: u64,
}
impl SecSpec {
fn new(name: &'static str, sh_type: u32) -> Self {
Self {
name,
sh_type,
sh_flags: 0,
sh_addr: 0,
data: Vec::new(),
sh_link: 0,
sh_info: 0,
sh_entsize: 0,
}
}
fn flags(mut self, f: u64) -> Self {
self.sh_flags = f;
self
}
fn data(mut self, d: Vec<u8>) -> Self {
self.data = d;
self
}
fn link(mut self, l: u32) -> Self {
self.sh_link = l;
self
}
fn info(mut self, i: u32) -> Self {
self.sh_info = i;
self
}
fn entsize(mut self, e: u64) -> Self {
self.sh_entsize = e;
self
}
}
fn build_elf64(sections: Vec<SecSpec>, e_machine: u16, e_type: u16) -> Vec<u8> {
let mut shstrtab: Vec<u8> = vec![0u8]; let null_name_off = 0u32;
let mut sec_name_offs: Vec<u32> = Vec::new();
for s in §ions {
sec_name_offs.push(shstrtab.len() as u32);
shstrtab.extend_from_slice(s.name.as_bytes());
shstrtab.push(0);
}
let shstrtab_self_name_off = shstrtab.len() as u32;
shstrtab.extend_from_slice(b".shstrtab");
shstrtab.push(0);
let ehdr_size: usize = 64;
let shdr_size: usize = 64;
let mut data_blob: Vec<u8> = Vec::new();
let mut sec_file_off: Vec<u64> = Vec::new();
sec_file_off.push(0);
let mut cursor: u64 = ehdr_size as u64;
for s in §ions {
sec_file_off.push(cursor);
data_blob.extend_from_slice(&s.data);
cursor += s.data.len() as u64;
}
let shstrtab_file_off = cursor;
data_blob.extend_from_slice(&shstrtab);
cursor += shstrtab.len() as u64;
let shoff = cursor;
let shnum = (1 + sections.len() + 1) as u16;
let shstrndx = (1 + sections.len()) as u16;
let mut blob: Vec<u8> = Vec::with_capacity(ehdr_size);
blob.extend_from_slice(h::ELFMAG); blob.push(h::ELFCLASS64); blob.push(h::ELFDATA2LSB); blob.push(h::EV_CURRENT); blob.push(0); blob.push(0); blob.extend_from_slice(&[0u8; 7]);
blob.extend_from_slice(&e_type.to_le_bytes());
blob.extend_from_slice(&e_machine.to_le_bytes());
blob.extend_from_slice(&1u32.to_le_bytes()); blob.extend_from_slice(&0u64.to_le_bytes()); blob.extend_from_slice(&0u64.to_le_bytes()); blob.extend_from_slice(&shoff.to_le_bytes()); blob.extend_from_slice(&0u32.to_le_bytes()); blob.extend_from_slice(&(ehdr_size as u16).to_le_bytes()); blob.extend_from_slice(&0u16.to_le_bytes()); blob.extend_from_slice(&0u16.to_le_bytes()); blob.extend_from_slice(&(shdr_size as u16).to_le_bytes()); blob.extend_from_slice(&shnum.to_le_bytes()); blob.extend_from_slice(&shstrndx.to_le_bytes());
blob.extend_from_slice(&data_blob);
let mut write_shdr = |sh_name: u32,
sh_type: u32,
sh_flags: u64,
sh_addr: u64,
sh_offset: u64,
sh_size: u64,
sh_link: u32,
sh_info: u32,
sh_addralign: u64,
sh_entsize: u64| {
blob.write_all(&sh_name.to_le_bytes()).unwrap();
blob.write_all(&sh_type.to_le_bytes()).unwrap();
blob.write_all(&sh_flags.to_le_bytes()).unwrap();
blob.write_all(&sh_addr.to_le_bytes()).unwrap();
blob.write_all(&sh_offset.to_le_bytes()).unwrap();
blob.write_all(&sh_size.to_le_bytes()).unwrap();
blob.write_all(&sh_link.to_le_bytes()).unwrap();
blob.write_all(&sh_info.to_le_bytes()).unwrap();
blob.write_all(&sh_addralign.to_le_bytes()).unwrap();
blob.write_all(&sh_entsize.to_le_bytes()).unwrap();
};
write_shdr(null_name_off, sh::SHT_NULL, 0, 0, 0, 0, 0, 0, 0, 0);
for (i, s) in sections.iter().enumerate() {
write_shdr(
sec_name_offs[i],
s.sh_type,
s.sh_flags,
s.sh_addr,
sec_file_off[i + 1],
s.data.len() as u64,
s.sh_link,
s.sh_info,
1,
s.sh_entsize,
);
}
write_shdr(
shstrtab_self_name_off,
sh::SHT_STRTAB,
0,
0,
shstrtab_file_off,
shstrtab.len() as u64,
0,
0,
1,
0,
);
blob
}
fn elf64_sym(st_name: u32, st_info: u8, st_shndx: u16, st_value: u64, st_size: u64) -> [u8; 24] {
let mut out = [0u8; 24];
out[0..4].copy_from_slice(&st_name.to_le_bytes());
out[4] = st_info;
out[5] = 0; out[6..8].copy_from_slice(&st_shndx.to_le_bytes());
out[8..16].copy_from_slice(&st_value.to_le_bytes());
out[16..24].copy_from_slice(&st_size.to_le_bytes());
out
}
fn st_info(bind: u8, ty: u8) -> u8 {
(bind << 4) | (ty & 0x0f)
}
fn build_btf_blob(types: &[u8], strings: &[u8]) -> Vec<u8> {
let type_len = types.len() as u32;
let str_len = strings.len() as u32;
let mut blob = Vec::new();
blob.write_all(&0xEB9F_u16.to_le_bytes()).unwrap(); blob.push(1); blob.push(0); blob.write_all(&24u32.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(types);
blob.extend_from_slice(strings);
blob
}
fn insn_to_bytes(i: BpfInsn) -> [u8; 8] {
let regs_byte = (i.dst_reg() & 0x0f) | ((i.src_reg() & 0x0f) << 4);
let mut buf = [0u8; 8];
buf[0] = i.code;
buf[1] = regs_byte;
buf[2..4].copy_from_slice(&i.off.to_le_bytes());
buf[4..8].copy_from_slice(&i.imm.to_le_bytes());
buf
}
fn insns_to_text_bytes(insns: &[BpfInsn]) -> Vec<u8> {
let mut out = Vec::with_capacity(insns.len() * 8);
for ins in insns {
out.extend_from_slice(&insn_to_bytes(*ins));
}
out
}
const OP_LDX_DW_MEM: u8 = 0x01 | 0x18 | 0x60; const OP_JMP_EXIT: u8 = 0x05 | 0x90;
fn ldx_dw_mem(dst: u8, src: u8, off: i16) -> BpfInsn {
BpfInsn::new(OP_LDX_DW_MEM, dst, src, off, 0)
}
fn exit_insn() -> BpfInsn {
BpfInsn::new(OP_JMP_EXIT, 0, 0, 0, 0)
}
fn addr_space_cast_insn(dst: u8, src: u8) -> BpfInsn {
use libbpf_rs::libbpf_sys as bs;
let code = (bs::BPF_ALU64 | bs::BPF_MOV | bs::BPF_X) as u8;
BpfInsn::new(code, dst, src, 1, 1)
}
const SYN_BTF_KIND_INT: u32 = 1;
const SYN_BTF_KIND_PTR: u32 = 2;
const SYN_BTF_KIND_STRUCT: u32 = 4;
const SYN_BTF_KIND_FWD: u32 = 7;
const SYN_BTF_KIND_FUNC: u32 = 12;
const SYN_BTF_KIND_FUNC_PROTO: u32 = 13;
fn push_btf_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
}
#[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,
}
enum SynKind {
Int {
name_off: u32,
size: u32,
encoding: u32,
offset: u32,
bits: u32,
},
Ptr {
type_id: u32,
},
Struct {
name_off: u32,
size: u32,
members: Vec<SynMember>,
},
Fwd {
name_off: u32,
kind_flag: u32,
},
Func {
name_off: u32,
type_id: u32,
linkage: u32,
},
FuncProto {
return_type_id: u32,
params: Vec<SynParam>,
},
}
fn build_btf_full(types: &[SynKind], strings: &[u8]) -> Vec<u8> {
let mut type_section = Vec::new();
for ty in types {
match ty {
SynKind::Int {
name_off,
size,
encoding,
offset,
bits,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = (SYN_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());
}
SynKind::Ptr { type_id } => {
type_section.extend_from_slice(&0u32.to_le_bytes());
let info = (SYN_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());
}
SynKind::Struct {
name_off,
size,
members,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let vlen = members.len() as u32;
let info = ((SYN_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());
}
}
SynKind::Fwd {
name_off,
kind_flag,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = ((SYN_BTF_KIND_FWD << 24) & 0x1f00_0000) | ((*kind_flag & 1) << 31);
type_section.extend_from_slice(&info.to_le_bytes());
type_section.extend_from_slice(&0u32.to_le_bytes());
}
SynKind::Func {
name_off,
type_id,
linkage,
} => {
type_section.extend_from_slice(&name_off.to_le_bytes());
let info = ((SYN_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());
}
SynKind::FuncProto {
return_type_id,
params,
} => {
type_section.extend_from_slice(&0u32.to_le_bytes());
let vlen = params.len() as u32;
let info = ((SYN_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());
}
}
}
}
let type_len = type_section.len() as u32;
let str_len = strings.len() as u32;
let mut blob = Vec::new();
blob.write_all(&0xEB9F_u16.to_le_bytes()).unwrap();
blob.push(1); blob.push(0); blob.write_all(&24u32.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 build_btf_ext(section_name_off: u32, records: &[(u32, u32)], record_size: u32) -> Vec<u8> {
let header_len = 24u32;
let info_len = 4 + 4 + 4 + records.len() as u32 * record_size;
let mut info = Vec::new();
info.extend_from_slice(&record_size.to_le_bytes());
info.extend_from_slice(§ion_name_off.to_le_bytes());
info.extend_from_slice(&(records.len() as u32).to_le_bytes());
for (insn_off, type_id) in records {
info.extend_from_slice(&insn_off.to_le_bytes());
info.extend_from_slice(&type_id.to_le_bytes());
let pad = record_size.saturating_sub(8) as usize;
info.extend(std::iter::repeat_n(0, pad));
}
let mut out = Vec::new();
out.extend_from_slice(&0xEB9F_u16.to_le_bytes());
out.push(1);
out.push(0);
out.extend_from_slice(&header_len.to_le_bytes());
out.extend_from_slice(&0u32.to_le_bytes()); out.extend_from_slice(&info_len.to_le_bytes());
out.extend_from_slice(&info_len.to_le_bytes()); out.extend_from_slice(&0u32.to_le_bytes()); out.extend_from_slice(&info);
out
}
fn build_full_bpf_object_elf(text: Vec<u8>, btf: Vec<u8>, btf_ext: Vec<u8>) -> Vec<u8> {
build_elf64(
vec![
SecSpec::new(".text", sh::SHT_PROGBITS)
.flags(sh::SHF_EXECINSTR.into())
.data(text),
SecSpec::new(".BTF", sh::SHT_PROGBITS).data(btf),
SecSpec::new(".BTF.ext", sh::SHT_PROGBITS).data(btf_ext),
],
h::EM_BPF,
h::ET_REL,
)
}
fn build_recovers_arena_cast_outer_elf() -> Vec<u8> {
let mut strings = vec![0u8];
let n_int = push_btf_name(&mut strings, "u64");
let n_t = push_btf_name(&mut strings, "T");
let n_q = push_btf_name(&mut strings, "Q");
let n_f = push_btf_name(&mut strings, "f");
let n_x = push_btf_name(&mut strings, "x");
let n_func = push_btf_name(&mut strings, "myfunc");
let n_text = push_btf_name(&mut strings, ".text");
let types = vec![
SynKind::Int {
name_off: n_int,
size: 8,
encoding: 0,
offset: 0,
bits: 64,
},
SynKind::Struct {
name_off: n_t,
size: 16,
members: vec![SynMember {
name_off: n_f,
type_id: 1,
byte_offset: 8,
}],
},
SynKind::Struct {
name_off: n_q,
size: 8,
members: vec![SynMember {
name_off: n_x,
type_id: 1,
byte_offset: 0,
}],
},
SynKind::Ptr { type_id: 2 },
SynKind::FuncProto {
return_type_id: 0,
params: vec![SynParam {
name_off: 0,
type_id: 4,
}],
},
SynKind::Func {
name_off: n_func,
type_id: 5,
linkage: 1,
},
];
let btf_blob = build_btf_full(&types, &strings);
let insns = vec![
ldx_dw_mem(2, 1, 8),
addr_space_cast_insn(2, 2),
ldx_dw_mem(3, 2, 0),
exit_insn(),
];
let text = insns_to_text_bytes(&insns);
let btf_ext = build_btf_ext(n_text, &[(0, 5)], 8);
let inner = build_full_bpf_object_elf(text, btf_blob, btf_ext);
build_elf64(
vec![SecSpec::new(".bpf.objs", sh::SHT_PROGBITS).data(inner)],
h::EM_X86_64,
h::ET_REL,
)
}
fn kfunc_btf_type_header(name_off: u32, kind: u32, vlen: u32, size_or_type: u32) -> [u8; 12] {
let info = ((kind << 24) & 0x1f00_0000) | (vlen & 0xffff);
let mut out = [0u8; 12];
out[0..4].copy_from_slice(&name_off.to_le_bytes());
out[4..8].copy_from_slice(&info.to_le_bytes());
out[8..12].copy_from_slice(&size_or_type.to_le_bytes());
out
}
fn build_kfunc_btf_blob(kf_name: &str) -> (Vec<u8>, u32, u32) {
let mut strings: Vec<u8> = vec![0];
let 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
};
let n_u64 = push_name(&mut strings, "u64");
let n_t = push_name(&mut strings, "T");
let n_x = push_name(&mut strings, "x");
let n_func = push_name(&mut strings, kf_name);
let mut types: Vec<u8> = Vec::new();
const BTF_KIND_INT: u32 = 1;
const BTF_KIND_PTR: u32 = 2;
const BTF_KIND_STRUCT: u32 = 4;
const BTF_KIND_FUNC: u32 = 12;
const BTF_KIND_FUNC_PROTO: u32 = 13;
const BTF_FUNC_EXTERN: u32 = 2;
types.extend_from_slice(&kfunc_btf_type_header(n_u64, BTF_KIND_INT, 0, 8));
let int_data: u32 = 64;
types.extend_from_slice(&int_data.to_le_bytes());
types.extend_from_slice(&kfunc_btf_type_header(n_t, BTF_KIND_STRUCT, 1, 8));
types.extend_from_slice(&n_x.to_le_bytes());
types.extend_from_slice(&1u32.to_le_bytes());
types.extend_from_slice(&0u32.to_le_bytes());
types.extend_from_slice(&kfunc_btf_type_header(0, BTF_KIND_PTR, 0, 2));
types.extend_from_slice(&kfunc_btf_type_header(0, BTF_KIND_FUNC_PROTO, 0, 3));
types.extend_from_slice(&kfunc_btf_type_header(
n_func,
BTF_KIND_FUNC,
BTF_FUNC_EXTERN,
4,
));
let mut blob: Vec<u8> = Vec::new();
blob.extend_from_slice(&0xEB9F_u16.to_le_bytes());
blob.push(1);
blob.push(0);
blob.extend_from_slice(&24u32.to_le_bytes());
blob.extend_from_slice(&0u32.to_le_bytes());
blob.extend_from_slice(&(types.len() as u32).to_le_bytes());
blob.extend_from_slice(&(types.len() as u32).to_le_bytes());
blob.extend_from_slice(&(strings.len() as u32).to_le_bytes());
blob.extend_from_slice(&types);
blob.extend_from_slice(&strings);
(blob, 5, 2)
}
fn elf64_rel(r_offset: u64, sym_idx: u64, r_type: u32) -> [u8; 16] {
let mut out = [0u8; 16];
out[0..8].copy_from_slice(&r_offset.to_le_bytes());
let r_info = (sym_idx << 32) | (r_type as u64);
out[8..16].copy_from_slice(&r_info.to_le_bytes());
out
}
fn pre_reloc_kfunc_call_bytes() -> [u8; 8] {
[0x85, 0x10, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]
}
fn kfunc_exit_bytes() -> [u8; 8] {
[0x95, 0, 0, 0, 0, 0, 0, 0]
}
fn pre_reloc_subprog_call_bytes() -> [u8; 8] {
[0x85, 0x10, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff]
}
fn subprog_nop_bytes() -> [u8; 8] {
[0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
}
fn pseudo_call_bytes(imm: i32) -> [u8; 8] {
let mut out = [0u8; 8];
out[0] = 0x85; out[1] = 0x10; out[2..4].copy_from_slice(&0i16.to_le_bytes());
out[4..8].copy_from_slice(&imm.to_le_bytes());
out
}
fn pseudo_kfunc_call_bytes(imm: i32) -> [u8; 8] {
let mut out = [0u8; 8];
out[0] = 0x85;
out[1] = 0x20; out[2..4].copy_from_slice(&0i16.to_le_bytes());
out[4..8].copy_from_slice(&imm.to_le_bytes());
out
}
#[allow(clippy::too_many_arguments)]
fn build_subprog_test_scaffold(
sym_name: &str,
sym_st_type_bind: u8,
sym_st_shndx: u16,
call_bytes: [u8; 8],
) -> (Vec<u8>, Vec<BpfInsn>, HashMap<u32, usize>) {
let mut strtab: Vec<u8> = vec![0];
let n_sym = strtab.len() as u32;
strtab.extend_from_slice(sym_name.as_bytes());
strtab.push(0);
let mut symtab: Vec<u8> = Vec::new();
symtab.extend_from_slice(&elf64_sym(0, 0, 0, 0, 0));
symtab.extend_from_slice(&elf64_sym(n_sym, sym_st_type_bind, sym_st_shndx, 0, 0));
let mut text: Vec<u8> = Vec::new();
text.extend_from_slice(&call_bytes);
text.extend_from_slice(&kfunc_exit_bytes());
let rel_data: Vec<u8> = elf64_rel(0, 1, 1).to_vec();
let blob = build_elf64(
vec![
SecSpec::new(".text", sh::SHT_PROGBITS)
.flags(sh::SHF_EXECINSTR.into())
.data(text),
SecSpec::new(".strtab", sh::SHT_STRTAB).data(strtab),
SecSpec::new(".symtab", sh::SHT_SYMTAB)
.data(symtab)
.link(2)
.entsize(24),
SecSpec::new(".rel.text", sh::SHT_REL)
.data(rel_data)
.link(3)
.info(1)
.entsize(16),
],
h::EM_BPF,
h::ET_REL,
);
let text_concat: Vec<BpfInsn> = vec![
BpfInsn::from_le_bytes(call_bytes),
BpfInsn::from_le_bytes(kfunc_exit_bytes()),
];
let mut section_bases: HashMap<u32, usize> = HashMap::new();
section_bases.insert(1, 0); (blob, text_concat, section_bases)
}
fn ld_imm64_first_slot_bytes(imm: i32) -> [u8; 8] {
let mut out = [0u8; 8];
out[0] = 0x18;
out[1] = 0; out[2..4].copy_from_slice(&0i16.to_le_bytes());
out[4..8].copy_from_slice(&imm.to_le_bytes());
out
}
fn ld_imm64_second_slot_bytes() -> [u8; 8] {
[0u8; 8]
}
fn append_btf_datasec(
types: &mut Vec<u8>,
name_off: u32,
section_size: u32,
vsi_entries: &[(u32, u32, u32)],
) {
const BTF_KIND_DATASEC: u32 = 15;
let vlen = vsi_entries.len() as u32;
let info = ((BTF_KIND_DATASEC << 24) & 0x1f00_0000) | (vlen & 0xffff);
types.extend_from_slice(&name_off.to_le_bytes());
types.extend_from_slice(&info.to_le_bytes());
types.extend_from_slice(§ion_size.to_le_bytes());
for (type_id, offset, size) in vsi_entries {
types.extend_from_slice(&type_id.to_le_bytes());
types.extend_from_slice(&offset.to_le_bytes());
types.extend_from_slice(&size.to_le_bytes());
}
}
fn build_datasec_btf_blob(sec_name: &str) -> (Vec<u8>, u32) {
let mut strings: Vec<u8> = vec![0];
let n_u64 = strings.len() as u32;
strings.extend_from_slice(b"u64");
strings.push(0);
let n_sec = strings.len() as u32;
strings.extend_from_slice(sec_name.as_bytes());
strings.push(0);
let mut types: Vec<u8> = Vec::new();
types.extend_from_slice(&kfunc_btf_type_header(n_u64, 1, 0, 8));
let int_data: u32 = 64;
types.extend_from_slice(&int_data.to_le_bytes());
append_btf_datasec(&mut types, n_sec, 32, &[]);
let mut blob: Vec<u8> = Vec::new();
blob.extend_from_slice(&0xEB9F_u16.to_le_bytes());
blob.push(1);
blob.push(0);
blob.extend_from_slice(&24u32.to_le_bytes());
blob.extend_from_slice(&0u32.to_le_bytes());
blob.extend_from_slice(&(types.len() as u32).to_le_bytes());
blob.extend_from_slice(&(types.len() as u32).to_le_bytes());
blob.extend_from_slice(&(strings.len() as u32).to_le_bytes());
blob.extend_from_slice(&types);
blob.extend_from_slice(&strings);
(blob, 2)
}
#[allow(clippy::too_many_arguments)]
fn build_datasec_test_scaffold(
bss_name: &'static str,
sec_name_in_btf: &str,
r_type: u32,
r_offset: u64,
sym_st_value: u64,
sym_st_shndx: u16,
sym_st_type_bind: u8,
imm_value: i32,
) -> (Vec<u8>, Vec<u8>, Vec<BpfInsn>, HashMap<u32, usize>) {
let (btf_blob, _ds_id) = build_datasec_btf_blob(sec_name_in_btf);
let mut strtab: Vec<u8> = vec![0];
let n_sym = strtab.len() as u32;
strtab.extend_from_slice(b"global_var");
strtab.push(0);
let mut symtab: Vec<u8> = Vec::new();
symtab.extend_from_slice(&elf64_sym(0, 0, 0, 0, 0));
symtab.extend_from_slice(&elf64_sym(
n_sym,
sym_st_type_bind,
sym_st_shndx,
sym_st_value,
0,
));
let mut text: Vec<u8> = Vec::new();
text.extend_from_slice(&ld_imm64_first_slot_bytes(imm_value));
text.extend_from_slice(&ld_imm64_second_slot_bytes());
text.extend_from_slice(&kfunc_exit_bytes());
let rel_data: Vec<u8> = elf64_rel(r_offset, 1, r_type).to_vec();
let blob = build_elf64(
vec![
SecSpec::new(bss_name, sh::SHT_PROGBITS).data(vec![0u8; 32]),
SecSpec::new(".text", sh::SHT_PROGBITS)
.flags(sh::SHF_EXECINSTR.into())
.data(text),
SecSpec::new(".strtab", sh::SHT_STRTAB).data(strtab),
SecSpec::new(".symtab", sh::SHT_SYMTAB)
.data(symtab)
.link(3)
.entsize(24),
SecSpec::new(".rel.text", sh::SHT_REL)
.data(rel_data)
.link(4)
.info(2) .entsize(16),
SecSpec::new(".BTF", sh::SHT_PROGBITS).data(btf_blob.clone()),
],
h::EM_BPF,
h::ET_REL,
);
let text_concat: Vec<BpfInsn> = vec![
BpfInsn::from_le_bytes(ld_imm64_first_slot_bytes(imm_value)),
BpfInsn::from_le_bytes(ld_imm64_second_slot_bytes()),
BpfInsn::from_le_bytes(kfunc_exit_bytes()),
];
let mut section_bases: HashMap<u32, usize> = HashMap::new();
section_bases.insert(2, 0);
(blob, btf_blob, text_concat, section_bases)
}
const MOV_R1_CODE: u8 = super::BPF_MOV64_IMM_CODE;
fn call_insn() -> BpfInsn {
BpfInsn::new(
super::cast_analysis_load_consts::BPF_JMP_CALL_CODE,
0,
0,
0,
0,
)
}
mod index;
mod parse;
mod patch;