Skip to content

Commit

Permalink
Some control flow operations were not tested before. (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lichtso authored Dec 19, 2024
1 parent 75d5bc8 commit 995c78f
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 47 deletions.
17 changes: 7 additions & 10 deletions src/disassembler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,19 +267,16 @@ pub fn disassemble_instruction<C: ContextObject>(
ebpf::JSLE_REG => { name = "jsle"; desc = jmp_reg_str(name, insn, cfg_nodes); },
ebpf::CALL_IMM => {
let key = sbpf_version.calculate_call_imm_target_pc(pc, insn.imm);
let function_name = function_registry.lookup_by_key(key).map(|(function_name, _)| String::from_utf8_lossy(function_name).to_string());
let function_name = if let Some(function_name) = function_name {
name = "call";
function_name
} else {
let mut name = "call";
let mut function_name = function_registry.lookup_by_key(key).map(|(function_name, _)| String::from_utf8_lossy(function_name).to_string());
if !sbpf_version.static_syscalls() && function_name.is_none() {
name = "syscall";
loader.get_function_registry(sbpf_version).lookup_by_key(insn.imm as u32).map(|(function_name, _)| String::from_utf8_lossy(function_name).to_string()).unwrap_or_else(|| "[invalid]".to_string())
};
desc = format!("{name} {function_name}");
function_name = loader.get_function_registry(sbpf_version).lookup_by_key(insn.imm as u32).map(|(function_name, _)| String::from_utf8_lossy(function_name).to_string());
}
desc = format!("{} {}", name, function_name.unwrap_or_else(|| "[invalid]".to_string()));
},
ebpf::CALL_REG => { name = "callx"; desc = format!("{} r{}", name, if sbpf_version.callx_uses_src_reg() { insn.src } else { insn.imm as u8 }); },
ebpf::EXIT
| ebpf::RETURN if !sbpf_version.static_syscalls() => { name = "exit"; desc = name.to_string(); },
ebpf::EXIT if !sbpf_version.static_syscalls() => { name = "exit"; desc = name.to_string(); },
ebpf::RETURN if sbpf_version.static_syscalls() => { name = "return"; desc = name.to_string(); },
ebpf::SYSCALL if sbpf_version.static_syscalls() => { desc = format!("syscall {}", insn.imm); },

Expand Down
61 changes: 40 additions & 21 deletions src/jit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1719,12 +1719,14 @@ impl<'a, C: ContextObject> JitCompiler<'a, C> {
mod tests {
use super::*;
use crate::{
disassembler::disassemble_instruction,
program::{BuiltinProgram, FunctionRegistry, SBPFVersion},
static_analysis::CfgNode,
syscalls,
vm::TestContextObject,
};
use byteorder::{ByteOrder, LittleEndian};
use std::sync::Arc;
use std::{collections::BTreeMap, sync::Arc};

#[test]
fn test_runtime_environment_slots() {
Expand Down Expand Up @@ -1838,35 +1840,45 @@ mod tests {
<= MACHINE_CODE_PER_INSTRUCTION_METER_CHECKPOINT
);

let mut cfg_nodes = BTreeMap::new();
cfg_nodes.insert(
8,
CfgNode {
label: std::string::String::from("label"),
..CfgNode::default()
},
);

for sbpf_version in [SBPFVersion::V0, SBPFVersion::V3] {
println!("opcode;machine_code_length_per_instruction;assembly");
let empty_program_machine_code_length =
empty_program_machine_code_length_per_version[sbpf_version as usize];

for mut opcode in 0x00..=0xFF {
let (registers, immediate) = match opcode {
0x85 | 0x8D => (0x88, 8),
0x86 => {
0x85 if !sbpf_version.static_syscalls() => (0x00, Some(8)),
0x85 if sbpf_version.static_syscalls() => (0x00, None),
0x8D => (0x88, Some(0)),
0x95 if sbpf_version.static_syscalls() => (0x00, Some(1)),
0xE5 if !sbpf_version.static_syscalls() => {
// Put external function calls on a separate loop iteration
opcode = 0x85;
(0x00, 0x91020CDD)
(0x00, Some(0x91020CDD))
}
0x87 => {
0xF5 => {
// Put invalid function calls on a separate loop iteration
opcode = 0x85;
(0x88, 0x91020CDD)
(0x00, Some(0x91020CD0))
}
0x95 => {
// Put a valid syscall
(0, 1)
}
0xD4 | 0xDC => (0x88, 16),
_ => (0x88, 0xFFFFFFFF),
0xD4 | 0xDC => (0x88, Some(16)),
_ => (0x88, Some(0x11223344)),
};
for pc in 0..INSTRUCTION_COUNT {
prog[pc * ebpf::INSN_SIZE] = opcode;
prog[pc * ebpf::INSN_SIZE + 1] = registers;
prog[pc * ebpf::INSN_SIZE + 2] = 0xFF;
prog[pc * ebpf::INSN_SIZE + 3] = 0xFF;
let offset = 7_u16.wrapping_sub(pc as u16);
LittleEndian::write_u16(&mut prog[pc * ebpf::INSN_SIZE + 2..], offset);
let immediate = immediate.unwrap_or_else(|| 7_u32.wrapping_sub(pc as u32));
LittleEndian::write_u32(&mut prog[pc * ebpf::INSN_SIZE + 4..], immediate);
}
let config = Config {
Expand Down Expand Up @@ -1897,15 +1909,22 @@ mod tests {
let machine_code_length_per_instruction =
machine_code_length as f64 / instruction_count as f64;
assert!(
(machine_code_length_per_instruction + 0.5) as usize
f64::ceil(machine_code_length_per_instruction) as usize
<= MAX_MACHINE_CODE_LENGTH_PER_INSTRUCTION
);
/*println!("opcode={:02X} machine_code_length_per_instruction={}", opcode, machine_code_length_per_instruction);
let analysis = crate::static_analysis::Analysis::from_executable(&executable).unwrap();
{
let stdout = std::io::stdout();
analysis.disassemble(&mut stdout.lock()).unwrap();
}*/
let insn = ebpf::get_insn_unchecked(&prog, 0);
let assembly = disassemble_instruction(
&insn,
0,
&cfg_nodes,
executable.get_function_registry(),
executable.get_loader(),
executable.get_sbpf_version(),
);
println!(
"{:02X};{:>7.3};{}",
opcode, machine_code_length_per_instruction, assembly
);
}
}
}
Expand Down
25 changes: 9 additions & 16 deletions src/static_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,24 +230,13 @@ impl<'a> Analysis<'a> {
self.cfg_nodes.entry(*pc).or_default();
}
let mut cfg_edges = BTreeMap::new();
for insn in self.instructions.iter() {
for (pc, insn) in self.instructions.iter().enumerate() {
let target_pc = (insn.ptr as isize + insn.off as isize + 1) as usize;
match insn.opc {
ebpf::CALL_IMM => {
if let Some((function_name, _function)) = self
.executable
.get_loader()
.get_function_registry(sbpf_version)
.lookup_by_key(insn.imm as u32)
{
if function_name == b"abort" {
self.cfg_nodes.entry(insn.ptr + 1).or_default();
cfg_edges.insert(insn.ptr, (insn.opc, Vec::new()));
}
} else if let Some((_function_name, target_pc)) = self
.executable
.get_function_registry()
.lookup_by_key(insn.imm as u32)
let key = sbpf_version.calculate_call_imm_target_pc(pc, insn.imm);
if let Some((_function_name, target_pc)) =
self.executable.get_function_registry().lookup_by_key(key)
{
self.cfg_nodes.entry(insn.ptr + 1).or_default();
self.cfg_nodes.entry(target_pc).or_default();
Expand All @@ -269,7 +258,11 @@ impl<'a> Analysis<'a> {
};
cfg_edges.insert(insn.ptr, (insn.opc, destinations));
}
ebpf::EXIT => {
ebpf::EXIT if !sbpf_version.static_syscalls() => {
self.cfg_nodes.entry(insn.ptr + 1).or_default();
cfg_edges.insert(insn.ptr, (insn.opc, Vec::new()));
}
ebpf::RETURN if sbpf_version.static_syscalls() => {
self.cfg_nodes.entry(insn.ptr + 1).or_default();
cfg_edges.insert(insn.ptr, (insn.opc, Vec::new()));
}
Expand Down

0 comments on commit 995c78f

Please sign in to comment.