| 1 | #define OPTIMISE 1 |
|---|
| 2 | #define OUTPUT_COMPILED 0 |
|---|
| 3 | |
|---|
| 4 | #include "bpf-jit/bpf-jit.h" |
|---|
| 5 | #include <llvm/LLVMContext.h> |
|---|
| 6 | namespace llvm { |
|---|
| 7 | class LLVMContext; |
|---|
| 8 | LLVMContext *libtraceContext; |
|---|
| 9 | } |
|---|
| 10 | #define getGlobalContext() (*libtraceContext) |
|---|
| 11 | #include <llvm/Module.h> |
|---|
| 12 | #include <llvm/DerivedTypes.h> |
|---|
| 13 | #include <llvm/Constants.h> |
|---|
| 14 | #include <llvm/Instructions.h> |
|---|
| 15 | #include <llvm/ModuleProvider.h> |
|---|
| 16 | #include <llvm/Analysis/Verifier.h> |
|---|
| 17 | #include <llvm/ExecutionEngine/JIT.h> |
|---|
| 18 | #include <llvm/ExecutionEngine/Interpreter.h> |
|---|
| 19 | #include <llvm/ExecutionEngine/GenericValue.h> |
|---|
| 20 | |
|---|
| 21 | #include <llvm/CallingConv.h> |
|---|
| 22 | #include <llvm/PassManager.h> |
|---|
| 23 | #include <llvm/Support/StandardPasses.h> |
|---|
| 24 | #include <llvm/Target/TargetData.h> |
|---|
| 25 | #include <llvm/Target/TargetSelect.h> |
|---|
| 26 | #ifdef OUTPUT_COMPILED |
|---|
| 27 | #include <llvm/Assembly/PrintModulePass.h> |
|---|
| 28 | #include <llvm/Support/FormattedStream.h> |
|---|
| 29 | #endif |
|---|
| 30 | #include <llvm/LinkAllPasses.h> |
|---|
| 31 | |
|---|
| 32 | #include <iostream> |
|---|
| 33 | #include <algorithm> |
|---|
| 34 | #include <map> |
|---|
| 35 | #include <stdarg.h> |
|---|
| 36 | |
|---|
| 37 | #include <pcap-bpf.h> |
|---|
| 38 | #include <net/ethernet.h> |
|---|
| 39 | #include <netinet/if_ether.h> |
|---|
| 40 | #include <boost/lexical_cast.hpp> |
|---|
| 41 | |
|---|
| 42 | |
|---|
| 43 | using namespace llvm; |
|---|
| 44 | |
|---|
| 45 | #include "bpf-jit/bpf-opcodes.llvm.cc" |
|---|
| 46 | |
|---|
| 47 | static const char *opcode_names[256]; |
|---|
| 48 | |
|---|
| 49 | template <class X> |
|---|
| 50 | static std::vector<X> construct_vector(int items, ...) |
|---|
| 51 | { |
|---|
| 52 | std::vector<X> ret; |
|---|
| 53 | va_list va; |
|---|
| 54 | va_start(va,items); |
|---|
| 55 | for(int i=0;i<items;++i) { |
|---|
| 56 | ret.push_back(va_arg(va,X)); |
|---|
| 57 | } |
|---|
| 58 | va_end(va); |
|---|
| 59 | return ret; |
|---|
| 60 | } |
|---|
| 61 | |
|---|
| 62 | static void construct_jeq_k(Module *mod, int insnum, const struct bpf_insn &insn, |
|---|
| 63 | AllocaInst *ptr_state, |
|---|
| 64 | std::map<int,BasicBlock *> &blocks) |
|---|
| 65 | { |
|---|
| 66 | BasicBlock *this_block = blocks[insnum]; |
|---|
| 67 | BasicBlock *true_block = blocks[insnum+1+insn.jt]; |
|---|
| 68 | BasicBlock *false_block = blocks[insnum+1+insn.jf]; |
|---|
| 69 | |
|---|
| 70 | std::vector<Value*> a_offsets = construct_vector<Value*>(2, |
|---|
| 71 | ConstantInt::get(getGlobalContext(),APInt(32,0)), |
|---|
| 72 | ConstantInt::get(getGlobalContext(),APInt(32,0)) |
|---|
| 73 | ); |
|---|
| 74 | |
|---|
| 75 | Instruction *a = GetElementPtrInst::Create(ptr_state, |
|---|
| 76 | a_offsets.begin(), a_offsets.end(), "state_a", this_block); |
|---|
| 77 | |
|---|
| 78 | ICmpInst *cmp = new ICmpInst(*this_block, ICmpInst::ICMP_EQ, |
|---|
| 79 | new LoadInst(a,"avalue", this_block), |
|---|
| 80 | ConstantInt::get(getGlobalContext(), APInt(32, insn.k)), |
|---|
| 81 | std::string("cmp_a_vs_")+boost::lexical_cast<std::string>(insn.k)); |
|---|
| 82 | |
|---|
| 83 | BranchInst::Create(true_block, false_block, cmp, this_block); |
|---|
| 84 | } |
|---|
| 85 | |
|---|
| 86 | static void construct_jgt_k(Module *mod, int insnum, const struct bpf_insn &insn, |
|---|
| 87 | AllocaInst *ptr_state, |
|---|
| 88 | std::map<int,BasicBlock *> &blocks) |
|---|
| 89 | { |
|---|
| 90 | BasicBlock *this_block = blocks[insnum]; |
|---|
| 91 | BasicBlock *true_block = blocks[insnum+1+insn.jt]; |
|---|
| 92 | BasicBlock *false_block = blocks[insnum+1+insn.jf]; |
|---|
| 93 | |
|---|
| 94 | std::vector<Value*> a_offsets = construct_vector<Value*>(2, |
|---|
| 95 | ConstantInt::get(getGlobalContext(),APInt(32,0)), |
|---|
| 96 | ConstantInt::get(getGlobalContext(),APInt(32,0)) |
|---|
| 97 | ); |
|---|
| 98 | |
|---|
| 99 | Instruction *a = GetElementPtrInst::Create(ptr_state, |
|---|
| 100 | a_offsets.begin(), a_offsets.end(), "state_a", this_block); |
|---|
| 101 | |
|---|
| 102 | ICmpInst *cmp = new ICmpInst(*this_block, ICmpInst::ICMP_UGT, |
|---|
| 103 | new LoadInst(a,"avalue", this_block), |
|---|
| 104 | ConstantInt::get(getGlobalContext(), APInt(32, insn.k)), |
|---|
| 105 | "cmp_a_vs_k"); |
|---|
| 106 | |
|---|
| 107 | BranchInst::Create(true_block, false_block, cmp, this_block); |
|---|
| 108 | } |
|---|
| 109 | |
|---|
| 110 | static void construct_jge_k(Module *mod, int insnum, const struct bpf_insn &insn, |
|---|
| 111 | AllocaInst *ptr_state, |
|---|
| 112 | std::map<int,BasicBlock *> &blocks) |
|---|
| 113 | { |
|---|
| 114 | BasicBlock *this_block = blocks[insnum]; |
|---|
| 115 | BasicBlock *true_block = blocks[insnum+1+insn.jt]; |
|---|
| 116 | BasicBlock *false_block = blocks[insnum+1+insn.jf]; |
|---|
| 117 | |
|---|
| 118 | std::vector<Value*> a_offsets = construct_vector<Value*>(2, |
|---|
| 119 | ConstantInt::get(getGlobalContext(),APInt(32,0)), |
|---|
| 120 | ConstantInt::get(getGlobalContext(),APInt(32,0)) |
|---|
| 121 | ); |
|---|
| 122 | |
|---|
| 123 | Instruction *a = GetElementPtrInst::Create(ptr_state, |
|---|
| 124 | a_offsets.begin(), a_offsets.end(), "state_a", this_block); |
|---|
| 125 | |
|---|
| 126 | ICmpInst *cmp = new ICmpInst(*this_block, ICmpInst::ICMP_UGE, |
|---|
| 127 | new LoadInst(a,"avalue", this_block), |
|---|
| 128 | ConstantInt::get(getGlobalContext(), APInt(32, insn.k)), |
|---|
| 129 | "cmp_a_vs_k"); |
|---|
| 130 | |
|---|
| 131 | BranchInst::Create(true_block, false_block, cmp, this_block); |
|---|
| 132 | } |
|---|
| 133 | |
|---|
| 134 | static void construct_jeq_x(Module *mod, int insnum, const struct bpf_insn &insn, |
|---|
| 135 | AllocaInst *ptr_state, |
|---|
| 136 | std::map<int,BasicBlock *> &blocks) |
|---|
| 137 | { |
|---|
| 138 | BasicBlock *this_block = blocks[insnum]; |
|---|
| 139 | BasicBlock *true_block = blocks[insnum+1+insn.jt]; |
|---|
| 140 | BasicBlock *false_block = blocks[insnum+1+insn.jf]; |
|---|
| 141 | |
|---|
| 142 | std::vector<Value*> a_offsets = construct_vector<Value*>(2, |
|---|
| 143 | ConstantInt::get(getGlobalContext(),APInt(32,0)), |
|---|
| 144 | ConstantInt::get(getGlobalContext(),APInt(32,0)) |
|---|
| 145 | ); |
|---|
| 146 | |
|---|
| 147 | std::vector<Value*> x_offsets = construct_vector<Value*>(2, |
|---|
| 148 | ConstantInt::get(getGlobalContext(),APInt(32,0)), |
|---|
| 149 | ConstantInt::get(getGlobalContext(),APInt(32,1)) |
|---|
| 150 | ); |
|---|
| 151 | |
|---|
| 152 | Instruction *a = GetElementPtrInst::Create(ptr_state, |
|---|
| 153 | a_offsets.begin(), a_offsets.end(), "state_a", this_block); |
|---|
| 154 | |
|---|
| 155 | Instruction *x = GetElementPtrInst::Create(ptr_state, |
|---|
| 156 | x_offsets.begin(), x_offsets.end(), "state_x", this_block); |
|---|
| 157 | |
|---|
| 158 | ICmpInst *cmp = new ICmpInst(*this_block, ICmpInst::ICMP_EQ, |
|---|
| 159 | new LoadInst(a,"avalue", this_block), |
|---|
| 160 | new LoadInst(x,"xvalue", this_block), |
|---|
| 161 | "cmp_a_vs_x"); |
|---|
| 162 | |
|---|
| 163 | BranchInst::Create(true_block, false_block, cmp, this_block); |
|---|
| 164 | } |
|---|
| 165 | |
|---|
| 166 | static void construct_jgt_x(Module *mod, int insnum, const struct bpf_insn &insn, |
|---|
| 167 | AllocaInst *ptr_state, |
|---|
| 168 | std::map<int,BasicBlock *> &blocks) |
|---|
| 169 | { |
|---|
| 170 | BasicBlock *this_block = blocks[insnum]; |
|---|
| 171 | BasicBlock *true_block = blocks[insnum+1+insn.jt]; |
|---|
| 172 | BasicBlock *false_block = blocks[insnum+1+insn.jf]; |
|---|
| 173 | |
|---|
| 174 | std::vector<Value*> a_offsets = construct_vector<Value*>(2, |
|---|
| 175 | ConstantInt::get(getGlobalContext(),APInt(32,0)), |
|---|
| 176 | ConstantInt::get(getGlobalContext(),APInt(32,0)) |
|---|
| 177 | ); |
|---|
| 178 | |
|---|
| 179 | std::vector<Value*> x_offsets = construct_vector<Value*>(2, |
|---|
| 180 | ConstantInt::get(getGlobalContext(),APInt(32,0)), |
|---|
| 181 | ConstantInt::get(getGlobalContext(),APInt(32,1)) |
|---|
| 182 | ); |
|---|
| 183 | |
|---|
| 184 | Instruction *a = GetElementPtrInst::Create(ptr_state, |
|---|
| 185 | a_offsets.begin(), a_offsets.end(), "state_a", this_block); |
|---|
| 186 | |
|---|
| 187 | Instruction *x = GetElementPtrInst::Create(ptr_state, |
|---|
| 188 | x_offsets.begin(), x_offsets.end(), "state_x", this_block); |
|---|
| 189 | |
|---|
| 190 | ICmpInst *cmp = new ICmpInst(*this_block, ICmpInst::ICMP_UGT, |
|---|
| 191 | new LoadInst(a,"avalue", this_block), |
|---|
| 192 | new LoadInst(x,"xvalue", this_block), |
|---|
| 193 | "cmp_a_vs_x"); |
|---|
| 194 | |
|---|
| 195 | BranchInst::Create(true_block, false_block, cmp, this_block); |
|---|
| 196 | } |
|---|
| 197 | |
|---|
| 198 | static void construct_jset_x(Module *mod, int insnum, const struct bpf_insn &insn, |
|---|
| 199 | AllocaInst *ptr_state, |
|---|
| 200 | std::map<int,BasicBlock *> &blocks) |
|---|
| 201 | { |
|---|
| 202 | BasicBlock *this_block = blocks[insnum]; |
|---|
| 203 | BasicBlock *true_block = blocks[insnum+1+insn.jt]; |
|---|
| 204 | BasicBlock *false_block = blocks[insnum+1+insn.jf]; |
|---|
| 205 | |
|---|
| 206 | std::vector<Value*> a_offsets = construct_vector<Value*>(2, |
|---|
| 207 | ConstantInt::get(getGlobalContext(),APInt(32,0)), |
|---|
| 208 | ConstantInt::get(getGlobalContext(),APInt(32,0)) |
|---|
| 209 | ); |
|---|
| 210 | |
|---|
| 211 | std::vector<Value*> x_offsets = construct_vector<Value*>(2, |
|---|
| 212 | ConstantInt::get(getGlobalContext(),APInt(32,0)), |
|---|
| 213 | ConstantInt::get(getGlobalContext(),APInt(32,1)) |
|---|
| 214 | ); |
|---|
| 215 | |
|---|
| 216 | Instruction *a = GetElementPtrInst::Create(ptr_state, |
|---|
| 217 | a_offsets.begin(), a_offsets.end(), "state_a", this_block); |
|---|
| 218 | |
|---|
| 219 | Instruction *x = GetElementPtrInst::Create(ptr_state, |
|---|
| 220 | x_offsets.begin(), x_offsets.end(), "state_x", this_block); |
|---|
| 221 | |
|---|
| 222 | BinaryOperator* band = BinaryOperator::Create(Instruction::And, |
|---|
| 223 | new LoadInst(a,"valuea_", this_block), |
|---|
| 224 | new LoadInst(a,"valuex_", this_block), |
|---|
| 225 | "and_a_and_x_", |
|---|
| 226 | this_block |
|---|
| 227 | ); |
|---|
| 228 | |
|---|
| 229 | ICmpInst *cmp = new ICmpInst(*this_block, ICmpInst::ICMP_EQ, |
|---|
| 230 | band, |
|---|
| 231 | ConstantInt::get(getGlobalContext(), APInt(32, 0)), |
|---|
| 232 | "cmp_a_and_x"); |
|---|
| 233 | |
|---|
| 234 | BranchInst::Create(true_block, false_block, cmp, this_block); |
|---|
| 235 | } |
|---|
| 236 | |
|---|
| 237 | static void construct_jge_x(Module *mod, int insnum, const struct bpf_insn &insn, |
|---|
| 238 | AllocaInst *ptr_state, |
|---|
| 239 | std::map<int,BasicBlock *> &blocks) |
|---|
| 240 | { |
|---|
| 241 | BasicBlock *this_block = blocks[insnum]; |
|---|
| 242 | BasicBlock *true_block = blocks[insnum+1+insn.jt]; |
|---|
| 243 | BasicBlock *false_block = blocks[insnum+1+insn.jf]; |
|---|
| 244 | |
|---|
| 245 | std::vector<Value*> a_offsets = construct_vector<Value*>(2, |
|---|
| 246 | ConstantInt::get(getGlobalContext(),APInt(32,0)), |
|---|
| 247 | ConstantInt::get(getGlobalContext(),APInt(32,0)) |
|---|
| 248 | ); |
|---|
| 249 | |
|---|
| 250 | std::vector<Value*> x_offsets = construct_vector<Value*>(2, |
|---|
| 251 | ConstantInt::get(getGlobalContext(),APInt(32,0)), |
|---|
| 252 | ConstantInt::get(getGlobalContext(),APInt(32,1)) |
|---|
| 253 | ); |
|---|
| 254 | |
|---|
| 255 | Instruction *a = GetElementPtrInst::Create(ptr_state, |
|---|
| 256 | a_offsets.begin(), a_offsets.end(), "state_a", this_block); |
|---|
| 257 | |
|---|
| 258 | Instruction *x = GetElementPtrInst::Create(ptr_state, |
|---|
| 259 | x_offsets.begin(), x_offsets.end(), "state_x", this_block); |
|---|
| 260 | |
|---|
| 261 | ICmpInst *cmp = new ICmpInst(*this_block, ICmpInst::ICMP_UGE, |
|---|
| 262 | new LoadInst(a,"avalue", this_block), |
|---|
| 263 | new LoadInst(x,"xvalue", this_block), |
|---|
| 264 | "cmp_a_vs_x"); |
|---|
| 265 | |
|---|
| 266 | BranchInst::Create(true_block, false_block, cmp, this_block); |
|---|
| 267 | } |
|---|
| 268 | |
|---|
| 269 | Module* build_bpf_program(struct bpf_insn insns[], int plen) |
|---|
| 270 | { |
|---|
| 271 | // Module Construction |
|---|
| 272 | Module* mod = makeLLVMModule(); |
|---|
| 273 | |
|---|
| 274 | FunctionType* memsetType = FunctionType::get( |
|---|
| 275 | /*Result=*/Type::getVoidTy(getGlobalContext()), |
|---|
| 276 | construct_vector<const Type*>(4, |
|---|
| 277 | PointerType::get(IntegerType::get(getGlobalContext(), 8), 0), |
|---|
| 278 | IntegerType::get(getGlobalContext(), 8), |
|---|
| 279 | IntegerType::get(getGlobalContext(), 64), |
|---|
| 280 | IntegerType::get(getGlobalContext(), 32)), |
|---|
| 281 | /*isVarArg=*/false); |
|---|
| 282 | |
|---|
| 283 | // Function Declarations |
|---|
| 284 | |
|---|
| 285 | Function* func_bpf_run = Function::Create( |
|---|
| 286 | /*Type=*/FunctionType::get( |
|---|
| 287 | IntegerType::get(getGlobalContext(), 32), |
|---|
| 288 | construct_vector<const Type*>(2, |
|---|
| 289 | PointerType::get(IntegerType::get(getGlobalContext(), 8), 0), |
|---|
| 290 | IntegerType::get(getGlobalContext(), 32)), |
|---|
| 291 | false), |
|---|
| 292 | /*Linkage=*/GlobalValue::ExternalLinkage, |
|---|
| 293 | /*Name=*/"bpf_run", mod); |
|---|
| 294 | func_bpf_run->setCallingConv(CallingConv::C); |
|---|
| 295 | AttrListPtr func_bpf_run_PAL; |
|---|
| 296 | { |
|---|
| 297 | SmallVector<AttributeWithIndex, 4> Attrs; |
|---|
| 298 | AttributeWithIndex PAWI; |
|---|
| 299 | PAWI.Index = 4294967295U; PAWI.Attrs = 0 | Attribute::NoUnwind; |
|---|
| 300 | Attrs.push_back(PAWI); |
|---|
| 301 | func_bpf_run_PAL = AttrListPtr::get(Attrs.begin(), Attrs.end()); |
|---|
| 302 | |
|---|
| 303 | } |
|---|
| 304 | func_bpf_run->setAttributes(func_bpf_run_PAL); |
|---|
| 305 | |
|---|
| 306 | Function* func_llvm_memset_i64 = Function::Create( |
|---|
| 307 | /*Type=*/memsetType, |
|---|
| 308 | /*Linkage=*/GlobalValue::ExternalLinkage, |
|---|
| 309 | /*Name=*/"llvm.memset.i64", mod); // (external, no body) |
|---|
| 310 | func_llvm_memset_i64->setCallingConv(CallingConv::C); |
|---|
| 311 | AttrListPtr func_llvm_memset_i64_PAL; |
|---|
| 312 | { |
|---|
| 313 | SmallVector<AttributeWithIndex, 4> Attrs; |
|---|
| 314 | AttributeWithIndex PAWI; |
|---|
| 315 | PAWI.Index = 1U; PAWI.Attrs = 0 | Attribute::NoCapture; |
|---|
| 316 | Attrs.push_back(PAWI); |
|---|
| 317 | PAWI.Index = 4294967295U; PAWI.Attrs = 0 | Attribute::NoUnwind; |
|---|
| 318 | Attrs.push_back(PAWI); |
|---|
| 319 | func_llvm_memset_i64_PAL = AttrListPtr::get(Attrs.begin(), Attrs.end()); |
|---|
| 320 | |
|---|
| 321 | } |
|---|
| 322 | func_llvm_memset_i64->setAttributes(func_llvm_memset_i64_PAL); |
|---|
| 323 | |
|---|
| 324 | |
|---|
| 325 | // Global Variable Declarations |
|---|
| 326 | |
|---|
| 327 | |
|---|
| 328 | // Constant Definitions |
|---|
| 329 | ConstantInt* const_int8_12 = ConstantInt::get(getGlobalContext(), APInt(8, StringRef("0"), 10)); |
|---|
| 330 | ConstantInt* const_int64_13 = ConstantInt::get(getGlobalContext(), APInt(64, StringRef("1056"), 10)); |
|---|
| 331 | ConstantInt* const_int32_14 = ConstantInt::get(getGlobalContext(), APInt(32, StringRef("8"), 10)); |
|---|
| 332 | |
|---|
| 333 | // Function: bpf_run (func_bpf_run) |
|---|
| 334 | { |
|---|
| 335 | Function::arg_iterator args = func_bpf_run->arg_begin(); |
|---|
| 336 | Value* ptr_packet = args++; |
|---|
| 337 | ptr_packet->setName("packet"); |
|---|
| 338 | Value* int32_len = args++; |
|---|
| 339 | int32_len->setName("len"); |
|---|
| 340 | |
|---|
| 341 | BasicBlock* label_entry = BasicBlock::Create(getGlobalContext(), "entry",func_bpf_run,0); |
|---|
| 342 | |
|---|
| 343 | // Block entry (label_entry) |
|---|
| 344 | /* Create function variables */ |
|---|
| 345 | AllocaInst* ptr_packet_addr = new AllocaInst( |
|---|
| 346 | PointerType::get(IntegerType::get(getGlobalContext(), 8), 0), "packet_addr", label_entry); |
|---|
| 347 | AllocaInst* ptr_len_addr = new AllocaInst(IntegerType::get(getGlobalContext(), 32), "len_addr", label_entry); |
|---|
| 348 | AllocaInst* ptr_retval = new AllocaInst(IntegerType::get(getGlobalContext(), 32), "retval", label_entry); |
|---|
| 349 | AllocaInst* ptr_state = new AllocaInst(mod->getTypeByName(std::string("struct.bpf_state_t")), |
|---|
| 350 | "state", label_entry); |
|---|
| 351 | /* Store the arguments */ |
|---|
| 352 | new StoreInst(ptr_packet, ptr_packet_addr, false, label_entry); |
|---|
| 353 | new StoreInst(int32_len, ptr_len_addr, false, label_entry); |
|---|
| 354 | /* Memset state */ |
|---|
| 355 | CastInst* ptr_state1 = new BitCastInst(ptr_state, |
|---|
| 356 | PointerType::get(IntegerType::get(getGlobalContext(), 8), 0), |
|---|
| 357 | "state1", label_entry); |
|---|
| 358 | std::vector<Value*> void_25_params; |
|---|
| 359 | void_25_params.push_back(ptr_state1); |
|---|
| 360 | void_25_params.push_back(const_int8_12); |
|---|
| 361 | void_25_params.push_back(const_int64_13); |
|---|
| 362 | void_25_params.push_back(const_int32_14); |
|---|
| 363 | CallInst* void_25 = CallInst::Create(func_llvm_memset_i64, void_25_params.begin(), void_25_params.end(), "", label_entry); |
|---|
| 364 | void_25->setCallingConv(CallingConv::C); |
|---|
| 365 | void_25->setTailCall(false);AttrListPtr void_25_PAL; |
|---|
| 366 | void_25->setAttributes(void_25_PAL); |
|---|
| 367 | |
|---|
| 368 | /* set state->P */ |
|---|
| 369 | std::vector<Value*> state_p_offset = construct_vector<Value*>(2, |
|---|
| 370 | ConstantInt::get(getGlobalContext(),APInt(32,0)), |
|---|
| 371 | ConstantInt::get(getGlobalContext(),APInt(32,2))); |
|---|
| 372 | |
|---|
| 373 | Instruction* state_p_ptr = GetElementPtrInst::Create(ptr_state, |
|---|
| 374 | state_p_offset.begin(), |
|---|
| 375 | state_p_offset.end(), "state_p_ptr", |
|---|
| 376 | label_entry); |
|---|
| 377 | |
|---|
| 378 | new StoreInst(new LoadInst(ptr_packet_addr, "load_ptr_packet_addr", false, label_entry), |
|---|
| 379 | state_p_ptr, false, label_entry); |
|---|
| 380 | |
|---|
| 381 | /* set state->len */ |
|---|
| 382 | std::vector<Value*> state_len_offset = construct_vector<Value*>(2, |
|---|
| 383 | ConstantInt::get(getGlobalContext(),APInt(32,0)), |
|---|
| 384 | ConstantInt::get(getGlobalContext(),APInt(32,3))); |
|---|
| 385 | Instruction* state_len_ptr = GetElementPtrInst::Create(ptr_state, state_len_offset.begin(), state_len_offset.end(), "state_len_ptr", label_entry); |
|---|
| 386 | new StoreInst(new LoadInst(ptr_len_addr, "len", false, label_entry), state_len_ptr, false, label_entry); |
|---|
| 387 | |
|---|
| 388 | // Build one block per bpf instruction in our program |
|---|
| 389 | std::map<int, BasicBlock *> blocks; |
|---|
| 390 | BasicBlock *fail = BasicBlock::Create(getGlobalContext(), "fail", func_bpf_run, 0); |
|---|
| 391 | BasicBlock *success = BasicBlock::Create(getGlobalContext(), "success", func_bpf_run, 0); |
|---|
| 392 | for(int i=0; i<plen; ++i) { |
|---|
| 393 | char name[32]; |
|---|
| 394 | sprintf(name,"bpf_isn_%d",i); |
|---|
| 395 | blocks.insert(std::make_pair(i, |
|---|
| 396 | BasicBlock::Create(getGlobalContext(), std::string(name), func_bpf_run, 0))); |
|---|
| 397 | } |
|---|
| 398 | |
|---|
| 399 | BranchInst::Create(blocks[0], label_entry); |
|---|
| 400 | |
|---|
| 401 | // For each opcode, generate a call to the opcode that implements that function |
|---|
| 402 | // check if the function returns "continue" (~0U) "fail" (0) or "success" (other wise) |
|---|
| 403 | for(int i=0; i<plen; ++i) { |
|---|
| 404 | BasicBlock *this_block = blocks[i]; |
|---|
| 405 | BasicBlock *next_block; |
|---|
| 406 | if (blocks.find(i+1) != blocks.end()) |
|---|
| 407 | next_block = blocks[i+1]; |
|---|
| 408 | else |
|---|
| 409 | next_block = fail; |
|---|
| 410 | |
|---|
| 411 | switch (insns[i].code) { |
|---|
| 412 | case BPF_JMP+BPF_JGE+BPF_K: |
|---|
| 413 | construct_jge_k(mod,i,insns[i],ptr_state,blocks); |
|---|
| 414 | break; |
|---|
| 415 | |
|---|
| 416 | case BPF_JMP+BPF_JEQ+BPF_K: |
|---|
| 417 | construct_jeq_k(mod,i,insns[i],ptr_state,blocks); |
|---|
| 418 | break; |
|---|
| 419 | |
|---|
| 420 | case BPF_JMP+BPF_JGT+BPF_K: |
|---|
| 421 | construct_jgt_k(mod,i,insns[i],ptr_state,blocks); |
|---|
| 422 | break; |
|---|
| 423 | |
|---|
| 424 | case BPF_JMP+BPF_JSET+BPF_K: |
|---|
| 425 | construct_jset_x(mod,i,insns[i],ptr_state,blocks); |
|---|
| 426 | break; |
|---|
| 427 | |
|---|
| 428 | case BPF_JMP+BPF_JGE+BPF_X: |
|---|
| 429 | construct_jge_x(mod,i,insns[i],ptr_state,blocks); |
|---|
| 430 | break; |
|---|
| 431 | |
|---|
| 432 | case BPF_JMP+BPF_JEQ+BPF_X: |
|---|
| 433 | construct_jeq_x(mod,i,insns[i],ptr_state,blocks); |
|---|
| 434 | break; |
|---|
| 435 | |
|---|
| 436 | case BPF_JMP+BPF_JGT+BPF_X: |
|---|
| 437 | construct_jgt_x(mod,i,insns[i],ptr_state,blocks); |
|---|
| 438 | break; |
|---|
| 439 | |
|---|
| 440 | case BPF_JMP+BPF_JSET+BPF_X: |
|---|
| 441 | abort(); |
|---|
| 442 | |
|---|
| 443 | |
|---|
| 444 | default: |
|---|
| 445 | if (!opcode_names[insns[i].code]) |
|---|
| 446 | printf("Unknown opcode %02x\n", insns[i].code); |
|---|
| 447 | |
|---|
| 448 | |
|---|
| 449 | Function* func_opcode = mod->getFunction(opcode_names[insns[i].code]); |
|---|
| 450 | if (!func_opcode) { |
|---|
| 451 | printf("Couldn't find function for %s\n",opcode_names[insns[i].code]); |
|---|
| 452 | } |
|---|
| 453 | |
|---|
| 454 | std::vector<Value*> opcode_params; |
|---|
| 455 | opcode_params.push_back(ptr_state); |
|---|
| 456 | opcode_params.push_back( |
|---|
| 457 | ConstantInt::get(getGlobalContext(), APInt(8, insns[i].jt))); |
|---|
| 458 | opcode_params.push_back( |
|---|
| 459 | ConstantInt::get(getGlobalContext(), APInt(8, insns[i].jf))); |
|---|
| 460 | opcode_params.push_back( |
|---|
| 461 | ConstantInt::get(getGlobalContext(), APInt(64, insns[i].k))); |
|---|
| 462 | |
|---|
| 463 | CallInst* opcode = CallInst::Create( |
|---|
| 464 | func_opcode, |
|---|
| 465 | opcode_params.begin(), |
|---|
| 466 | opcode_params.end(), "bpf_opcode_call", |
|---|
| 467 | this_block); |
|---|
| 468 | opcode->setCallingConv(CallingConv::C); |
|---|
| 469 | opcode->setTailCall(false); |
|---|
| 470 | AttrListPtr opcode_PAL; |
|---|
| 471 | { |
|---|
| 472 | SmallVector<AttributeWithIndex, 4> Attrs; |
|---|
| 473 | AttributeWithIndex PAWI; |
|---|
| 474 | PAWI.Index = 2U; PAWI.Attrs = 0 | Attribute::ZExt; |
|---|
| 475 | Attrs.push_back(PAWI); |
|---|
| 476 | PAWI.Index = 3U; PAWI.Attrs = 0 | Attribute::ZExt; |
|---|
| 477 | Attrs.push_back(PAWI); |
|---|
| 478 | PAWI.Index = 4294967295U; PAWI.Attrs = 0 | Attribute::NoUnwind; |
|---|
| 479 | Attrs.push_back(PAWI); |
|---|
| 480 | opcode_PAL = AttrListPtr::get(Attrs.begin(), Attrs.end()); |
|---|
| 481 | } |
|---|
| 482 | opcode->setAttributes(opcode_PAL); |
|---|
| 483 | |
|---|
| 484 | new StoreInst(opcode, ptr_retval, this_block); |
|---|
| 485 | |
|---|
| 486 | ICmpInst *cmp = new ICmpInst(*this_block, ICmpInst::ICMP_NE, opcode, |
|---|
| 487 | ConstantInt::get(getGlobalContext(), APInt(32, ~0U)), |
|---|
| 488 | "cmp_failure"); |
|---|
| 489 | |
|---|
| 490 | BranchInst::Create(success, next_block, cmp, this_block); |
|---|
| 491 | break; |
|---|
| 492 | } |
|---|
| 493 | } |
|---|
| 494 | |
|---|
| 495 | /* Create an instruction so if we get here we fail */ |
|---|
| 496 | ReturnInst::Create(getGlobalContext(), |
|---|
| 497 | ConstantInt::get(getGlobalContext(), APInt(32, 0)), |
|---|
| 498 | fail); |
|---|
| 499 | |
|---|
| 500 | /* Create a success return */ |
|---|
| 501 | ReturnInst::Create(getGlobalContext(), |
|---|
| 502 | new LoadInst(ptr_retval, "retval", success), |
|---|
| 503 | success); |
|---|
| 504 | } |
|---|
| 505 | |
|---|
| 506 | return mod; |
|---|
| 507 | |
|---|
| 508 | } |
|---|
| 509 | |
|---|
| 510 | void initialise_array(void) |
|---|
| 511 | { |
|---|
| 512 | opcode_names[BPF_LD+BPF_W+BPF_ABS] = "bpf_ldw_abs"; |
|---|
| 513 | opcode_names[BPF_LD+BPF_H+BPF_ABS] = "bpf_ldh_abs"; |
|---|
| 514 | opcode_names[BPF_LD+BPF_B+BPF_ABS] = "bpf_ldb_abs"; |
|---|
| 515 | opcode_names[BPF_LD+BPF_W+BPF_IND] = "bpf_ldw_ind"; |
|---|
| 516 | opcode_names[BPF_LD+BPF_H+BPF_IND] = "bpf_ldh_ind"; |
|---|
| 517 | opcode_names[BPF_LD+BPF_B+BPF_IND] = "bpf_ldb_ind"; |
|---|
| 518 | opcode_names[BPF_LD+BPF_IMM] = "bpf_ldb_imm"; |
|---|
| 519 | opcode_names[BPF_LD+BPF_MEM] = "bpf_ldb_mem"; |
|---|
| 520 | |
|---|
| 521 | opcode_names[BPF_LDX+BPF_W+BPF_IMM] = "bpf_ldx_imm"; |
|---|
| 522 | opcode_names[BPF_LDX+BPF_W+BPF_MEM] = "bpf_ldx_mem"; |
|---|
| 523 | opcode_names[BPF_LDX+BPF_W+BPF_LEN] = "bpf_ldx_len"; |
|---|
| 524 | opcode_names[BPF_LDX+BPF_B+BPF_MSH] = "bpf_ldx_msh"; |
|---|
| 525 | |
|---|
| 526 | opcode_names[BPF_ST] = "bpf_st"; |
|---|
| 527 | opcode_names[BPF_STX] = "bpf_stx"; |
|---|
| 528 | |
|---|
| 529 | opcode_names[BPF_ALU+BPF_ADD+BPF_K] = "bpf_alu_add_k"; |
|---|
| 530 | opcode_names[BPF_ALU+BPF_SUB+BPF_K] = "bpf_alu_sub_k"; |
|---|
| 531 | opcode_names[BPF_ALU+BPF_MUL+BPF_K] = "bpf_alu_mul_k"; |
|---|
| 532 | opcode_names[BPF_ALU+BPF_DIV+BPF_K] = "bpf_alu_div_k"; |
|---|
| 533 | opcode_names[BPF_ALU+BPF_AND+BPF_K] = "bpf_alu_and_k"; |
|---|
| 534 | opcode_names[BPF_ALU+BPF_OR+BPF_K] = "bpf_alu_or_k"; |
|---|
| 535 | opcode_names[BPF_ALU+BPF_LSH+BPF_K] = "bpf_alu_lsh_k"; |
|---|
| 536 | opcode_names[BPF_ALU+BPF_RSH+BPF_K] = "bpf_alu_rsh_k"; |
|---|
| 537 | |
|---|
| 538 | opcode_names[BPF_ALU+BPF_NEG] = "bpf_alu_neg"; |
|---|
| 539 | |
|---|
| 540 | opcode_names[BPF_ALU+BPF_ADD+BPF_X] = "bpf_alu_add_x"; |
|---|
| 541 | opcode_names[BPF_ALU+BPF_SUB+BPF_X] = "bpf_alu_sub_x"; |
|---|
| 542 | opcode_names[BPF_ALU+BPF_MUL+BPF_X] = "bpf_alu_mul_x"; |
|---|
| 543 | opcode_names[BPF_ALU+BPF_DIV+BPF_X] = "bpf_alu_div_x"; |
|---|
| 544 | opcode_names[BPF_ALU+BPF_AND+BPF_X] = "bpf_alu_and_x"; |
|---|
| 545 | opcode_names[BPF_ALU+BPF_OR+BPF_X] = "bpf_alu_or_x"; |
|---|
| 546 | opcode_names[BPF_ALU+BPF_LSH+BPF_X] = "bpf_alu_lsh_x"; |
|---|
| 547 | opcode_names[BPF_ALU+BPF_RSH+BPF_X] = "bpf_alu_rsh_x"; |
|---|
| 548 | |
|---|
| 549 | opcode_names[BPF_JMP+BPF_JA] = "bpf_ja"; |
|---|
| 550 | opcode_names[BPF_JMP+BPF_JGT+BPF_K] = "bpf_gt_k"; |
|---|
| 551 | opcode_names[BPF_JMP+BPF_JGE+BPF_K] = "bpf_ge_k"; |
|---|
| 552 | opcode_names[BPF_JMP+BPF_JEQ+BPF_K] = "bpf_eq_k"; |
|---|
| 553 | opcode_names[BPF_JMP+BPF_JSET+BPF_K] = "bpf_set_k"; |
|---|
| 554 | opcode_names[BPF_JMP+BPF_JGT+BPF_X] = "bpf_gt_x"; |
|---|
| 555 | opcode_names[BPF_JMP+BPF_JGE+BPF_X] = "bpf_ge_x"; |
|---|
| 556 | opcode_names[BPF_JMP+BPF_JEQ+BPF_X] = "bpf_eq_x"; |
|---|
| 557 | opcode_names[BPF_JMP+BPF_JSET+BPF_X] = "bpf_set_x"; |
|---|
| 558 | |
|---|
| 559 | opcode_names[BPF_RET+BPF_A] = "bpf_ret_a"; |
|---|
| 560 | opcode_names[BPF_RET+BPF_K] = "bpf_ret_k"; |
|---|
| 561 | |
|---|
| 562 | opcode_names[BPF_MISC+BPF_TAX] = "bpf_tax"; |
|---|
| 563 | opcode_names[BPF_MISC+BPF_TXA] = "bpf_tax"; |
|---|
| 564 | |
|---|
| 565 | } |
|---|
| 566 | |
|---|
| 567 | /* Sample BPF Program */ |
|---|
| 568 | struct bpf_insn insns[] = { |
|---|
| 569 | BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12), |
|---|
| 570 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_REVARP, 0, 3), |
|---|
| 571 | BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20), |
|---|
| 572 | BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, /*REVARP_REQUEST*/6, 0, 1), |
|---|
| 573 | BPF_STMT(BPF_RET+BPF_K, sizeof(struct ether_arp) + |
|---|
| 574 | sizeof(struct ether_header)), |
|---|
| 575 | BPF_STMT(BPF_RET+BPF_K, 0), |
|---|
| 576 | }; |
|---|
| 577 | |
|---|
| 578 | |
|---|
| 579 | /* To external users we pass around a "bpf_jit_t", but actually it's layed out as a bpf_jit_private_t |
|---|
| 580 | * This is so people can use this from C, even tho we have C++ objects refered to from here. |
|---|
| 581 | */ |
|---|
| 582 | struct bpf_jit_private_t { |
|---|
| 583 | bpf_jit_t bpf_jit; |
|---|
| 584 | LLVMContext context; |
|---|
| 585 | ExecutionEngine *EE; |
|---|
| 586 | }; |
|---|
| 587 | |
|---|
| 588 | |
|---|
| 589 | extern "C" |
|---|
| 590 | bpf_jit_t *compile_program(struct bpf_insn insns[], int plen) |
|---|
| 591 | { |
|---|
| 592 | initialise_array(); |
|---|
| 593 | |
|---|
| 594 | struct bpf_jit_private_t * bpf_jitpriv |
|---|
| 595 | = (bpf_jit_private_t*)malloc(sizeof(bpf_jit_private_t)); |
|---|
| 596 | Module *mod; |
|---|
| 597 | |
|---|
| 598 | libtraceContext = new LLVMContext(); |
|---|
| 599 | mod = build_bpf_program(insns,plen); |
|---|
| 600 | |
|---|
| 601 | verifyModule(*mod, PrintMessageAction); |
|---|
| 602 | |
|---|
| 603 | PassManager PM; |
|---|
| 604 | |
|---|
| 605 | std::string errorStr; |
|---|
| 606 | PM.add(new TargetData(mod)); |
|---|
| 607 | |
|---|
| 608 | #if OPTIMISE |
|---|
| 609 | /* We need -O3, because inlining is very important to us */ |
|---|
| 610 | createStandardModulePasses(&PM, |
|---|
| 611 | /* -O3 */ 3, |
|---|
| 612 | false, /* Optimise for size? */ |
|---|
| 613 | true, /* UnitAtAtime -- Allow optimisations that may make global module changes*/ |
|---|
| 614 | false, /* Loop Unrolling? -- We don't support loops! */ |
|---|
| 615 | true, /* Simplify Library Calls */ |
|---|
| 616 | false, /* Exception support needed? */ |
|---|
| 617 | createFunctionInliningPass() /* Inlining Pass To use */ |
|---|
| 618 | ); |
|---|
| 619 | |
|---|
| 620 | createStandardLTOPasses(&PM, |
|---|
| 621 | false, /* Internalize -- Useless, we've done it already */ |
|---|
| 622 | true, /* Run Inliner -- If anything hasn't been inlined, do it now */ |
|---|
| 623 | false /* Verify Each */ |
|---|
| 624 | ); |
|---|
| 625 | #endif |
|---|
| 626 | |
|---|
| 627 | #if OUTPUT_COMPILED |
|---|
| 628 | /* Display the output */ |
|---|
| 629 | PM.add(createPrintModulePass(&outs())); |
|---|
| 630 | #endif |
|---|
| 631 | |
|---|
| 632 | PM.run(*mod); |
|---|
| 633 | |
|---|
| 634 | InitializeNativeTarget(); |
|---|
| 635 | |
|---|
| 636 | EngineBuilder EB = EngineBuilder(mod); |
|---|
| 637 | EB.setErrorStr(&errorStr); |
|---|
| 638 | EB.setEngineKind(EngineKind::JIT); |
|---|
| 639 | |
|---|
| 640 | bpf_jitpriv->EE = EB.create(); |
|---|
| 641 | if (!bpf_jitpriv->EE) { |
|---|
| 642 | std::cerr << "Failed to create JIT: " << errorStr << std::endl; |
|---|
| 643 | } |
|---|
| 644 | assert(bpf_jitpriv->EE); |
|---|
| 645 | |
|---|
| 646 | bpf_jitpriv->bpf_jit.bpf_run = |
|---|
| 647 | reinterpret_cast<bpf_run_t>(bpf_jitpriv->EE->getPointerToFunction(mod->getFunction("bpf_run"))); |
|---|
| 648 | |
|---|
| 649 | |
|---|
| 650 | /* |
|---|
| 651 | delete bpf_jit->EE; |
|---|
| 652 | delete libtraceContext; |
|---|
| 653 | free(bpf_jit); |
|---|
| 654 | */ |
|---|
| 655 | |
|---|
| 656 | return reinterpret_cast<bpf_jit_t*>(bpf_jitpriv); |
|---|
| 657 | } |
|---|
| 658 | |
|---|
| 659 | extern "C" |
|---|
| 660 | void destroy_program(struct bpf_jit_t *bpf_jit) |
|---|
| 661 | { |
|---|
| 662 | struct bpf_jit_private_t *priv=reinterpret_cast<bpf_jit_private_t*>(bpf_jit); |
|---|
| 663 | |
|---|
| 664 | delete priv->EE; |
|---|
| 665 | delete libtraceContext; |
|---|
| 666 | priv->bpf_jit.bpf_run = NULL; |
|---|
| 667 | free(bpf_jit); |
|---|
| 668 | } |
|---|
| 669 | |
|---|