DragonOS/kernel/crates/rbpf/tests/disassembler.rs
linfeng fae6e9ade4
feat(ebpf):[WIP] add eBPF support (#948)
* feat(kprobe): Add basic kprobe support for x86_64

* feat: add ebpf support (#912)

- 实现bpf()一部分命令,包括几种基本map,相关的helper函数
- 实现部分perf相关的数据结构
- 暂时为文件实现简单mmap
- 实现一个使用kprobe统计syscall 调用次数的ebpf程序

对eBPF支持程度(基本):

- 简单的eBPF程序(没有指定特殊的Map)
- 使用内核已经实现的Map的eBPF程序
- 可以和kprobe配合使用
- 内核Map相关的接口定义已经实现,添加新的Map较为简单

不支持的功能:
- 区分不同的eBPF程序类型(Network/Cgroup)并限定可调用的helper函数集
- 与内核其它跟踪机制配合(tracepoint)
- 其它helper和Map


todo

- [ ]  修改mmap,需要讨论,因为这个和块缓存层相关
- [x]  添加文档
- [x]  修复可能的错误
- [x] 增加rbpf版本信息

* feat: add /sys/devices/system/cpu/possible file

* feat: add /sys/devices/system/cpu/online
2024-10-25 15:59:57 +08:00

378 lines
6.8 KiB
Rust

// SPDX-License-Identifier: (Apache-2.0 OR MIT)
// Copyright 2017 Jan-Erik Rediger <badboy@archlinux.us>
//
// Adopted from tests in `tests/assembler.rs`
extern crate rbpf;
mod common;
use rbpf::{assembler::assemble, disassembler::to_insn_vec};
// Using a macro to keep actual line numbers in failure output
macro_rules! disasm {
($src:expr) => {{
let src = $src;
let asm = assemble(src).expect("Can't assemble from string");
let insn = to_insn_vec(&asm);
let reasm = insn
.into_iter()
.map(|ins| ins.desc)
.collect::<Vec<_>>()
.join("\n");
assert_eq!(src, reasm);
}};
}
#[test]
fn test_empty() {
disasm!("");
}
// Example for InstructionType::NoOperand.
#[test]
fn test_exit() {
disasm!("exit");
}
// Example for InstructionType::AluBinary.
#[test]
fn test_add64() {
disasm!("add64 r1, r3");
disasm!("add64 r1, 0x5");
}
// Example for InstructionType::AluUnary.
#[test]
fn test_neg64() {
disasm!("neg64 r1");
}
// Example for InstructionType::LoadReg.
#[test]
fn test_ldxw() {
disasm!("ldxw r1, [r2+0x5]");
}
// Example for InstructionType::StoreImm.
#[test]
fn test_stw() {
disasm!("stw [r2+0x5], 0x7");
}
// Example for InstructionType::StoreReg.
#[test]
fn test_stxw() {
disasm!("stxw [r2+0x5], r8");
}
// Example for InstructionType::JumpUnconditional.
#[test]
fn test_ja() {
disasm!("ja +0x8");
}
// Example for InstructionType::JumpConditional.
#[test]
fn test_jeq() {
disasm!("jeq r1, 0x4, +0x8");
disasm!("jeq r1, r3, +0x8");
}
// Example for InstructionType::Call.
#[test]
fn test_call() {
disasm!("call 0x3");
}
// Example for InstructionType::Endian.
#[test]
fn test_be32() {
disasm!("be32 r1");
}
// Example for InstructionType::LoadImm.
#[test]
fn test_lddw() {
disasm!("lddw r1, 0x1234abcd5678eeff");
disasm!("lddw r1, 0xff11ee22dd33cc44");
}
// Example for InstructionType::LoadAbs.
#[test]
fn test_ldabsw() {
disasm!("ldabsw 0x1");
}
// Example for InstructionType::LoadInd.
#[test]
fn test_ldindw() {
disasm!("ldindw r1, 0x2");
}
// Example for InstructionType::LoadReg.
#[test]
fn test_ldxdw() {
disasm!("ldxdw r1, [r2+0x3]");
}
// Example for InstructionType::StoreImm.
#[test]
fn test_sth() {
disasm!("sth [r1+0x2], 0x3");
}
// Example for InstructionType::StoreReg.
#[test]
fn test_stxh() {
disasm!("stxh [r1+0x2], r3");
}
// Test all supported AluBinary mnemonics.
#[test]
fn test_alu_binary() {
disasm!(
"add64 r1, r2
sub64 r1, r2
mul64 r1, r2
div64 r1, r2
or64 r1, r2
and64 r1, r2
lsh64 r1, r2
rsh64 r1, r2
mod64 r1, r2
xor64 r1, r2
mov64 r1, r2
arsh64 r1, r2"
);
disasm!(
"add64 r1, 0x2
sub64 r1, 0x2
mul64 r1, 0x2
div64 r1, 0x2
or64 r1, 0x2
and64 r1, 0x2
lsh64 r1, 0x2
rsh64 r1, 0x2
mod64 r1, 0x2
xor64 r1, 0x2
mov64 r1, 0x2
arsh64 r1, 0x2"
);
disasm!(
"add32 r1, r2
sub32 r1, r2
mul32 r1, r2
div32 r1, r2
or32 r1, r2
and32 r1, r2
lsh32 r1, r2
rsh32 r1, r2
mod32 r1, r2
xor32 r1, r2
mov32 r1, r2
arsh32 r1, r2"
);
disasm!(
"add32 r1, 0x2
sub32 r1, 0x2
mul32 r1, 0x2
div32 r1, 0x2
or32 r1, 0x2
and32 r1, 0x2
lsh32 r1, 0x2
rsh32 r1, 0x2
mod32 r1, 0x2
xor32 r1, 0x2
mov32 r1, 0x2
arsh32 r1, 0x2"
);
}
// Test all supported AluUnary mnemonics.
#[test]
fn test_alu_unary() {
disasm!(
"neg64 r1
neg32 r1"
);
}
// Test all supported LoadAbs mnemonics.
#[test]
fn test_load_abs() {
disasm!(
"ldabsw 0x1
ldabsh 0x1
ldabsb 0x1
ldabsdw 0x1"
);
}
// Test all supported LoadInd mnemonics.
#[test]
fn test_load_ind() {
disasm!(
"ldindw r1, 0x2
ldindh r1, 0x2
ldindb r1, 0x2
ldinddw r1, 0x2"
);
}
// Test all supported LoadReg mnemonics.
#[test]
fn test_load_reg() {
disasm!(
r"ldxw r1, [r2+0x3]
ldxh r1, [r2+0x3]
ldxb r1, [r2+0x3]
ldxdw r1, [r2+0x3]"
);
}
// Test all supported StoreImm mnemonics.
#[test]
fn test_store_imm() {
disasm!(
"stw [r1+0x2], 0x3
sth [r1+0x2], 0x3
stb [r1+0x2], 0x3
stdw [r1+0x2], 0x3"
);
}
// Test all supported StoreReg mnemonics.
#[test]
fn test_store_reg() {
disasm!(
"stxw [r1+0x2], r3
stxh [r1+0x2], r3
stxb [r1+0x2], r3
stxdw [r1+0x2], r3"
);
}
// Test all supported JumpConditional mnemonics.
#[test]
fn test_jump_conditional() {
disasm!(
"jeq r1, r2, +0x3
jgt r1, r2, +0x3
jge r1, r2, +0x3
jlt r1, r2, +0x3
jle r1, r2, +0x3
jset r1, r2, +0x3
jne r1, r2, +0x3
jsgt r1, r2, +0x3
jsge r1, r2, -0x3
jslt r1, r2, +0x3
jsle r1, r2, -0x3"
);
disasm!(
"jeq r1, 0x2, +0x3
jgt r1, 0x2, +0x3
jge r1, 0x2, +0x3
jlt r1, 0x2, +0x3
jle r1, 0x2, +0x3
jset r1, 0x2, +0x3
jne r1, 0x2, +0x3
jsgt r1, 0x2, +0x3
jsge r1, 0x2, -0x3
jslt r1, 0x2, +0x3
jsle r1, 0x2, -0x3"
);
disasm!(
"jeq32 r1, r2, +0x3
jgt32 r1, r2, +0x3
jge32 r1, r2, +0x3
jlt32 r1, r2, +0x3
jle32 r1, r2, +0x3
jset32 r1, r2, +0x3
jne32 r1, r2, +0x3
jsgt32 r1, r2, +0x3
jsge32 r1, r2, -0x3
jslt32 r1, r2, +0x3
jsle32 r1, r2, -0x3"
);
disasm!(
"jeq32 r1, 0x2, +0x3
jgt32 r1, 0x2, +0x3
jge32 r1, 0x2, +0x3
jlt32 r1, 0x2, +0x3
jle32 r1, 0x2, +0x3
jset32 r1, 0x2, +0x3
jne32 r1, 0x2, +0x3
jsgt32 r1, 0x2, +0x3
jsge32 r1, 0x2, -0x3
jslt32 r1, 0x2, +0x3
jsle32 r1, 0x2, -0x3"
);
}
// Test all supported Endian mnemonics.
#[test]
fn test_endian() {
disasm!(
"be16 r1
be32 r1
be64 r1
le16 r1
le32 r1
le64 r1"
);
}
#[test]
fn test_large_immediate() {
disasm!("add64 r1, 0x7fffffff");
disasm!("add64 r1, 0x7fffffff");
}
// Non-regression tests for overflow when trying to negate offset 0x8000i16.
#[test]
fn test_offset_overflow() {
let insns = [
0x62, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // stw
0x6a, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // sth
0x72, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // stb
0x7a, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // stdw
0x61, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxw
0x69, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxh
0x71, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxb
0x79, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxdw
0x15, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, // jeq (imm)
0x1d, 0x21, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // jeq (reg)
0x16, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, // jeq32 (imm)
0x1e, 0x21, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // jeq32 (reg)
];
let expected_output = "stw [r1-0x8000], 0x1
sth [r1-0x8000], 0x1
stb [r1-0x8000], 0x1
stdw [r1-0x8000], 0x1
ldxw r1, [r0-0x8000]
ldxh r1, [r0-0x8000]
ldxb r1, [r0-0x8000]
ldxdw r1, [r0-0x8000]
jeq r1, 0x2, -0x8000
jeq r1, r2, -0x8000
jeq32 r1, 0x2, -0x8000
jeq32 r1, r2, -0x8000";
let prog = to_insn_vec(&insns);
let asm = prog
.into_iter()
.map(|ins| ins.desc)
.collect::<Vec<_>>()
.join("\n");
assert_eq!(asm, expected_output);
}