Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
72e44fc
feat: init passes
linsyking Nov 25, 2024
8f08b2b
feat: jmp complexity pass
linsyking Nov 25, 2024
6f16fb8
feat: code compaction opt pass
linsyking Nov 25, 2024
60c3290
fix: probe read user should be a vd pass
linsyking Nov 25, 2024
eed55fc
feat: add test
linsyking Nov 26, 2024
cb504d4
Merge branch 'main' into dev
linsyking Nov 26, 2024
1585da4
feat: test code compaction
linsyking Nov 26, 2024
e51ff1d
feat: readlog
linsyking Nov 26, 2024
c36c694
fix: coalescing
linsyking Nov 26, 2024
2d11058
fix: compaction option
linsyking Nov 26, 2024
3bdeaa3
feat: eval
linsyking Nov 26, 2024
f486598
fix: change name to prog
linsyking Nov 26, 2024
1762c15
feat: eval opt
linsyking Nov 26, 2024
94af655
feat: eval
linsyking Nov 26, 2024
b229872
fix: reachable bb
linsyking Nov 28, 2024
346bb82
chore: insn counter name
linsyking Nov 28, 2024
29ab0a8
feat: printk log mode
linsyking Nov 28, 2024
12bdfd5
fix: remove redundant function
linsyking Nov 28, 2024
6afc3cd
fix: no need to clean the log
linsyking Nov 28, 2024
53a22d4
fix: load imm64 translate
linsyking Nov 29, 2024
50b0b70
feat: add tests
linsyking Nov 30, 2024
eb4570e
fix: test
linsyking Nov 30, 2024
57168f5
fix: use xdp
Nov 30, 2024
7553dbb
fix: decrease loop
linsyking Nov 30, 2024
662e74f
fix: to many iterations
linsyking Nov 30, 2024
e568e50
test: insn counter
linsyking Nov 30, 2024
9c9c615
feat: add tests
linsyking Nov 30, 2024
0c3fc5d
feat: eval
linsyking Nov 30, 2024
efce027
feat: eval
linsyking Dec 1, 2024
6eea5d6
feat: add tests
linsyking Dec 1, 2024
81ce23e
fix: msan2
linsyking Dec 1, 2024
5a8bb83
feat: eval
linsyking Dec 1, 2024
98c0d82
fix: eval
linsyking Dec 1, 2024
5ea5071
feat: add bpftrace programs
linsyking Dec 2, 2024
5dffbde
feat: count obj
linsyking Dec 2, 2024
840d689
feat: add kernel sample bpf
linsyking Dec 2, 2024
70b2015
feat: auto sec
linsyking Dec 2, 2024
ff4095d
feat: eval
linsyking Dec 2, 2024
ffa3fbd
feat: eval obj
linsyking Dec 3, 2024
d5d7df7
feat: add vi map
linsyking Dec 3, 2024
766bc33
fix: iter num check
linsyking Dec 3, 2024
9886e50
feat: eval
linsyking Dec 4, 2024
509d60f
feat: loadtime
linsyking Dec 4, 2024
b410ea9
feat: comp time 2
linsyking Dec 4, 2024
3a53fe1
feat: eval compile time 2
linsyking Dec 4, 2024
c2c5f91
feat: add programs to eval
linsyking Dec 5, 2024
6b64833
docs: instructions to build
linsyking Dec 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ add_library(epass STATIC
ir_bb.c
ir_insn.c
passes/phi_pass.c
passes/add_counter_pass.c
passes/insn_counter_pass.c
passes/translate_throw.c
passes/optimization.c
passes/cg_prepare.c
passes/code_compaction.c
passes/msan.c
passes/div_by_zero.c
passes/jmp_complexity.c
aux/prog_check.c
aux/disasm.c
aux/kern_utils.c
Expand Down
24 changes: 24 additions & 0 deletions core/Readme.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
# Build

If you are using normal kernel, inside this directory, run:

```
cmake -S . -B build -GNinja -DEPASS_LIBBPF=OFF
make
```

If you are running our custom kernel with custom libbpf, compile with:

```
cmake -S . -B build -GNinja -DEPASS_LIBBPF=ON
make
```

# Install

After building, run:

```
sudo cmake --install build
```

# Verifier

We design a form of constraint that could describe all types of ebpf verifier rules. The verifier will generate a "constraint set" based on static analysis information (e.g. BTF) and that doesn't need any simulation.
Expand Down
4 changes: 3 additions & 1 deletion core/aux/kern_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ static int apply_global_opt(struct bpf_ir_env *env, const char *opt)
env->opts.disable_prog_check = true;
} else if (strcmp(opt, "print_bpf_detail") == 0) {
env->opts.print_mode = BPF_IR_PRINT_BPF_DETAIL;
} else if (strcmp(opt, "printk_log") == 0) {
env->opts.enable_printk_log = true;
} else if (strcmp(opt, "throw_msg") == 0) {
env->opts.enable_throw_msg = true;
} else if (strncmp(opt, "verbose=", 8) == 0) {
Expand All @@ -123,7 +125,7 @@ static int apply_global_opt(struct bpf_ir_env *env, const char *opt)
if (err) {
return err;
}
if (res < 0 || res > 15) {
if (res <= 0 || res > 15) {
return -EINVAL;
}
env->opts.max_iteration = res;
Expand Down
15 changes: 14 additions & 1 deletion core/bpf_ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,11 @@ static const struct function_pass pre_passes[] = {
static const struct function_pass post_passes[] = {
DEF_FUNC_PASS(bpf_ir_div_by_zero, "div_by_zero", false),
DEF_FUNC_PASS(msan, "msan", false),
DEF_FUNC_PASS(add_counter, "add_counter", false),
DEF_FUNC_PASS(insn_counter, "insn_counter", false),
/* CG Preparation Passes */
DEF_NON_OVERRIDE_FUNC_PASS(translate_throw, "translate_throw"),
DEF_FUNC_PASS(bpf_ir_optimize_code_compaction, "optimize_compaction",
false),
DEF_NON_OVERRIDE_FUNC_PASS(bpf_ir_optimize_ir, "optimize_ir"),
DEF_NON_OVERRIDE_FUNC_PASS(bpf_ir_cg_change_fun_arg, "change_fun_arg"),
DEF_NON_OVERRIDE_FUNC_PASS(bpf_ir_cg_change_call_pre_cg, "change_call"),
Expand Down Expand Up @@ -1562,6 +1564,15 @@ static void add_reach(struct bpf_ir_env *env, struct ir_function *fun,
break;
}
if (cur_bb->succs.num_elem == 1) {
// Check if end with JA
struct ir_insn *lastinsn = bpf_ir_get_last_insn(cur_bb);
if (lastinsn && lastinsn->op == IR_INSN_JA) {
struct ir_basic_block **succ2 =
bpf_ir_array_get_void(&cur_bb->succs,
0);
bpf_ir_array_push(env, &todo, succ2);
break;
}
} else if (cur_bb->succs.num_elem == 2) {
struct ir_basic_block **succ2 =
bpf_ir_array_get_void(&cur_bb->succs, 1);
Expand Down Expand Up @@ -1848,6 +1859,7 @@ struct bpf_ir_opts bpf_ir_default_opts(void)
opts.max_iteration = 10;
opts.disable_prog_check = false;
opts.enable_throw_msg = false;
opts.enable_printk_log = false;
return opts;
}

Expand All @@ -1864,6 +1876,7 @@ struct bpf_ir_env *bpf_ir_init_env(struct bpf_ir_opts opts,
env->verifier_err = -1;
env->executed = false;
env->venv = NULL;
env->verifier_info_map = NULL;
env->verifier_log_end_pos = 0;
env->prog_type = 0; // Unspecified
env->lift_time = 0;
Expand Down
5 changes: 4 additions & 1 deletion core/epasstool/epasstool.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ int main(int argc, char **argv)
uopts.gopt[0] = 0;
uopts.popt[0] = 0;
uopts.no_compile = false;
uopts.auto_sec = true;
static struct option long_options[] = {
{ "mode", required_argument, NULL, 'm' },
{ "gopt", required_argument, NULL, 0 },
Expand Down Expand Up @@ -89,6 +90,7 @@ int main(int argc, char **argv)
strcpy(uopts.prog, optarg);
break;
case 's':
uopts.auto_sec = false;
strcpy(uopts.sec, optarg);
break;
case 'h':
Expand Down Expand Up @@ -116,8 +118,9 @@ int main(int argc, char **argv)
// Initialize common options
common_opts = bpf_ir_default_opts();
struct builtin_pass_cfg passes[] = {
bpf_ir_kern_add_counter_pass,
bpf_ir_kern_insn_counter_pass,
bpf_ir_kern_optimization_pass,
bpf_ir_kern_compaction_pass,
bpf_ir_kern_msan,
};
struct custom_pass_cfg custom_passes[] = {
Expand Down
1 change: 1 addition & 0 deletions core/epasstool/epasstool.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ struct user_opts {
char sec[64];
struct bpf_ir_opts opts;
bool no_compile;
bool auto_sec;
};

void masking_pass(struct bpf_ir_env *env, struct ir_function *fun, void *param);
Expand Down
8 changes: 6 additions & 2 deletions core/epasstool/read.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ int read(struct user_opts uopts)
printf("Failed to open object\n");
return 1;
}
struct bpf_program *prog =
bpf_object__find_program_by_name(obj, uopts.sec);
struct bpf_program *prog = NULL;
if (uopts.auto_sec) {
prog = bpf_object__next_program(obj, NULL);
} else {
prog = bpf_object__find_program_by_name(obj, uopts.sec);
}

if (!prog) {
printf("Program not found\n");
Expand Down
8 changes: 6 additions & 2 deletions core/epasstool/readload.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ static int callback_fn(struct bpf_program *prog,
int readload(struct user_opts uopts)
{
struct bpf_object *obj = bpf_object__open(uopts.prog);
struct bpf_program *prog =
bpf_object__find_program_by_name(obj, uopts.sec);
struct bpf_program *prog = NULL;
if (uopts.auto_sec) {
prog = bpf_object__next_program(obj, NULL);
} else {
prog = bpf_object__find_program_by_name(obj, uopts.sec);
}
if (!prog) {
return 1;
}
Expand Down
10 changes: 9 additions & 1 deletion core/epasstool/readlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,19 @@ int readlog(struct user_opts uopts)
return err;
}
enable_builtin(env);
u64 starttime = get_cur_time_ns();
bpf_ir_autorun(env);
if (env->err) {
return env->err;
}
// bpf_ir_print_log_dbg(env);
u64 tot = get_cur_time_ns() - starttime;

printf("ePass finished in %lluns\n", tot);
printf("lift %lluns\trun %lluns\tcompile %lluns\tsum %lluns\n",
env->lift_time, env->run_time, env->cg_time,
env->lift_time + env->run_time + env->cg_time);
printf("program size: %zu->%zu\n", index, env->insn_cnt);

bpf_ir_free_opts(env);
bpf_ir_free_env(env);

Expand Down
16 changes: 14 additions & 2 deletions core/include/linux/bpf_ir.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,13 @@ struct bpf_ir_opts {
// Force to use ePass, even if verifier passes
bool force;

// Enable printing log to printk
bool enable_printk_log;

// Enable register coalesce optimization
bool enable_coalesce;

// Write an error message to trace when throwing an error
bool enable_throw_msg;

// Verbose level
Expand Down Expand Up @@ -119,6 +123,10 @@ struct bpf_ir_env {

// Verifier env
void *venv;

// Verifier information map
// Bytecode Insn number -> Verifier information (e.g. min max, type)
void *verifier_info_map;
};

void bpf_ir_print_to_log(int level, struct bpf_ir_env *env, char *fmt, ...);
Expand Down Expand Up @@ -1178,17 +1186,21 @@ void print_ir_bb_err(struct bpf_ir_env *env, struct ir_basic_block *bb);
void remove_trivial_phi(struct bpf_ir_env *env, struct ir_function *fun,
void *param);

void add_counter(struct bpf_ir_env *env, struct ir_function *fun, void *param);
void insn_counter(struct bpf_ir_env *env, struct ir_function *fun, void *param);

void msan(struct bpf_ir_env *env, struct ir_function *fun, void *param);

void bpf_ir_div_by_zero(struct bpf_ir_env *env, struct ir_function *fun,
void *param);

extern const struct builtin_pass_cfg bpf_ir_kern_add_counter_pass;
void bpf_ir_optimize_code_compaction(struct bpf_ir_env *env,
struct ir_function *fun, void *param);

extern const struct builtin_pass_cfg bpf_ir_kern_insn_counter_pass;
extern const struct builtin_pass_cfg bpf_ir_kern_optimization_pass;
extern const struct builtin_pass_cfg bpf_ir_kern_msan;
extern const struct builtin_pass_cfg bpf_ir_kern_div_by_zero_pass;
extern const struct builtin_pass_cfg bpf_ir_kern_compaction_pass;

void translate_throw(struct bpf_ir_env *env, struct ir_function *fun,
void *param);
Expand Down
45 changes: 6 additions & 39 deletions core/ir_code_gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -446,33 +446,6 @@ static bool has_conflict(struct ir_insn *v1, struct ir_insn *v2)
return false;
}

static void erase_same_reg_assign(struct bpf_ir_env *env,
struct ir_function *fun, struct ir_insn *insn)
{
struct ir_insn *dst_insn = insn_dst(insn);
struct ir_insn *src_insn = insn->values[0].data.insn_d;
struct ir_insn_cg_extra *dst_insn_cg = insn_cg(dst_insn);
struct ir_insn_cg_extra *src_insn_cg = insn_cg(src_insn);
u8 src_reg = src_insn_cg->alloc_reg;
u8 dst_reg = dst_insn_cg->alloc_reg;
DBGASSERT(src_reg == dst_reg);
// Merge!
if (dst_insn_cg->nonvr && src_insn_cg->nonvr) {
// R = R
bpf_ir_erase_insn_cg(env, fun, insn);
return;
}
if (dst_insn_cg->nonvr) {
// R = r
set_insn_dst(env, src_insn, dst_insn);
bpf_ir_erase_insn_cg(env, fun, insn);
return;
}
// r = R || r = r
set_insn_dst(env, dst_insn, src_insn);
bpf_ir_erase_insn_cg(env, fun, insn);
}

/* Optimization: Coalescing

Returns false if no need to rerun liveness analysis
Expand All @@ -498,9 +471,10 @@ static bool coalescing(struct bpf_ir_env *env, struct ir_function *fun)
if (insn_cg(src)->alloc_reg ==
insn_cg(insn_dst)->alloc_reg) {
// Remove
erase_same_reg_assign(env, fun,
insn);
return true;
// erase_same_reg_assign(env, fun,
// insn);
// return true;
continue;
}

// R = R
Expand Down Expand Up @@ -2614,15 +2588,8 @@ static void translate_loadimm_extra(struct ir_insn *insn)
extra->translated[0].src_reg = insn->imm_extra_type;
extra->translated[0].dst_reg = get_alloc_reg(dst_insn);
// 0 2 6 needs next
if (insn->imm_extra_type == IR_LOADIMM_IMM64 ||
insn->imm_extra_type == IR_LOADIMM_MAP_VAL_FD ||
insn->imm_extra_type == IR_LOADIMM_MAP_VAL_IDX) {
extra->translated[0].it = IMM64;
extra->translated[0].imm64 = insn->imm64;
} else {
extra->translated[0].imm = insn->imm64 & 0xFFFFFFFF;
extra->translated[0].it = IMM;
}
extra->translated[0].it = IMM64;
extra->translated[0].imm64 = insn->imm64;
}

static void translate_storeraw(struct ir_insn *insn)
Expand Down
1 change: 0 additions & 1 deletion core/ir_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -784,5 +784,4 @@ void bpf_ir_print_log_dbg(struct bpf_ir_env *env)
PRINT_DBG("%s", line);
}
PRINT_DBG("----- End of Log -----\nLog size: %zu\n", env->log_pos);
env->log_pos = 0;
}
73 changes: 73 additions & 0 deletions core/passes/code_compaction.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/bpf_ir.h>

// An optimization mentioned in MERLIN that is hard to do in LLVM

void bpf_ir_optimize_code_compaction(struct bpf_ir_env *env,
struct ir_function *fun, void *param)
{
struct array opt_insns;
INIT_ARRAY(&opt_insns, struct ir_insn *);
struct ir_basic_block **pos;
struct ir_insn *prev_insn = NULL;
struct ir_insn *cur_insn = NULL;
array_for(pos, fun->reachable_bbs)
{
struct ir_basic_block *bb = *pos;
list_for_each_entry(cur_insn, &bb->ir_insn_head, list_ptr) {
if (prev_insn == NULL) {
prev_insn = cur_insn;
continue;
}
if (prev_insn->op == IR_INSN_LSH &&
cur_insn->op == IR_INSN_RSH) {
if (prev_insn->values[1].type !=
IR_VALUE_CONSTANT ||
cur_insn->values[1].type !=
IR_VALUE_CONSTANT) {
continue;
}
if (prev_insn->values[1].data.constant_d !=
32 ||
cur_insn->values[1].data.constant_d != 32) {
continue;
}
if (prev_insn->values[0].type ==
IR_VALUE_INSN &&
cur_insn->values[0].type == IR_VALUE_INSN &&
prev_insn ==
cur_insn->values[0].data.insn_d) {
// Same!
bpf_ir_array_push(env, &opt_insns,
&cur_insn);
}
}
prev_insn = cur_insn;
}
}
PRINT_LOG_DEBUG(env, "Found %d compaction opt\n", opt_insns.num_elem);
if (opt_insns.num_elem == 0) {
return;
}
struct ir_insn **pos2;
array_for(pos2, opt_insns)
{
struct ir_insn *insn = *pos2;
struct ir_insn *lsh_insn = insn->values[0].data.insn_d;
DBGASSERT(insn->op == IR_INSN_RSH);
DBGASSERT(lsh_insn->op == IR_INSN_LSH);
// Insert optimized code
bpf_ir_change_value(env, insn, &insn->values[0],
lsh_insn->values[0]);
insn->op = IR_INSN_ASSIGN;
insn->vr_type = IR_VR_TYPE_32;
insn->alu_op = IR_ALU_32;
insn->value_num = 1;
insn->raw_pos.valid = false;
bpf_ir_erase_insn(env, lsh_insn);
}
bpf_ir_array_free(&opt_insns);
}

const struct builtin_pass_cfg bpf_ir_kern_compaction_pass =
DEF_BUILTIN_PASS_CFG("optimize_compaction", NULL, NULL);
Loading