#ifndef _PLY_IR_H #define _PLY_IR_H #include #include #include #include #include #define INSN(_code, _dst, _src, _off, _imm) \ ((struct bpf_insn) { \ .code = _code, \ .dst_reg = _dst, \ .src_reg = _src, \ .off = _off, \ .imm = _imm \ }) #define MOV32 INSN(BPF_ALU | BPF_MOV | BPF_X, 0, 0, 0, 0) #define MOV32_IMM(_imm) INSN(BPF_ALU | BPF_MOV | BPF_K, 0, 0, 0, _imm) #define MOV64 INSN(BPF_ALU64 | BPF_MOV | BPF_X, 0, 0, 0, 0) #define MOV64_IMM(_imm) INSN(BPF_ALU64 | BPF_MOV | BPF_K, 0, 0, 0, _imm) #define EXIT INSN(BPF_JMP | BPF_EXIT, 0, 0, 0, 0) #define CALL(_imm) INSN(BPF_JMP | BPF_CALL, 0, 0, 0, _imm) #define JMP(_op, _off) INSN(BPF_JMP | BPF_OP((_op)) | BPF_X, 0, 0, _off, 0) #define JMP_IMM(_op, _imm, _off) INSN(BPF_JMP | BPF_OP((_op)) | BPF_K, 0, 0, _off, _imm) #define ALU32(_op) INSN(BPF_ALU | BPF_OP((_op)) | BPF_X, 0, 0, 0, 0) #define ALU32_IMM(_op, _imm) INSN(BPF_ALU | BPF_OP((_op)) | BPF_K, 0, 0, 0, _imm) #define ALU64(_op) INSN(BPF_ALU64 | BPF_OP((_op)) | BPF_X, 0, 0, 0, 0) #define ALU64_IMM(_op, _imm) INSN(BPF_ALU64 | BPF_OP((_op)) | BPF_K, 0, 0, 0, _imm) #define ST_IMM(_width, _off, _imm) INSN(BPF_ST | BPF_SIZE(_width) | BPF_MEM, 0, 0, _off, _imm) #define STX(_width, _off) INSN(BPF_STX | BPF_SIZE(_width) | BPF_MEM, 0, 0, _off, 0) #define LDX(_width, _off) INSN(BPF_LDX | BPF_SIZE(_width) | BPF_MEM, 0, 0, _off, 0) #if __WORDSIZE == 64 # define MOV MOV64 # define MOV_IMM MOV64_IMM # define ALU ALU64 # define ALU_IMM ALU64_IMM #else # define MOV MOV32 # define MOV_IMM MOV32_IMM # define ALU ALU32 # define ALU_IMM ALU32_IMM #endif #define BPF_REG_BP BPF_REG_10 static inline int bpf_width(size_t size) { switch (size) { case 1: return BPF_B; case 2: return BPF_H; case 4: return BPF_W; case 8: return BPF_DW; } return -1; } struct sym; struct type; enum vitype { VI_INSN, VI_LDMAP, VI_LABEL, VI_REG_GET, VI_REG_PUT, }; struct vinsn { enum vitype vitype; union { struct { struct bpf_insn bpf; uint16_t dst; uint16_t src; } insn; int16_t label; uint16_t reg; struct { uint16_t reg; struct sym *sym; } map; }; }; struct ir { struct vinsn *vi; size_t len; int16_t next_label; uint16_t next_reg; ssize_t sp; }; enum irloc { LOC_IMM = (1 << 0), LOC_REG = (1 << 1), LOC_STACK = (1 << 2), }; struct irstate { int loc; size_t size; int32_t stack; int32_t imm; uint16_t reg; struct { int dot:1; int lval:1; int stack:1; } hint; }; void insn_dump(struct bpf_insn insn, FILE *fp); void vinsn_dump(struct vinsn *vi, FILE *fp); void ir_dump(struct ir *ir, FILE *fp); int16_t ir_alloc_label (struct ir *ir); void ir_init_irs(struct ir *ir, struct irstate *irs, struct type *t); void ir_init_sym(struct ir *ir, struct sym *sym); void ir_emit_insn (struct ir *ir, struct bpf_insn bpf, uint16_t dst, uint16_t src); void ir_emit_ldmap (struct ir *ir, uint16_t dst, struct sym *map); void ir_emit_label (struct ir *ir, int16_t label); void ir_emit_sym_to_reg(struct ir *ir, uint16_t dst, struct sym *src); void ir_emit_reg_to_sym(struct ir *ir, struct sym *dst, uint16_t src); void ir_emit_sym_to_stack(struct ir *ir, ssize_t offset, struct sym *src); void ir_emit_read_to_sym(struct ir *ir, struct sym *dst, uint16_t src); void ir_emit_memcpy(struct ir *ir, ssize_t dst, ssize_t src, size_t size); void ir_emit_bzero(struct ir *ir, ssize_t offset, size_t size); struct ir *ir_new(void); #endif /* _PLY_IR_H */