use alloc::{vec, vec::Vec};
use crate::{
BpfResult as Result, KernelAuxiliaryOps,
linux_bpf::{BPF_PSEUDO_MAP_FD, BPF_PSEUDO_MAP_VALUE},
};
pub struct EbpfPreProcessor {
new_insn: Vec<u8>,
raw_file_ptr: Vec<usize>,
}
pub trait EbpfInst: Clone {
fn opc(&self) -> u8;
fn imm(&self) -> i32;
fn src(&self) -> u8;
fn set_imm(&mut self, imm: i32);
fn to_array(&self) -> [u8; 8];
}
const LD_DW_IMM: u8 = 0x18;
impl EbpfPreProcessor {
pub fn preprocess<F: KernelAuxiliaryOps>(mut instructions: Vec<u8>) -> Result<Self> {
let mut fmt_insn = F::translate_instruction(instructions.clone())?;
let mut index = 0;
let mut raw_file_ptr = vec![];
loop {
if index >= fmt_insn.len() {
break;
}
let mut insn = fmt_insn[index].clone();
if insn.opc() == LD_DW_IMM {
let mut next_insn = fmt_insn[index + 1].clone();
let map_fd = insn.imm() as usize;
let src_reg = insn.src();
let ptr = match src_reg as u32 {
BPF_PSEUDO_MAP_VALUE => {
let value_ptr = F::get_unified_map_from_fd(map_fd as u32, |unified_map| {
unified_map.map().map_values_ptr_range()
})?;
let offset = next_insn.imm() as usize;
log::trace!(
"Relocate for BPF_PSEUDO_MAP_VALUE, instruction index: {}, map_fd: {}, ptr: {:#x}, offset: {}",
index,
map_fd,
value_ptr.start,
offset
);
Some(value_ptr.start + offset)
}
BPF_PSEUDO_MAP_FD => {
let map_ptr = F::get_unified_map_ptr_from_fd(map_fd as u32)? as usize;
log::trace!(
"Relocate for BPF_PSEUDO_MAP_FD, instruction index: {}, map_fd: {}, ptr: {:#x}",
index,
map_fd,
map_ptr
);
raw_file_ptr.push(map_ptr);
Some(map_ptr)
}
ty => {
log::error!(
"relocation for ty: {} not implemented, instruction index: {}",
ty,
index
);
None
}
};
if let Some(ptr) = ptr {
insn.set_imm(ptr as i32);
next_insn.set_imm((ptr >> 32) as i32);
fmt_insn[index] = insn;
fmt_insn[index + 1] = next_insn;
index += 2;
} else {
index += 1;
}
} else {
index += 1;
}
}
let mut idx = 0;
for ins in fmt_insn {
let bytes = ins.to_array();
instructions[idx..idx + 8].copy_from_slice(&bytes);
idx += 8;
}
Ok(Self {
new_insn: instructions,
raw_file_ptr,
})
}
pub fn get_new_insn(&self) -> &Vec<u8> {
self.new_insn.as_ref()
}
pub fn get_raw_file_ptr(&self) -> &Vec<usize> {
self.raw_file_ptr.as_ref()
}
}