From: Dave Marchevsky Date: Fri, 17 Dec 2021 07:54:49 +0000 (-0500) Subject: Remove B language support X-Git-Tag: v0.24.0~41 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b8ff0856798da23f88266d28ede33ebd423729f5;p=platform%2Fupstream%2Fbcc.git Remove B language support Remove support for compiling B programs (see #3682 for explanation). There may be some vestigial logic in other files that needs to be cleanded up for simplicity - bpf_module.cc most likely - but that can be addressed in followup commits. Signed-off-by: Dave Marchevsky --- diff --git a/src/cc/CMakeLists.txt b/src/cc/CMakeLists.txt index bcbbaebe..ffe8feec 100644 --- a/src/cc/CMakeLists.txt +++ b/src/cc/CMakeLists.txt @@ -123,7 +123,7 @@ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${llvm_lib_exclude_f # bcc_common_libs_for_a for archive libraries # bcc_common_libs_for_s for shared libraries -set(bcc_common_libs b_frontend clang_frontend +set(bcc_common_libs clang_frontend -Wl,--whole-archive ${clang_libs} ${llvm_libs} -Wl,--no-whole-archive ${LIBELF_LIBRARIES}) if (LIBDEBUGINFOD_FOUND) @@ -131,7 +131,7 @@ if (LIBDEBUGINFOD_FOUND) endif (LIBDEBUGINFOD_FOUND) set(bcc_common_libs_for_a ${bcc_common_libs}) set(bcc_common_libs_for_s ${bcc_common_libs}) -set(bcc_common_libs_for_lua b_frontend clang_frontend +set(bcc_common_libs_for_lua clang_frontend ${clang_libs} ${llvm_libs} ${LIBELF_LIBRARIES}) if(LIBBPF_FOUND) list(APPEND bcc_common_libs_for_a ${LIBBPF_LIBRARIES}) diff --git a/src/cc/bcc_common.cc b/src/cc/bcc_common.cc index 1ccd8d16..5c349d70 100644 --- a/src/cc/bcc_common.cc +++ b/src/cc/bcc_common.cc @@ -17,16 +17,6 @@ #include "bpf_module.h" extern "C" { -void * bpf_module_create_b(const char *filename, const char *proto_filename, unsigned flags, - const char *dev_name) { - auto mod = new ebpf::BPFModule(flags, nullptr, true, "", true, dev_name); - if (mod->load_b(filename, proto_filename) != 0) { - delete mod; - return nullptr; - } - return mod; -} - void * bpf_module_create_c(const char *filename, unsigned flags, const char *cflags[], int ncflags, bool allow_rlimit, const char *dev_name) { auto mod = new ebpf::BPFModule(flags, nullptr, true, "", allow_rlimit, dev_name); diff --git a/src/cc/bcc_common.h b/src/cc/bcc_common.h index 4377523d..b5f77db9 100644 --- a/src/cc/bcc_common.h +++ b/src/cc/bcc_common.h @@ -25,8 +25,6 @@ extern "C" { #endif -void * bpf_module_create_b(const char *filename, const char *proto_filename, unsigned flags, - const char *dev_name); void * bpf_module_create_c(const char *filename, unsigned flags, const char *cflags[], int ncflags, bool allow_rlimit, const char *dev_name); void * bpf_module_create_c_from_string(const char *text, unsigned flags, const char *cflags[], diff --git a/src/cc/bpf_module.cc b/src/cc/bpf_module.cc index 80d3fc64..36f9582a 100644 --- a/src/cc/bpf_module.cc +++ b/src/cc/bpf_module.cc @@ -38,7 +38,6 @@ #include "common.h" #include "bcc_debug.h" #include "bcc_elf.h" -#include "frontends/b/loader.h" #include "frontends/clang/loader.h" #include "frontends/clang/b_frontend_action.h" #include "bpf_module.h" @@ -834,43 +833,6 @@ int BPFModule::table_leaf_scanf(size_t id, const char *leaf_str, void *leaf) { return 0; } -// load a B file, which comes in two parts -int BPFModule::load_b(const string &filename, const string &proto_filename) { - if (!sections_.empty()) { - fprintf(stderr, "Program already initialized\n"); - return -1; - } - if (filename.empty() || proto_filename.empty()) { - fprintf(stderr, "Invalid filenames\n"); - return -1; - } - - // Helpers are inlined in the following file (C). Load the definitions and - // pass the partially compiled module to the B frontend to continue with. - auto helpers_h = ExportedFiles::headers().find("/virtual/include/bcc/helpers.h"); - if (helpers_h == ExportedFiles::headers().end()) { - fprintf(stderr, "Internal error: missing bcc/helpers.h"); - return -1; - } - if (int rc = load_includes(helpers_h->second)) - return rc; - - BLoader b_loader(flags_); - used_b_loader_ = true; - if (int rc = b_loader.parse(&*mod_, filename, proto_filename, *ts_, id_, - maps_ns_)) - return rc; - if (rw_engine_enabled_) { - if (int rc = annotate()) - return rc; - } else { - annotate_light(); - } - if (int rc = finalize()) - return rc; - return 0; -} - // load a C file int BPFModule::load_c(const string &filename, const char *cflags[], int ncflags) { if (!sections_.empty()) { diff --git a/src/cc/bpf_module.h b/src/cc/bpf_module.h index d5729558..87938c3f 100644 --- a/src/cc/bpf_module.h +++ b/src/cc/bpf_module.h @@ -99,7 +99,6 @@ class BPFModule { const char *dev_name = nullptr); ~BPFModule(); int free_bcc_memory(); - int load_b(const std::string &filename, const std::string &proto_filename); int load_c(const std::string &filename, const char *cflags[], int ncflags); int load_string(const std::string &text, const char *cflags[], int ncflags); std::string id() const { return id_; } diff --git a/src/cc/frontends/CMakeLists.txt b/src/cc/frontends/CMakeLists.txt index cef6c3c7..5d3678c6 100644 --- a/src/cc/frontends/CMakeLists.txt +++ b/src/cc/frontends/CMakeLists.txt @@ -1,5 +1,4 @@ # Copyright (c) PLUMgrid, Inc. # Licensed under the Apache License, Version 2.0 (the "License") -add_subdirectory(b) add_subdirectory(clang) diff --git a/src/cc/frontends/b/CMakeLists.txt b/src/cc/frontends/b/CMakeLists.txt deleted file mode 100644 index 391ab274..00000000 --- a/src/cc/frontends/b/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) PLUMgrid, Inc. -# Licensed under the Apache License, Version 2.0 (the "License") - -include_directories(${CMAKE_CURRENT_BINARY_DIR}) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) - -BISON_TARGET(Parser parser.yy ${CMAKE_CURRENT_BINARY_DIR}/parser.yy.cc COMPILE_FLAGS "-o parser.yy.cc -v --debug") -FLEX_TARGET(Lexer lexer.ll ${CMAKE_CURRENT_BINARY_DIR}/lexer.ll.cc COMPILE_FLAGS "--c++ --o lexer.ll.cc") -ADD_FLEX_BISON_DEPENDENCY(Lexer Parser) -if (CMAKE_C_COMPILER_ID STREQUAL "Clang") - set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/lexer.ll.cc PROPERTIES COMPILE_FLAGS "-Wno-deprecated-register") -endif() - -add_library(b_frontend STATIC loader.cc codegen_llvm.cc node.cc parser.cc printer.cc - type_check.cc ${BISON_Parser_OUTPUTS} ${FLEX_Lexer_OUTPUTS}) diff --git a/src/cc/frontends/b/codegen_llvm.cc b/src/cc/frontends/b/codegen_llvm.cc deleted file mode 100644 index 359303c4..00000000 --- a/src/cc/frontends/b/codegen_llvm.cc +++ /dev/null @@ -1,1405 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bcc_exception.h" -#include "codegen_llvm.h" -#include "file_desc.h" -#include "lexer.h" -#include "libbpf.h" -#include "linux/bpf.h" -#include "table_storage.h" -#include "type_helper.h" - -namespace ebpf { -namespace cc { - -using namespace llvm; - -using std::for_each; -using std::make_tuple; -using std::map; -using std::pair; -using std::set; -using std::string; -using std::stringstream; -using std::to_string; -using std::vector; - -// can't forward declare IRBuilder in .h file (template with default -// parameters), so cast it instead :( -#define B (*((IRBuilder<> *)this->b_)) - -// Helper class to push/pop the insert block -class BlockStack { - public: - explicit BlockStack(CodegenLLVM *cc, BasicBlock *bb) - : old_bb_(cc->b_->GetInsertBlock()), cc_(cc) { - cc_->b_->SetInsertPoint(bb); - } - ~BlockStack() { - if (old_bb_) - cc_->b_->SetInsertPoint(old_bb_); - else - cc_->b_->ClearInsertionPoint(); - } - private: - BasicBlock *old_bb_; - CodegenLLVM *cc_; -}; - -// Helper class to push/pop switch statement insert block -class SwitchStack { - public: - explicit SwitchStack(CodegenLLVM *cc, SwitchInst *sw) - : old_sw_(cc->cur_switch_), cc_(cc) { - cc_->cur_switch_ = sw; - } - ~SwitchStack() { - cc_->cur_switch_ = old_sw_; - } - private: - SwitchInst *old_sw_; - CodegenLLVM *cc_; -}; - -CodegenLLVM::CodegenLLVM(llvm::Module *mod, Scopes *scopes, Scopes *proto_scopes) - : out_(stdout), mod_(mod), indent_(0), tmp_reg_index_(0), scopes_(scopes), - proto_scopes_(proto_scopes), expr_(nullptr) { - b_ = new IRBuilder<>(ctx()); -} -CodegenLLVM::~CodegenLLVM() { - delete b_; -} - -template -void CodegenLLVM::emit(const char *fmt, Args&&... params) { - //fprintf(out_, fmt, std::forward(params)...); - //fflush(out_); -} -void CodegenLLVM::emit(const char *s) { - //fprintf(out_, "%s", s); - //fflush(out_); -} - -CallInst *CodegenLLVM::createCall(Value *callee, ArrayRef args) -{ -#if LLVM_MAJOR_VERSION >= 11 - auto *calleePtrType = cast(callee->getType()); - auto *calleeType = cast(calleePtrType->getElementType()); - return B.CreateCall(calleeType, callee, args); -#else - return B.CreateCall(callee, args); -#endif -} - -LoadInst *CodegenLLVM::createLoad(Value *addr) -{ -#if LLVM_MAJOR_VERSION >= 14 - return B.CreateLoad(addr->getType()->getPointerElementType(), addr); -#else - return B.CreateLoad(addr); -#endif -} - -Value *CodegenLLVM::createInBoundsGEP(Value *ptr, ArrayRefidxlist) -{ -#if LLVM_MAJOR_VERSION >= 14 - return B.CreateInBoundsGEP(ptr->getType()->getScalarType()->getPointerElementType(), - ptr, idxlist); -#else - return B.CreateInBoundsGEP(ptr, idxlist); -#endif -} - -StatusTuple CodegenLLVM::visit_block_stmt_node(BlockStmtNode *n) { - - // enter scope - if (n->scope_) - scopes_->push_var(n->scope_); - - if (!n->stmts_.empty()) { - for (auto it = n->stmts_.begin(); it != n->stmts_.end(); ++it) - TRY2((*it)->accept(this)); - } - // exit scope - if (n->scope_) - scopes_->pop_var(); - - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_if_stmt_node(IfStmtNode *n) { - Function *parent = B.GetInsertBlock()->getParent(); - BasicBlock *label_then = BasicBlock::Create(ctx(), "if.then", parent); - BasicBlock *label_else = n->false_block_ ? BasicBlock::Create(ctx(), "if.else", parent) : nullptr; - BasicBlock *label_end = BasicBlock::Create(ctx(), "if.end", parent); - - TRY2(n->cond_->accept(this)); - Value *is_not_null = B.CreateIsNotNull(pop_expr()); - - if (n->false_block_) - B.CreateCondBr(is_not_null, label_then, label_else); - else - B.CreateCondBr(is_not_null, label_then, label_end); - - { - BlockStack bstack(this, label_then); - TRY2(n->true_block_->accept(this)); - if (!B.GetInsertBlock()->getTerminator()) - B.CreateBr(label_end); - } - - if (n->false_block_) { - BlockStack bstack(this, label_else); - TRY2(n->false_block_->accept(this)); - if (!B.GetInsertBlock()->getTerminator()) - B.CreateBr(label_end); - } - - B.SetInsertPoint(label_end); - - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_onvalid_stmt_node(OnValidStmtNode *n) { - TRY2(n->cond_->accept(this)); - - Value *is_null = B.CreateIsNotNull(pop_expr()); - - Function *parent = B.GetInsertBlock()->getParent(); - BasicBlock *label_then = BasicBlock::Create(ctx(), "onvalid.then", parent); - BasicBlock *label_else = n->else_block_ ? BasicBlock::Create(ctx(), "onvalid.else", parent) : nullptr; - BasicBlock *label_end = BasicBlock::Create(ctx(), "onvalid.end", parent); - - if (n->else_block_) - B.CreateCondBr(is_null, label_then, label_else); - else - B.CreateCondBr(is_null, label_then, label_end); - - { - BlockStack bstack(this, label_then); - TRY2(n->block_->accept(this)); - if (!B.GetInsertBlock()->getTerminator()) - B.CreateBr(label_end); - } - - if (n->else_block_) { - BlockStack bstack(this, label_else); - TRY2(n->else_block_->accept(this)); - if (!B.GetInsertBlock()->getTerminator()) - B.CreateBr(label_end); - } - - B.SetInsertPoint(label_end); - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_switch_stmt_node(SwitchStmtNode *n) { - Function *parent = B.GetInsertBlock()->getParent(); - BasicBlock *label_default = BasicBlock::Create(ctx(), "switch.default", parent); - BasicBlock *label_end = BasicBlock::Create(ctx(), "switch.end", parent); - // switch (cond) - TRY2(n->cond_->accept(this)); - SwitchInst *switch_inst = B.CreateSwitch(pop_expr(), label_default); - B.SetInsertPoint(label_end); - { - // case 1..N - SwitchStack sstack(this, switch_inst); - TRY2(n->block_->accept(this)); - } - // if other cases are terminal, erase the end label - if (pred_empty(label_end)) { - B.SetInsertPoint(resolve_label("DONE")); - label_end->eraseFromParent(); - } - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_case_stmt_node(CaseStmtNode *n) { - if (!cur_switch_) return mkstatus_(n, "no valid switch instruction"); - Function *parent = B.GetInsertBlock()->getParent(); - BasicBlock *label_end = B.GetInsertBlock(); - BasicBlock *dest; - if (n->value_) { - TRY2(n->value_->accept(this)); - dest = BasicBlock::Create(ctx(), "switch.case", parent); - Value *cond = B.CreateIntCast(pop_expr(), cur_switch_->getCondition()->getType(), false); - cur_switch_->addCase(cast(cond), dest); - } else { - dest = cur_switch_->getDefaultDest(); - } - { - BlockStack bstack(this, dest); - TRY2(n->block_->accept(this)); - // if no trailing goto, fall to end - if (!B.GetInsertBlock()->getTerminator()) - B.CreateBr(label_end); - } - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_ident_expr_node(IdentExprNode *n) { - if (!n->decl_) - return mkstatus_(n, "variable lookup failed: %s", n->name_.c_str()); - if (n->decl_->is_pointer()) { - if (n->sub_name_.size()) { - if (n->bitop_) { - // ident is holding a host endian number, don't use dext - if (n->is_lhs()) { - emit("%s%s->%s", n->decl_->scope_id(), n->c_str(), n->sub_name_.c_str()); - } else { - emit("(((%s%s->%s) >> %d) & (((%s)1 << %d) - 1))", n->decl_->scope_id(), n->c_str(), n->sub_name_.c_str(), - n->bitop_->bit_offset_, bits_to_uint(n->bitop_->bit_width_ + 1), n->bitop_->bit_width_); - } - return mkstatus_(n, "unsupported"); - } else { - if (n->struct_type_->id_->name_ == "_Packet" && n->sub_name_.substr(0, 3) == "arg") { - // convert arg1~arg8 into args[0]~args[7] assuming type_check verified the range already - auto arg_num = stoi(n->sub_name_.substr(3, 3)); - if (arg_num < 5) { - emit("%s%s->args_lo[%d]", n->decl_->scope_id(), n->c_str(), arg_num - 1); - } else { - emit("%s%s->args_hi[%d]", n->decl_->scope_id(), n->c_str(), arg_num - 5); - } - return mkstatus_(n, "unsupported"); - } else { - emit("%s%s->%s", n->decl_->scope_id(), n->c_str(), n->sub_name_.c_str()); - auto it = vars_.find(n->decl_); - if (it == vars_.end()) return mkstatus_(n, "Cannot locate variable %s in vars_ table", n->c_str()); - LoadInst *load_1 = createLoad(it->second); - vector indices({B.getInt32(0), B.getInt32(n->sub_decl_->slot_)}); - expr_ = createInBoundsGEP(load_1, indices); - if (!n->is_lhs()) - expr_ = createLoad(pop_expr()); - } - } - } else { - auto it = vars_.find(n->decl_); - if (it == vars_.end()) return mkstatus_(n, "Cannot locate variable %s in vars_ table", n->c_str()); - expr_ = n->is_lhs() ? it->second : (Value *)createLoad(it->second); - } - } else { - if (n->sub_name_.size()) { - emit("%s%s.%s", n->decl_->scope_id(), n->c_str(), n->sub_name_.c_str()); - auto it = vars_.find(n->decl_); - if (it == vars_.end()) return mkstatus_(n, "Cannot locate variable %s in vars_ table", n->c_str()); - vector indices({const_int(0), const_int(n->sub_decl_->slot_, 32)}); - expr_ = B.CreateGEP(nullptr, it->second, indices); - if (!n->is_lhs()) - expr_ = createLoad(pop_expr()); - } else { - if (n->bitop_) { - // ident is holding a host endian number, don't use dext - if (n->is_lhs()) - return mkstatus_(n, "illegal: ident %s is a left-hand-side type", n->name_.c_str()); - if (n->decl_->is_struct()) - return mkstatus_(n, "illegal: can only take bitop of a struct subfield"); - emit("(((%s%s) >> %d) & (((%s)1 << %d) - 1))", n->decl_->scope_id(), n->c_str(), - n->bitop_->bit_offset_, bits_to_uint(n->bitop_->bit_width_ + 1), n->bitop_->bit_width_); - } else { - emit("%s%s", n->decl_->scope_id(), n->c_str()); - auto it = vars_.find(n->decl_); - if (it == vars_.end()) return mkstatus_(n, "Cannot locate variable %s in vars_ table", n->c_str()); - if (n->is_lhs() || n->decl_->is_struct()) - expr_ = it->second; - else - expr_ = createLoad(it->second); - } - } - } - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_assign_expr_node(AssignExprNode *n) { - if (n->bitop_) { - TRY2(n->lhs_->accept(this)); - emit(" = ("); - TRY2(n->lhs_->accept(this)); - emit(" & ~((((%s)1 << %d) - 1) << %d)) | (", bits_to_uint(n->lhs_->bit_width_), - n->bitop_->bit_width_, n->bitop_->bit_offset_); - TRY2(n->rhs_->accept(this)); - emit(" << %d)", n->bitop_->bit_offset_); - return mkstatus_(n, "unsupported"); - } else { - if (n->lhs_->flags_[ExprNode::PROTO]) { - // auto f = n->lhs_->struct_type_->field(n->id_->sub_name_); - // emit("bpf_dins(%s%s + %zu, %zu, %zu, ", n->id_->decl_->scope_id(), n->id_->c_str(), - // f->bit_offset_ >> 3, f->bit_offset_ & 0x7, f->bit_width_); - // TRY2(n->rhs_->accept(this)); - // emit(")"); - return mkstatus_(n, "unsupported"); - } else { - TRY2(n->rhs_->accept(this)); - if (n->lhs_->is_pkt()) { - TRY2(n->lhs_->accept(this)); - } else { - Value *rhs = pop_expr(); - TRY2(n->lhs_->accept(this)); - Value *lhs = pop_expr(); - if (!n->rhs_->is_ref()) - rhs = B.CreateIntCast(rhs, cast(lhs->getType())->getElementType(), false); - B.CreateStore(rhs, lhs); - } - } - } - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::lookup_var(Node *n, const string &name, Scopes::VarScope *scope, - VariableDeclStmtNode **decl, Value **mem) const { - *decl = scope->lookup(name, SCOPE_GLOBAL); - if (!*decl) return mkstatus_(n, "cannot find %s variable", name.c_str()); - auto it = vars_.find(*decl); - if (it == vars_.end()) return mkstatus_(n, "unable to find %s memory location", name.c_str()); - *mem = it->second; - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_packet_expr_node(PacketExprNode *n) { - auto p = proto_scopes_->top_struct()->lookup(n->id_->name_, true); - VariableDeclStmtNode *offset_decl, *skb_decl; - Value *offset_mem, *skb_mem; - TRY2(lookup_var(n, "skb", scopes_->current_var(), &skb_decl, &skb_mem)); - TRY2(lookup_var(n, "$" + n->id_->name_, scopes_->current_var(), &offset_decl, &offset_mem)); - - if (p) { - auto f = p->field(n->id_->sub_name_); - if (f) { - size_t bit_offset = f->bit_offset_; - size_t bit_width = f->bit_width_; - if (n->bitop_) { - bit_offset += f->bit_width_ - (n->bitop_->bit_offset_ + n->bitop_->bit_width_); - bit_width = std::min(bit_width - n->bitop_->bit_offset_, n->bitop_->bit_width_); - } - if (n->is_ref()) { - // e.g.: @ip.hchecksum, return offset of the header within packet - LoadInst *offset_ptr = createLoad(offset_mem); - Value *skb_hdr_offset = B.CreateAdd(offset_ptr, B.getInt64(bit_offset >> 3)); - expr_ = B.CreateIntCast(skb_hdr_offset, B.getInt64Ty(), false); - } else if (n->is_lhs()) { - emit("bpf_dins_pkt(pkt, %s + %zu, %zu, %zu, ", n->id_->c_str(), bit_offset >> 3, bit_offset & 0x7, bit_width); - Function *store_fn = mod_->getFunction("bpf_dins_pkt"); - if (!store_fn) return mkstatus_(n, "unable to find function bpf_dins_pkt"); - LoadInst *skb_ptr = createLoad(skb_mem); - Value *skb_ptr8 = B.CreateBitCast(skb_ptr, B.getInt8PtrTy()); - LoadInst *offset_ptr = createLoad(offset_mem); - Value *skb_hdr_offset = B.CreateAdd(offset_ptr, B.getInt64(bit_offset >> 3)); - Value *rhs = B.CreateIntCast(pop_expr(), B.getInt64Ty(), false); - createCall(store_fn, vector({skb_ptr8, skb_hdr_offset, B.getInt64(bit_offset & 0x7), - B.getInt64(bit_width), rhs})); - } else { - emit("bpf_dext_pkt(pkt, %s + %zu, %zu, %zu)", n->id_->c_str(), bit_offset >> 3, bit_offset & 0x7, bit_width); - Function *load_fn = mod_->getFunction("bpf_dext_pkt"); - if (!load_fn) return mkstatus_(n, "unable to find function bpf_dext_pkt"); - LoadInst *skb_ptr = createLoad(skb_mem); - Value *skb_ptr8 = B.CreateBitCast(skb_ptr, B.getInt8PtrTy()); - LoadInst *offset_ptr = createLoad(offset_mem); - Value *skb_hdr_offset = B.CreateAdd(offset_ptr, B.getInt64(bit_offset >> 3)); - expr_ = createCall(load_fn, vector({skb_ptr8, skb_hdr_offset, - B.getInt64(bit_offset & 0x7), B.getInt64(bit_width)})); - // this generates extra trunc insns whereas the bpf.load fns already - // trunc the values internally in the bpf interpreter - //expr_ = B.CreateTrunc(pop_expr(), B.getIntNTy(bit_width)); - } - } else { - emit("pkt->start + pkt->offset + %s", n->id_->c_str()); - return mkstatus_(n, "unsupported"); - } - } - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_integer_expr_node(IntegerExprNode *n) { - APInt val; - StringRef(n->val_).getAsInteger(0, val); - expr_ = ConstantInt::get(mod_->getContext(), val); - if (n->bits_) - expr_ = B.CreateIntCast(expr_, B.getIntNTy(n->bits_), false); - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_string_expr_node(StringExprNode *n) { - if (n->is_lhs()) return mkstatus_(n, "cannot assign to a string"); - - Value *global = B.CreateGlobalString(n->val_); - Value *ptr = make_alloca(resolve_entry_stack(), B.getInt8Ty(), "", - B.getInt64(n->val_.size() + 1)); -#if LLVM_MAJOR_VERSION >= 11 - B.CreateMemCpy(ptr, Align(1), global, Align(1), n->val_.size() + 1); -#elif LLVM_MAJOR_VERSION >= 7 - B.CreateMemCpy(ptr, 1, global, 1, n->val_.size() + 1); -#else - B.CreateMemCpy(ptr, global, n->val_.size() + 1, 1); -#endif - expr_ = ptr; - - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::emit_short_circuit_and(BinopExprNode *n) { - Function *parent = B.GetInsertBlock()->getParent(); - BasicBlock *label_start = B.GetInsertBlock(); - BasicBlock *label_then = BasicBlock::Create(ctx(), "and.then", parent); - BasicBlock *label_end = BasicBlock::Create(ctx(), "and.end", parent); - - TRY2(n->lhs_->accept(this)); - Value *neq_zero = B.CreateICmpNE(pop_expr(), B.getIntN(n->lhs_->bit_width_, 0)); - B.CreateCondBr(neq_zero, label_then, label_end); - - { - BlockStack bstack(this, label_then); - TRY2(n->rhs_->accept(this)); - expr_ = B.CreateICmpNE(pop_expr(), B.getIntN(n->rhs_->bit_width_, 0)); - B.CreateBr(label_end); - } - - B.SetInsertPoint(label_end); - - PHINode *phi = B.CreatePHI(B.getInt1Ty(), 2); - phi->addIncoming(B.getFalse(), label_start); - phi->addIncoming(pop_expr(), label_then); - expr_ = phi; - - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::emit_short_circuit_or(BinopExprNode *n) { - Function *parent = B.GetInsertBlock()->getParent(); - BasicBlock *label_start = B.GetInsertBlock(); - BasicBlock *label_then = BasicBlock::Create(ctx(), "or.then", parent); - BasicBlock *label_end = BasicBlock::Create(ctx(), "or.end", parent); - - TRY2(n->lhs_->accept(this)); - Value *neq_zero = B.CreateICmpNE(pop_expr(), B.getIntN(n->lhs_->bit_width_, 0)); - B.CreateCondBr(neq_zero, label_end, label_then); - - { - BlockStack bstack(this, label_then); - TRY2(n->rhs_->accept(this)); - expr_ = B.CreateICmpNE(pop_expr(), B.getIntN(n->rhs_->bit_width_, 0)); - B.CreateBr(label_end); - } - - B.SetInsertPoint(label_end); - - PHINode *phi = B.CreatePHI(B.getInt1Ty(), 2); - phi->addIncoming(B.getTrue(), label_start); - phi->addIncoming(pop_expr(), label_then); - expr_ = phi; - - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_binop_expr_node(BinopExprNode *n) { - if (n->op_ == Tok::TAND) - return emit_short_circuit_and(n); - if (n->op_ == Tok::TOR) - return emit_short_circuit_or(n); - - TRY2(n->lhs_->accept(this)); - Value *lhs = pop_expr(); - TRY2(n->rhs_->accept(this)); - Value *rhs = B.CreateIntCast(pop_expr(), lhs->getType(), false); - switch (n->op_) { - case Tok::TCEQ: expr_ = B.CreateICmpEQ(lhs, rhs); break; - case Tok::TCNE: expr_ = B.CreateICmpNE(lhs, rhs); break; - case Tok::TXOR: expr_ = B.CreateXor(lhs, rhs); break; - case Tok::TMOD: expr_ = B.CreateURem(lhs, rhs); break; - case Tok::TCLT: expr_ = B.CreateICmpULT(lhs, rhs); break; - case Tok::TCLE: expr_ = B.CreateICmpULE(lhs, rhs); break; - case Tok::TCGT: expr_ = B.CreateICmpUGT(lhs, rhs); break; - case Tok::TCGE: expr_ = B.CreateICmpUGE(lhs, rhs); break; - case Tok::TPLUS: expr_ = B.CreateAdd(lhs, rhs); break; - case Tok::TMINUS: expr_ = B.CreateSub(lhs, rhs); break; - case Tok::TLAND: expr_ = B.CreateAnd(lhs, rhs); break; - case Tok::TLOR: expr_ = B.CreateOr(lhs, rhs); break; - default: return mkstatus_(n, "unsupported binary operator"); - } - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_unop_expr_node(UnopExprNode *n) { - TRY2(n->expr_->accept(this)); - switch (n->op_) { - case Tok::TNOT: expr_ = B.CreateNot(pop_expr()); break; - case Tok::TCMPL: expr_ = B.CreateNeg(pop_expr()); break; - default: {} - } - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_bitop_expr_node(BitopExprNode *n) { - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_goto_expr_node(GotoExprNode *n) { - if (n->id_->name_ == "DONE") { - return mkstatus_(n, "use return statement instead"); - } - string jump_label; - // when dealing with multistates, goto statements may be overridden - auto rewrite_it = proto_rewrites_.find(n->id_->full_name()); - auto default_it = proto_rewrites_.find(""); - if (rewrite_it != proto_rewrites_.end()) { - jump_label = rewrite_it->second; - } else if (default_it != proto_rewrites_.end()) { - jump_label = default_it->second; - } else { - auto state = scopes_->current_state()->lookup(n->id_->full_name(), false); - if (state) { - jump_label = state->scoped_name(); - if (n->is_continue_) { - jump_label += "_continue"; - } - } else { - state = scopes_->current_state()->lookup("EOP", false); - if (state) { - jump_label = state->scoped_name(); - } - } - } - B.CreateBr(resolve_label(jump_label)); - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_return_expr_node(ReturnExprNode *n) { - TRY2(n->expr_->accept(this)); - Function *parent = B.GetInsertBlock()->getParent(); - Value *cast_1 = B.CreateIntCast(pop_expr(), parent->getReturnType(), true); - B.CreateStore(cast_1, retval_); - B.CreateBr(resolve_label("DONE")); - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::emit_table_lookup(MethodCallExprNode *n) { - TableDeclStmtNode* table = scopes_->top_table()->lookup(n->id_->name_); - IdentExprNode* arg0 = static_cast(n->args_.at(0).get()); - IdentExprNode* arg1; - StructVariableDeclStmtNode* arg1_type; - - auto table_fd_it = table_fds_.find(table); - if (table_fd_it == table_fds_.end()) - return mkstatus_(n, "unable to find table %s in table_fds_", n->id_->c_str()); - - Function *pseudo_fn = mod_->getFunction("llvm.bpf.pseudo"); - if (!pseudo_fn) return mkstatus_(n, "pseudo fd loader doesn't exist"); - Function *lookup_fn = mod_->getFunction("bpf_map_lookup_elem_"); - if (!lookup_fn) return mkstatus_(n, "bpf_map_lookup_elem_ undefined"); - - CallInst *pseudo_call = createCall(pseudo_fn, vector({B.getInt64(BPF_PSEUDO_MAP_FD), - B.getInt64(table_fd_it->second)})); - Value *pseudo_map_fd = pseudo_call; - - TRY2(arg0->accept(this)); - Value *key_ptr = B.CreateBitCast(pop_expr(), B.getInt8PtrTy()); - - expr_ = createCall(lookup_fn, vector({pseudo_map_fd, key_ptr})); - - if (table->type_id()->name_ == "FIXED_MATCH" || table->type_id()->name_ == "INDEXED") { - if (n->args_.size() == 2) { - arg1 = static_cast(n->args_.at(1).get()); - arg1_type = static_cast(arg1->decl_); - if (table->leaf_id()->name_ != arg1_type->struct_id_->name_) { - return mkstatus_(n, "lookup pointer type mismatch %s != %s", table->leaf_id()->c_str(), - arg1_type->struct_id_->c_str()); - } - auto it = vars_.find(arg1_type); - if (it == vars_.end()) return mkstatus_(n, "Cannot locate variable %s in vars_ table", n->id_->c_str()); - expr_ = B.CreateBitCast(pop_expr(), cast(it->second->getType())->getElementType()); - B.CreateStore(pop_expr(), it->second); - } - } else { - return mkstatus_(n, "lookup in table type %s unsupported", table->type_id()->c_str()); - } - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::emit_table_update(MethodCallExprNode *n) { - TableDeclStmtNode* table = scopes_->top_table()->lookup(n->id_->name_); - IdentExprNode* arg0 = static_cast(n->args_.at(0).get()); - IdentExprNode* arg1 = static_cast(n->args_.at(1).get()); - - auto table_fd_it = table_fds_.find(table); - if (table_fd_it == table_fds_.end()) - return mkstatus_(n, "unable to find table %s in table_fds_", n->id_->c_str()); - Function *pseudo_fn = mod_->getFunction("llvm.bpf.pseudo"); - if (!pseudo_fn) return mkstatus_(n, "pseudo fd loader doesn't exist"); - Function *update_fn = mod_->getFunction("bpf_map_update_elem_"); - if (!update_fn) return mkstatus_(n, "bpf_map_update_elem_ undefined"); - - CallInst *pseudo_call = createCall(pseudo_fn, vector({B.getInt64(BPF_PSEUDO_MAP_FD), - B.getInt64(table_fd_it->second)})); - Value *pseudo_map_fd = pseudo_call; - - TRY2(arg0->accept(this)); - Value *key_ptr = B.CreateBitCast(pop_expr(), B.getInt8PtrTy()); - - if (table->type_id()->name_ == "FIXED_MATCH" || table->type_id()->name_ == "INDEXED") { - TRY2(arg1->accept(this)); - Value *value_ptr = B.CreateBitCast(pop_expr(), B.getInt8PtrTy()); - - expr_ = createCall(update_fn, vector({pseudo_map_fd, key_ptr, value_ptr, B.getInt64(BPF_ANY)})); - } else { - return mkstatus_(n, "unsupported"); - } - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::emit_table_delete(MethodCallExprNode *n) { - TableDeclStmtNode* table = scopes_->top_table()->lookup(n->id_->name_); - IdentExprNode* arg0 = static_cast(n->args_.at(0).get()); - - auto table_fd_it = table_fds_.find(table); - if (table_fd_it == table_fds_.end()) - return mkstatus_(n, "unable to find table %s in table_fds_", n->id_->c_str()); - Function *pseudo_fn = mod_->getFunction("llvm.bpf.pseudo"); - if (!pseudo_fn) return mkstatus_(n, "pseudo fd loader doesn't exist"); - Function *update_fn = mod_->getFunction("bpf_map_update_elem_"); - if (!update_fn) return mkstatus_(n, "bpf_map_update_elem_ undefined"); - - CallInst *pseudo_call = createCall(pseudo_fn, vector({B.getInt64(BPF_PSEUDO_MAP_FD), - B.getInt64(table_fd_it->second)})); - Value *pseudo_map_fd = pseudo_call; - - TRY2(arg0->accept(this)); - Value *key_ptr = B.CreateBitCast(pop_expr(), B.getInt8PtrTy()); - - if (table->type_id()->name_ == "FIXED_MATCH" || table->type_id()->name_ == "INDEXED") { - expr_ = createCall(update_fn, vector({pseudo_map_fd, key_ptr})); - } else { - return mkstatus_(n, "unsupported"); - } - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::emit_log(MethodCallExprNode *n) { - vector args; - auto arg = n->args_.begin(); - TRY2((*arg)->accept(this)); - args.push_back(pop_expr()); - args.push_back(B.getInt64(((*arg)->bit_width_ >> 3) + 1)); - ++arg; - for (; arg != n->args_.end(); ++arg) { - TRY2((*arg)->accept(this)); - args.push_back(pop_expr()); - } - - // int bpf_trace_printk(fmt, sizeof(fmt), ...) - FunctionType *printk_fn_type = FunctionType::get(B.getInt32Ty(), vector({B.getInt8PtrTy(), B.getInt64Ty()}), true); - Value *printk_fn = B.CreateIntToPtr(B.getInt64(BPF_FUNC_trace_printk), - PointerType::getUnqual(printk_fn_type)); - - expr_ = createCall(printk_fn, args); - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::emit_packet_rewrite_field(MethodCallExprNode *n) { - TRY2(n->args_[1]->accept(this)); - TRY2(n->args_[0]->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::emit_atomic_add(MethodCallExprNode *n) { - TRY2(n->args_[0]->accept(this)); - Value *lhs = B.CreateBitCast(pop_expr(), Type::getInt64PtrTy(ctx())); - TRY2(n->args_[1]->accept(this)); - Value *rhs = B.CreateSExt(pop_expr(), B.getInt64Ty()); -#if LLVM_MAJOR_VERSION >= 13 - AtomicRMWInst *atomic_inst = B.CreateAtomicRMW( - AtomicRMWInst::Add, lhs, rhs, Align(8), - AtomicOrdering::SequentiallyConsistent); -#else - AtomicRMWInst *atomic_inst = B.CreateAtomicRMW( - AtomicRMWInst::Add, lhs, rhs, AtomicOrdering::SequentiallyConsistent); -#endif - atomic_inst->setVolatile(false); - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::emit_incr_cksum(MethodCallExprNode *n, size_t sz) { - Value *is_pseudo; - string csum_fn_str; - if (n->args_.size() == 4) { - TRY2(n->args_[3]->accept(this)); - is_pseudo = B.CreateIntCast(B.CreateIsNotNull(pop_expr()), B.getInt64Ty(), false); - csum_fn_str = "bpf_l4_csum_replace_"; - } else { - is_pseudo = B.getInt64(0); - csum_fn_str = "bpf_l3_csum_replace_"; - } - - TRY2(n->args_[2]->accept(this)); - Value *new_val = B.CreateZExt(pop_expr(), B.getInt64Ty()); - TRY2(n->args_[1]->accept(this)); - Value *old_val = B.CreateZExt(pop_expr(), B.getInt64Ty()); - TRY2(n->args_[0]->accept(this)); - Value *offset = B.CreateZExt(pop_expr(), B.getInt64Ty()); - - Function *csum_fn = mod_->getFunction(csum_fn_str); - if (!csum_fn) return mkstatus_(n, "Undefined built-in %s", csum_fn_str.c_str()); - - // flags = (is_pseudo << 4) | sizeof(old_val) - Value *flags_lower = B.getInt64(sz ? sz : bits_to_size(n->args_[1]->bit_width_)); - Value *flags_upper = B.CreateShl(is_pseudo, B.getInt64(4)); - Value *flags = B.CreateOr(flags_upper, flags_lower); - - VariableDeclStmtNode *skb_decl; - Value *skb_mem; - TRY2(lookup_var(n, "skb", scopes_->current_var(), &skb_decl, &skb_mem)); - LoadInst *skb_ptr = createLoad(skb_mem); - Value *skb_ptr8 = B.CreateBitCast(skb_ptr, B.getInt8PtrTy()); - - expr_ = createCall(csum_fn, vector({skb_ptr8, offset, old_val, new_val, flags})); - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::emit_get_usec_time(MethodCallExprNode *n) { - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_method_call_expr_node(MethodCallExprNode *n) { - if (n->id_->sub_name_.size()) { - if (n->id_->sub_name_ == "lookup") { - TRY2(emit_table_lookup(n)); - } else if (n->id_->sub_name_ == "update") { - TRY2(emit_table_update(n)); - } else if (n->id_->sub_name_ == "delete") { - TRY2(emit_table_delete(n)); - } else if (n->id_->sub_name_ == "rewrite_field" && n->id_->name_ == "pkt") { - TRY2(emit_packet_rewrite_field(n)); - } - } else if (n->id_->name_ == "atomic_add") { - TRY2(emit_atomic_add(n)); - } else if (n->id_->name_ == "log") { - TRY2(emit_log(n)); - } else if (n->id_->name_ == "incr_cksum") { - TRY2(emit_incr_cksum(n)); - } else if (n->id_->name_ == "get_usec_time") { - TRY2(emit_get_usec_time(n)); - } else { - return mkstatus_(n, "unsupported"); - } - TRY2(n->block_->accept(this)); - return StatusTuple::OK(); -} - -/* result = lookup(key) - * if (!result) { - * update(key, {0}, BPF_NOEXIST) - * result = lookup(key) - * } - */ -StatusTuple CodegenLLVM::visit_table_index_expr_node(TableIndexExprNode *n) { - auto table_fd_it = table_fds_.find(n->table_); - if (table_fd_it == table_fds_.end()) - return mkstatus_(n, "unable to find table %s in table_fds_", n->id_->c_str()); - - Function *pseudo_fn = mod_->getFunction("llvm.bpf.pseudo"); - if (!pseudo_fn) return mkstatus_(n, "pseudo fd loader doesn't exist"); - Function *update_fn = mod_->getFunction("bpf_map_update_elem_"); - if (!update_fn) return mkstatus_(n, "bpf_map_update_elem_ undefined"); - Function *lookup_fn = mod_->getFunction("bpf_map_lookup_elem_"); - if (!lookup_fn) return mkstatus_(n, "bpf_map_lookup_elem_ undefined"); - StructType *leaf_type; - TRY2(lookup_struct_type(n->table_->leaf_type_, &leaf_type)); - PointerType *leaf_ptype = PointerType::getUnqual(leaf_type); - - CallInst *pseudo_call = createCall(pseudo_fn, vector({B.getInt64(BPF_PSEUDO_MAP_FD), - B.getInt64(table_fd_it->second)})); - Value *pseudo_map_fd = pseudo_call; - - TRY2(n->index_->accept(this)); - Value *key_ptr = B.CreateBitCast(pop_expr(), B.getInt8PtrTy()); - - // result = lookup(key) - Value *lookup1 = B.CreateBitCast(createCall(lookup_fn, vector({pseudo_map_fd, key_ptr})), leaf_ptype); - - Value *result = nullptr; - if (n->table_->policy_id()->name_ == "AUTO") { - Function *parent = B.GetInsertBlock()->getParent(); - BasicBlock *label_start = B.GetInsertBlock(); - BasicBlock *label_then = BasicBlock::Create(ctx(), n->id_->name_ + "[].then", parent); - BasicBlock *label_end = BasicBlock::Create(ctx(), n->id_->name_ + "[].end", parent); - - Value *eq_zero = B.CreateIsNull(lookup1); - B.CreateCondBr(eq_zero, label_then, label_end); - - B.SetInsertPoint(label_then); - // var Leaf leaf {0} - Value *leaf_ptr = B.CreateBitCast( - make_alloca(resolve_entry_stack(), leaf_type), B.getInt8PtrTy()); -#if LLVM_MAJOR_VERSION >= 10 - B.CreateMemSet(leaf_ptr, B.getInt8(0), B.getInt64(n->table_->leaf_id()->bit_width_ >> 3), MaybeAlign(1)); -#else - B.CreateMemSet(leaf_ptr, B.getInt8(0), B.getInt64(n->table_->leaf_id()->bit_width_ >> 3), 1); -#endif - // update(key, leaf) - createCall(update_fn, vector({pseudo_map_fd, key_ptr, leaf_ptr, B.getInt64(BPF_NOEXIST)})); - - // result = lookup(key) - Value *lookup2 = B.CreateBitCast(createCall(lookup_fn, vector({pseudo_map_fd, key_ptr})), leaf_ptype); - B.CreateBr(label_end); - - B.SetInsertPoint(label_end); - - PHINode *phi = B.CreatePHI(leaf_ptype, 2); - phi->addIncoming(lookup1, label_start); - phi->addIncoming(lookup2, label_then); - result = phi; - } else if (n->table_->policy_id()->name_ == "NONE") { - result = lookup1; - } - - if (n->is_lhs()) { - if (n->sub_decl_) { - Type *ptr_type = PointerType::getUnqual(B.getIntNTy(n->sub_decl_->bit_width_)); - // u64 *errval -> uN *errval - Value *err_cast = B.CreateBitCast(errval_, ptr_type); - // if valid then &field, else &errval - Function *parent = B.GetInsertBlock()->getParent(); - BasicBlock *label_start = B.GetInsertBlock(); - BasicBlock *label_then = BasicBlock::Create(ctx(), n->id_->name_ + "[]field.then", parent); - BasicBlock *label_end = BasicBlock::Create(ctx(), n->id_->name_ + "[]field.end", parent); - - if (1) { - // the PHI implementation of this doesn't load, maybe eBPF limitation? - B.CreateCondBr(B.CreateIsNull(result), label_then, label_end); - B.SetInsertPoint(label_then); - B.CreateStore(B.getInt32(2), retval_); - B.CreateBr(resolve_label("DONE")); - - B.SetInsertPoint(label_end); - vector indices({B.getInt32(0), B.getInt32(n->sub_decl_->slot_)}); - expr_ = createInBoundsGEP(result, indices); - } else { - B.CreateCondBr(B.CreateIsNotNull(result), label_then, label_end); - - B.SetInsertPoint(label_then); - vector indices({B.getInt32(0), B.getInt32(n->sub_decl_->slot_)}); - Value *field = createInBoundsGEP(result, indices); - B.CreateBr(label_end); - - B.SetInsertPoint(label_end); - PHINode *phi = B.CreatePHI(ptr_type, 2); - phi->addIncoming(err_cast, label_start); - phi->addIncoming(field, label_then); - expr_ = phi; - } - } else { - return mkstatus_(n, "unsupported"); - } - } else { - expr_ = result; - } - return StatusTuple::OK(); -} - -/// on_match -StatusTuple CodegenLLVM::visit_match_decl_stmt_node(MatchDeclStmtNode *n) { - if (n->formals_.size() != 1) - return mkstatus_(n, "on_match expected 1 arguments, %zu given", n->formals_.size()); - StructVariableDeclStmtNode* leaf_n = static_cast(n->formals_.at(0).get()); - if (!leaf_n) - return mkstatus_(n, "invalid parameter type"); - // lookup result variable - auto result_decl = scopes_->current_var()->lookup("_result", false); - if (!result_decl) return mkstatus_(n, "unable to find _result built-in"); - auto result = vars_.find(result_decl); - if (result == vars_.end()) return mkstatus_(n, "unable to find memory for _result built-in"); - vars_[leaf_n] = result->second; - - Value *load_1 = createLoad(result->second); - Value *is_null = B.CreateIsNotNull(load_1); - - Function *parent = B.GetInsertBlock()->getParent(); - BasicBlock *label_then = BasicBlock::Create(ctx(), "onvalid.then", parent); - BasicBlock *label_end = BasicBlock::Create(ctx(), "onvalid.end", parent); - B.CreateCondBr(is_null, label_then, label_end); - - { - BlockStack bstack(this, label_then); - TRY2(n->block_->accept(this)); - if (!B.GetInsertBlock()->getTerminator()) - B.CreateBr(label_end); - } - - B.SetInsertPoint(label_end); - return StatusTuple::OK(); -} - -/// on_miss -StatusTuple CodegenLLVM::visit_miss_decl_stmt_node(MissDeclStmtNode *n) { - if (n->formals_.size() != 0) - return mkstatus_(n, "on_match expected 0 arguments, %zu given", n->formals_.size()); - auto result_decl = scopes_->current_var()->lookup("_result", false); - if (!result_decl) return mkstatus_(n, "unable to find _result built-in"); - auto result = vars_.find(result_decl); - if (result == vars_.end()) return mkstatus_(n, "unable to find memory for _result built-in"); - - Value *load_1 = createLoad(result->second); - Value *is_null = B.CreateIsNull(load_1); - - Function *parent = B.GetInsertBlock()->getParent(); - BasicBlock *label_then = BasicBlock::Create(ctx(), "onvalid.then", parent); - BasicBlock *label_end = BasicBlock::Create(ctx(), "onvalid.end", parent); - B.CreateCondBr(is_null, label_then, label_end); - - { - BlockStack bstack(this, label_then); - TRY2(n->block_->accept(this)); - if (!B.GetInsertBlock()->getTerminator()) - B.CreateBr(label_end); - } - - B.SetInsertPoint(label_end); - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_failure_decl_stmt_node(FailureDeclStmtNode *n) { - return mkstatus_(n, "unsupported"); -} - -StatusTuple CodegenLLVM::visit_expr_stmt_node(ExprStmtNode *n) { - TRY2(n->expr_->accept(this)); - expr_ = nullptr; - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_struct_variable_decl_stmt_node(StructVariableDeclStmtNode *n) { - if (n->struct_id_->name_ == "" || n->struct_id_->name_[0] == '_') { - return StatusTuple::OK(); - } - - StructType *stype; - StructDeclStmtNode *decl; - TRY2(lookup_struct_type(n, &stype, &decl)); - - Type *ptr_stype = n->is_pointer() ? PointerType::getUnqual(stype) : (PointerType *)stype; - AllocaInst *ptr_a = make_alloca(resolve_entry_stack(), ptr_stype); - vars_[n] = ptr_a; - - if (n->struct_id_->scope_name_ == "proto") { - if (n->is_pointer()) { - ConstantPointerNull *const_null = ConstantPointerNull::get(cast(ptr_stype)); - B.CreateStore(const_null, ptr_a); - } else { - return mkstatus_(n, "unsupported"); - // string var = n->scope_id() + n->id_->name_; - // /* zero initialize array to be filled in with packet header */ - // emit("uint64_t __%s[%zu] = {}; uint8_t *%s = (uint8_t*)__%s;", - // var.c_str(), ((decl->bit_width_ >> 3) + 7) >> 3, var.c_str(), var.c_str()); - // for (auto it = n->init_.begin(); it != n->init_.end(); ++it) { - // auto asn = static_cast(it->get()); - // if (auto f = decl->field(asn->id_->sub_name_)) { - // size_t bit_offset = f->bit_offset_; - // size_t bit_width = f->bit_width_; - // if (asn->bitop_) { - // bit_offset += f->bit_width_ - (asn->bitop_->bit_offset_ + asn->bitop_->bit_width_); - // bit_width = std::min(bit_width - asn->bitop_->bit_offset_, asn->bitop_->bit_width_); - // } - // emit(" bpf_dins(%s + %zu, %zu, %zu, ", var.c_str(), bit_offset >> 3, bit_offset & 0x7, bit_width); - // TRY2(asn->rhs_->accept(this)); - // emit(");"); - // } - // } - } - } else { - if (n->is_pointer()) { - if (n->id_->name_ == "_result") { - // special case for capturing the return value of a previous method call - Value *cast_1 = B.CreateBitCast(pop_expr(), ptr_stype); - B.CreateStore(cast_1, ptr_a); - } else { - ConstantPointerNull *const_null = ConstantPointerNull::get(cast(ptr_stype)); - B.CreateStore(const_null, ptr_a); - } - } else { -#if LLVM_MAJOR_VERSION >= 10 - B.CreateMemSet(ptr_a, B.getInt8(0), B.getInt64(decl->bit_width_ >> 3), MaybeAlign(1)); -#else - B.CreateMemSet(ptr_a, B.getInt8(0), B.getInt64(decl->bit_width_ >> 3), 1); -#endif - if (!n->init_.empty()) { - for (auto it = n->init_.begin(); it != n->init_.end(); ++it) - TRY2((*it)->accept(this)); - } - } - } - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_integer_variable_decl_stmt_node(IntegerVariableDeclStmtNode *n) { - if (!B.GetInsertBlock()) - return StatusTuple::OK(); - - // uintX var = init - AllocaInst *ptr_a = make_alloca(resolve_entry_stack(), - B.getIntNTy(n->bit_width_), n->id_->name_); - vars_[n] = ptr_a; - - // todo - if (!n->init_.empty()) - TRY2(n->init_[0]->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_struct_decl_stmt_node(StructDeclStmtNode *n) { - ++indent_; - StructType *struct_type = StructType::create(ctx(), "_struct." + n->id_->name_); - vector fields; - for (auto it = n->stmts_.begin(); it != n->stmts_.end(); ++it) - fields.push_back(B.getIntNTy((*it)->bit_width_)); - struct_type->setBody(fields, n->is_packed()); - structs_[n] = struct_type; - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_parser_state_stmt_node(ParserStateStmtNode *n) { - string jump_label = n->scoped_name() + "_continue"; - BasicBlock *label_entry = resolve_label(jump_label); - B.SetInsertPoint(label_entry); - if (n->next_state_) - TRY2(n->next_state_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_state_decl_stmt_node(StateDeclStmtNode *n) { - if (!n->id_) - return StatusTuple::OK(); - string jump_label = n->scoped_name(); - BasicBlock *label_entry = resolve_label(jump_label); - B.SetInsertPoint(label_entry); - - auto it = n->subs_.begin(); - - scopes_->push_state(it->scope_); - - for (auto in = n->init_.begin(); in != n->init_.end(); ++in) - TRY2((*in)->accept(this)); - - if (n->subs_.size() == 1 && it->id_->name_ == "") { - // this is not a multistate protocol, emit everything and finish - TRY2(it->block_->accept(this)); - if (n->parser_) { - B.CreateBr(resolve_label(jump_label + "_continue")); - TRY2(n->parser_->accept(this)); - } - } else { - return mkstatus_(n, "unsupported"); - } - - scopes_->pop_state(); - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_table_decl_stmt_node(TableDeclStmtNode *n) { - if (n->table_type_->name_ == "Table" - || n->table_type_->name_ == "SharedTable") { - if (n->templates_.size() != 4) - return mkstatus_(n, "%s expected 4 arguments, %zu given", n->table_type_->c_str(), n->templates_.size()); - auto key = scopes_->top_struct()->lookup(n->key_id()->name_, /*search_local*/true); - if (!key) return mkstatus_(n, "cannot find key %s", n->key_id()->name_.c_str()); - auto leaf = scopes_->top_struct()->lookup(n->leaf_id()->name_, /*search_local*/true); - if (!leaf) return mkstatus_(n, "cannot find leaf %s", n->leaf_id()->name_.c_str()); - - bpf_map_type map_type = BPF_MAP_TYPE_UNSPEC; - if (n->type_id()->name_ == "FIXED_MATCH") - map_type = BPF_MAP_TYPE_HASH; - else if (n->type_id()->name_ == "INDEXED") - map_type = BPF_MAP_TYPE_ARRAY; - else - return mkstatus_(n, "Table type %s not implemented", n->type_id()->name_.c_str()); - - StructType *key_stype, *leaf_stype; - TRY2(lookup_struct_type(n->key_type_, &key_stype)); - TRY2(lookup_struct_type(n->leaf_type_, &leaf_stype)); -#if LLVM_MAJOR_VERSION >= 12 - StructType *decl_struct = StructType::getTypeByName(mod_->getContext(), "_struct." + n->id_->name_); -#else - StructType *decl_struct = mod_->getTypeByName("_struct." + n->id_->name_); -#endif - if (!decl_struct) - decl_struct = StructType::create(ctx(), "_struct." + n->id_->name_); - if (decl_struct->isOpaque()) - decl_struct->setBody(vector({key_stype, leaf_stype}), /*isPacked=*/false); - GlobalVariable *decl_gvar = new GlobalVariable(*mod_, decl_struct, false, - GlobalValue::ExternalLinkage, 0, n->id_->name_); - decl_gvar->setSection("maps"); - tables_[n] = decl_gvar; - - int map_fd = bcc_create_map(map_type, n->id_->name_.c_str(), - key->bit_width_ / 8, leaf->bit_width_ / 8, - n->size_, 0); - if (map_fd >= 0) - table_fds_[n] = map_fd; - } else { - return mkstatus_(n, "Table %s not implemented", n->table_type_->name_.c_str()); - } - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::lookup_struct_type(StructDeclStmtNode *decl, StructType **stype) const { - auto struct_it = structs_.find(decl); - if (struct_it == structs_.end()) - return mkstatus_(decl, "could not find IR for type %s", decl->id_->c_str()); - *stype = struct_it->second; - - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::lookup_struct_type(VariableDeclStmtNode *n, StructType **stype, - StructDeclStmtNode **decl) const { - if (!n->is_struct()) - return mkstatus_(n, "attempt to search for struct with a non-struct type %s", n->id_->c_str()); - - auto var = (StructVariableDeclStmtNode *)n; - StructDeclStmtNode *type; - if (var->struct_id_->scope_name_ == "proto") - type = proto_scopes_->top_struct()->lookup(var->struct_id_->name_, true); - else - type = scopes_->top_struct()->lookup(var->struct_id_->name_, true); - - if (!type) return mkstatus_(n, "could not find type %s", var->struct_id_->c_str()); - - TRY2(lookup_struct_type(type, stype)); - - if (decl) - *decl = type; - - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit_func_decl_stmt_node(FuncDeclStmtNode *n) { - if (n->formals_.size() != 1) - return mkstatus_(n, "Functions must have exactly 1 argument, %zd given", n->formals_.size()); - - vector formals; - for (auto it = n->formals_.begin(); it != n->formals_.end(); ++it) { - VariableDeclStmtNode *formal = it->get(); - if (formal->is_struct()) { - StructType *stype; - //TRY2(lookup_struct_type(formal, &stype)); - auto var = (StructVariableDeclStmtNode *)formal; -#if LLVM_MAJOR_VERSION >= 12 - stype = StructType::getTypeByName(mod_->getContext(), "_struct." + var->struct_id_->name_); -#else - stype = mod_->getTypeByName("_struct." + var->struct_id_->name_); -#endif - if (!stype) return mkstatus_(n, "could not find type %s", var->struct_id_->c_str()); - formals.push_back(PointerType::getUnqual(stype)); - } else { - formals.push_back(B.getIntNTy(formal->bit_width_)); - } - } - FunctionType *fn_type = FunctionType::get(B.getInt32Ty(), formals, /*isVarArg=*/false); - - Function *fn = mod_->getFunction(n->id_->name_); - if (fn) return mkstatus_(n, "Function %s already defined", n->id_->c_str()); - fn = Function::Create(fn_type, GlobalValue::ExternalLinkage, n->id_->name_, mod_); - fn->setCallingConv(CallingConv::C); - fn->addFnAttr(Attribute::NoUnwind); - fn->setSection(BPF_FN_PREFIX + n->id_->name_); - - BasicBlock *label_entry = BasicBlock::Create(ctx(), "entry", fn); - B.SetInsertPoint(label_entry); - string scoped_entry_label = to_string((uintptr_t)fn) + "::entry"; - labels_[scoped_entry_label] = label_entry; - BasicBlock *label_return = resolve_label("DONE"); - retval_ = make_alloca(label_entry, fn->getReturnType(), "ret"); - B.CreateStore(B.getInt32(0), retval_); - errval_ = make_alloca(label_entry, B.getInt64Ty(), "err"); - B.CreateStore(B.getInt64(0), errval_); - - auto formal = n->formals_.begin(); - for (auto arg = fn->arg_begin(); arg != fn->arg_end(); ++arg, ++formal) { - TRY2((*formal)->accept(this)); - Value *ptr = vars_[formal->get()]; - if (!ptr) return mkstatus_(n, "cannot locate memory location for arg %s", (*formal)->id_->c_str()); - B.CreateStore(&*arg, ptr); - - // Type *ptype; - // if ((*formal)->is_struct()) { - // StructType *type; - // TRY2(lookup_struct_type(formal->get(), &type)); - // ptype = PointerType::getUnqual(type); - // } else { - // ptype = PointerType::getUnqual(B.getIntNTy((*formal)->bit_width_)); - // } - - // arg->setName((*formal)->id_->name_); - // AllocaInst *ptr = make_alloca(label_entry, ptype, (*formal)->id_->name_); - // B.CreateStore(arg, ptr); - // vars_[formal->get()] = ptr; - } - - // visit function scoped variables - { - scopes_->push_state(n->scope_); - - for (auto it = scopes_->current_var()->obegin(); it != scopes_->current_var()->oend(); ++it) - TRY2((*it)->accept(this)); - - TRY2(n->block_->accept(this)); - - scopes_->pop_state(); - if (!B.GetInsertBlock()->getTerminator()) - B.CreateBr(resolve_label("DONE")); - - // always return something - B.SetInsertPoint(label_return); - B.CreateRet(createLoad(retval_)); - } - - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::visit(Node *root, TableStorage &ts, const string &id, - const string &maps_ns) { - scopes_->set_current(scopes_->top_state()); - scopes_->set_current(scopes_->top_var()); - - TRY2(print_header()); - - for (auto it = scopes_->top_table()->obegin(); it != scopes_->top_table()->oend(); ++it) - TRY2((*it)->accept(this)); - - for (auto it = scopes_->top_func()->obegin(); it != scopes_->top_func()->oend(); ++it) - TRY2((*it)->accept(this)); - //TRY2(print_parser()); - - for (auto table : tables_) { - bpf_map_type map_type = BPF_MAP_TYPE_UNSPEC; - if (table.first->type_id()->name_ == "FIXED_MATCH") - map_type = BPF_MAP_TYPE_HASH; - else if (table.first->type_id()->name_ == "INDEXED") - map_type = BPF_MAP_TYPE_ARRAY; - ts.Insert(Path({id, table.first->id_->name_}), - { - table.first->id_->name_, FileDesc(table_fds_[table.first]), map_type, - table.first->key_type_->bit_width_ >> 3, table.first->leaf_type_->bit_width_ >> 3, - table.first->size_, 0, - }); - } - return StatusTuple::OK(); -} - -StatusTuple CodegenLLVM::print_header() { - - GlobalVariable *gvar_license = new GlobalVariable(*mod_, ArrayType::get(Type::getInt8Ty(ctx()), 4), - false, GlobalValue::ExternalLinkage, 0, "_license"); - gvar_license->setSection("license"); - gvar_license->setInitializer(ConstantDataArray::getString(ctx(), "GPL", true)); - - Function *pseudo_fn = mod_->getFunction("llvm.bpf.pseudo"); - if (!pseudo_fn) { - pseudo_fn = Function::Create( - FunctionType::get(B.getInt64Ty(), vector({B.getInt64Ty(), B.getInt64Ty()}), false), - GlobalValue::ExternalLinkage, "llvm.bpf.pseudo", mod_); - } - - // declare structures - for (auto it = scopes_->top_struct()->obegin(); it != scopes_->top_struct()->oend(); ++it) { - if ((*it)->id_->name_ == "_Packet") - continue; - TRY2((*it)->accept(this)); - } - for (auto it = proto_scopes_->top_struct()->obegin(); it != proto_scopes_->top_struct()->oend(); ++it) { - if ((*it)->id_->name_ == "_Packet") - continue; - TRY2((*it)->accept(this)); - } - return StatusTuple::OK(); -} - -int CodegenLLVM::get_table_fd(const string &name) const { - TableDeclStmtNode *table = scopes_->top_table()->lookup(name); - if (!table) - return -1; - - auto table_fd_it = table_fds_.find(table); - if (table_fd_it == table_fds_.end()) - return -1; - - return table_fd_it->second; -} - -LLVMContext & CodegenLLVM::ctx() const { - return mod_->getContext(); -} - -Constant * CodegenLLVM::const_int(uint64_t val, unsigned bits, bool is_signed) { - return ConstantInt::get(ctx(), APInt(bits, val, is_signed)); -} - -Value * CodegenLLVM::pop_expr() { - Value *ret = expr_; - expr_ = nullptr; - return ret; -} - -BasicBlock * CodegenLLVM::resolve_label(const string &label) { - Function *parent = B.GetInsertBlock()->getParent(); - string scoped_label = to_string((uintptr_t)parent) + "::" + label; - auto it = labels_.find(scoped_label); - if (it != labels_.end()) return it->second; - BasicBlock *label_new = BasicBlock::Create(ctx(), label, parent); - labels_[scoped_label] = label_new; - return label_new; -} - -Instruction * CodegenLLVM::resolve_entry_stack() { - BasicBlock *label_entry = resolve_label("entry"); - return &label_entry->back(); -} - -AllocaInst *CodegenLLVM::make_alloca(Instruction *Inst, Type *Ty, - const string &name, Value *ArraySize) { - IRBuilderBase::InsertPoint ip = B.saveIP(); - B.SetInsertPoint(Inst); - AllocaInst *a = B.CreateAlloca(Ty, ArraySize, name); - B.restoreIP(ip); - return a; -} - -AllocaInst *CodegenLLVM::make_alloca(BasicBlock *BB, Type *Ty, - const string &name, Value *ArraySize) { - IRBuilderBase::InsertPoint ip = B.saveIP(); - B.SetInsertPoint(BB); - AllocaInst *a = B.CreateAlloca(Ty, ArraySize, name); - B.restoreIP(ip); - return a; -} - -} // namespace cc -} // namespace ebpf diff --git a/src/cc/frontends/b/codegen_llvm.h b/src/cc/frontends/b/codegen_llvm.h deleted file mode 100644 index 4998526e..00000000 --- a/src/cc/frontends/b/codegen_llvm.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include "node.h" -#include "scope.h" - -namespace llvm { -class AllocaInst; -template class ArrayRef; -class BasicBlock; -class BranchInst; -class CallInst; -class Constant; -class Instruction; -class IRBuilderBase; -class LLVMContext; -class LoadInst; -class Module; -class StructType; -class SwitchInst; -class Type; -class Value; -class GlobalVariable; -} - -namespace ebpf { - -class TableStorage; - -namespace cc { - -class BlockStack; -class SwitchStack; - -using std::vector; -using std::string; -using std::set; - -class CodegenLLVM : public Visitor { - friend class BlockStack; - friend class SwitchStack; - public: - CodegenLLVM(llvm::Module *mod, Scopes *scopes, Scopes *proto_scopes); - virtual ~CodegenLLVM(); - -#define VISIT(type, func) virtual STATUS_RETURN visit_##func(type* n); - EXPAND_NODES(VISIT) -#undef VISIT - - STATUS_RETURN visit(Node *n, TableStorage &ts, const std::string &id, - const std::string &maps_ns); - - int get_table_fd(const std::string &name) const; - - private: - STATUS_RETURN emit_short_circuit_and(BinopExprNode* n); - STATUS_RETURN emit_short_circuit_or(BinopExprNode* n); - STATUS_RETURN emit_table_lookup(MethodCallExprNode* n); - STATUS_RETURN emit_table_update(MethodCallExprNode* n); - STATUS_RETURN emit_table_delete(MethodCallExprNode* n); - STATUS_RETURN emit_log(MethodCallExprNode* n); - STATUS_RETURN emit_packet_rewrite_field(MethodCallExprNode* n); - STATUS_RETURN emit_atomic_add(MethodCallExprNode* n); - STATUS_RETURN emit_cksum(MethodCallExprNode* n); - STATUS_RETURN emit_incr_cksum(MethodCallExprNode* n, size_t sz = 0); - STATUS_RETURN emit_lb_hash(MethodCallExprNode* n); - STATUS_RETURN emit_sizeof(MethodCallExprNode* n); - STATUS_RETURN emit_get_usec_time(MethodCallExprNode* n); - STATUS_RETURN emit_forward_to_vnf(MethodCallExprNode* n); - STATUS_RETURN emit_forward_to_group(MethodCallExprNode* n); - STATUS_RETURN print_header(); - - llvm::LLVMContext & ctx() const; - llvm::Constant * const_int(uint64_t val, unsigned bits = 64, bool is_signed = false); - llvm::Value * pop_expr(); - llvm::BasicBlock * resolve_label(const string &label); - llvm::Instruction * resolve_entry_stack(); - llvm::AllocaInst *make_alloca(llvm::Instruction *Inst, llvm::Type *Ty, - const std::string &name = "", - llvm::Value *ArraySize = nullptr); - llvm::AllocaInst *make_alloca(llvm::BasicBlock *BB, llvm::Type *Ty, - const std::string &name = "", - llvm::Value *ArraySize = nullptr); - StatusTuple lookup_var(Node *n, const std::string &name, Scopes::VarScope *scope, - VariableDeclStmtNode **decl, llvm::Value **mem) const; - StatusTuple lookup_struct_type(StructDeclStmtNode *decl, llvm::StructType **stype) const; - StatusTuple lookup_struct_type(VariableDeclStmtNode *n, llvm::StructType **stype, - StructDeclStmtNode **decl = nullptr) const; - llvm::CallInst *createCall(llvm::Value *Callee, - llvm::ArrayRef Args); - llvm::LoadInst *createLoad(llvm::Value *Addr); - llvm::Value *createInBoundsGEP(llvm::Value *Ptr, llvm::ArrayRef IdxList); - - template void emit(const char *fmt, Args&&... params); - void emit(const char *s); - - FILE* out_; - llvm::Module* mod_; - llvm::IRBuilderBase *b_; - int indent_; - int tmp_reg_index_; - Scopes *scopes_; - Scopes *proto_scopes_; - vector > free_instructions_; - vector table_inits_; - map proto_rewrites_; - map tables_; - map table_fds_; - map vars_; - map structs_; - map labels_; - llvm::SwitchInst *cur_switch_; - llvm::Value *expr_; - llvm::AllocaInst *retval_; - llvm::AllocaInst *errval_; -}; - -} // namespace cc -} // namespace ebpf diff --git a/src/cc/frontends/b/lexer.h b/src/cc/frontends/b/lexer.h deleted file mode 100644 index 394daa33..00000000 --- a/src/cc/frontends/b/lexer.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#ifndef yyFlexLexerOnce -#undef yyFlexLexer -#define yyFlexLexer ebpfccFlexLexer -#include -#endif - -#undef YY_DECL -#define YY_DECL int ebpf::cc::Lexer::yylex() - -#include // NOLINT -#include -#include "parser.yy.hh" - -namespace ebpf { -namespace cc { - -typedef BisonParser::token::yytokentype Tok; - -class Lexer : public yyFlexLexer { - public: - explicit Lexer(std::istream* in) - : yyFlexLexer(in), prev_tok_(Tok::TSEMI), lines_({""}), yylval_(NULL), yylloc_(NULL) { - if (!in || !*in) - fprintf(stderr, "Unable to open input stream\n"); - } - int yylex(BisonParser::semantic_type *lval, BisonParser::location_type *lloc) { - yylval_ = lval; - yylloc_ = lloc; - return yylex(); - } - std::string text(const BisonParser::location_type& loc) const { - return text(loc.begin, loc.end); - } - std::string text(const position& begin, const position& end) const { - std::string result; - for (auto i = begin.line; i <= end.line; ++i) { - if (i == begin.line && i == end.line) { - result += lines_.at(i - 1).substr(begin.column - 1, end.column - begin.column); - } else if (i == begin.line && i < end.line) { - result += lines_.at(i - 1).substr(begin.column - 1); - } else if (i > begin.line && i == end.line) { - result += lines_.at(i - 1).substr(0, end.column); - } else if (i > begin.line && i == end.line) { - result += lines_.at(i - 1); - } - } - return result; - } - private: - - // true if a semicolon should be replaced here - bool next_line() { - lines_.push_back(""); - yylloc_->lines(); - yylloc_->step(); - switch (prev_tok_) { - case Tok::TIDENTIFIER: - case Tok::TINTEGER: - case Tok::THEXINTEGER: - case Tok::TRBRACE: - case Tok::TRPAREN: - case Tok::TRBRACK: - case Tok::TTRUE: - case Tok::TFALSE: - // uncomment to add implicit semicolons - //return true; - default: - break; - } - return false; - } - - Tok save(Tok tok, bool ignore_text = false) { - if (!ignore_text) { - save_text(); - } - - switch (tok) { - case Tok::TIDENTIFIER: - case Tok::TINTEGER: - case Tok::THEXINTEGER: - yylval_->string = new std::string(yytext, yyleng); - break; - default: - yylval_->token = tok; - } - prev_tok_ = tok; - return tok; - } - - /* - std::string * alloc_string(const char *c, size_t len) { - strings_.push_back(std::unique_ptr(new std::string(c, len))); - return strings_.back().get(); - } - - std::string * alloc_string(const std::string &s) { - strings_.push_back(std::unique_ptr(new std::string(s))); - return strings_.back().get(); - } - */ - - void save_text() { - lines_.back().append(yytext, yyleng); - yylloc_->columns(yyleng); - } - - int yylex(); - Tok prev_tok_; - std::vector lines_; - //std::list> strings_; - BisonParser::semantic_type *yylval_; - BisonParser::location_type *yylloc_; -}; - -} // namespace cc -} // namespace ebpf diff --git a/src/cc/frontends/b/lexer.ll b/src/cc/frontends/b/lexer.ll deleted file mode 100644 index 1072b590..00000000 --- a/src/cc/frontends/b/lexer.ll +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -%{ -#include "lexer.h" -%} - -%option yylineno nodefault yyclass="Lexer" noyywrap c++ prefix="ebpfcc" -%option never-interactive -%{ -#include -#include "parser.yy.hh" -std::string tmp_str_cc; -%} - -%x STRING_ -%% - -\" {BEGIN STRING_;} -\" { BEGIN 0; - yylval_->string = new std::string(tmp_str_cc); - tmp_str_cc = ""; - return Tok::TSTRING; - } -\\n {tmp_str_cc += "\n"; } -. {tmp_str_cc += *yytext; } - - - -[ \t]+ { save_text(); } -\n { if (next_line()) { return save(Tok::TSEMI, true); } } -"//".*\n { if (next_line()) { return save(Tok::TSEMI, true); } } -^"#" return save(Tok::TPRAGMA); -"=" return save(Tok::TEQUAL); -"==" return save(Tok::TCEQ); -"!=" return save(Tok::TCNE); -"<" return save(Tok::TCLT); -"<=" return save(Tok::TCLE); -">" return save(Tok::TCGT); -">=" return save(Tok::TCGE); -"(" return save(Tok::TLPAREN); -")" return save(Tok::TRPAREN); -"{" return save(Tok::TLBRACE); -"}" return save(Tok::TRBRACE); -"[" return save(Tok::TLBRACK); -"]" return save(Tok::TRBRACK); -"->" return save(Tok::TARROW); -"." return save(Tok::TDOT); -"," return save(Tok::TCOMMA); -"+" return save(Tok::TPLUS); -"++" return save(Tok::TINCR); -"-" return save(Tok::TMINUS); -"--" return save(Tok::TDECR); -"*" return save(Tok::TMUL); -"/" return save(Tok::TDIV); -"%" return save(Tok::TMOD); -"^" return save(Tok::TXOR); -"$" return save(Tok::TDOLLAR); -"!" return save(Tok::TNOT); -"~" return save(Tok::TCMPL); -":" return save(Tok::TCOLON); -"::" return save(Tok::TSCOPE); -";" return save(Tok::TSEMI); -"&&" return save(Tok::TAND); -"||" return save(Tok::TOR); -"&" return save(Tok::TLAND); -"|" return save(Tok::TLOR); -"@" return save(Tok::TAT); - -"case" return save(Tok::TCASE); -"continue" return save(Tok::TCONTINUE); -"else" return save(Tok::TELSE); -"false" return save(Tok::TFALSE); -"goto" return save(Tok::TGOTO); -"if" return save(Tok::TIF); -"next" return save(Tok::TNEXT); -"on_match" return save(Tok::TMATCH); -"on_miss" return save(Tok::TMISS); -"on_failure" return save(Tok::TFAILURE); -"on_valid" return save(Tok::TVALID); -"return" return save(Tok::TRETURN); -"state" return save(Tok::TSTATE); -"struct" return save(Tok::TSTRUCT); -"switch" return save(Tok::TSWITCH); -"true" return save(Tok::TTRUE); -"u8" return save(Tok::TU8); -"u16" return save(Tok::TU16); -"u32" return save(Tok::TU32); -"u64" return save(Tok::TU64); - -[a-zA-Z_][a-zA-Z0-9_]* return save(Tok::TIDENTIFIER); -[0-9]+ return save(Tok::TINTEGER); -0x[0-9a-fA-F]+ return save(Tok::THEXINTEGER); - -. printf("Unknown token \"%s\"\n", yytext); yyterminate(); - -%% diff --git a/src/cc/frontends/b/loader.cc b/src/cc/frontends/b/loader.cc deleted file mode 100644 index b7b63551..00000000 --- a/src/cc/frontends/b/loader.cc +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "common.h" -#include "parser.h" -#include "type_check.h" -#include "codegen_llvm.h" -#include "loader.h" - -using std::string; -using std::unique_ptr; -using std::vector; - -namespace ebpf { - -BLoader::BLoader(unsigned flags) : flags_(flags) { - (void)flags_; -} - -BLoader::~BLoader() { -} - -int BLoader::parse(llvm::Module *mod, const string &filename, const string &proto_filename, - TableStorage &ts, const string &id, const std::string &maps_ns) { - int rc; - - proto_parser_ = make_unique(proto_filename); - rc = proto_parser_->parse(); - if (rc) { - fprintf(stderr, "In file: %s\n", filename.c_str()); - return rc; - } - - parser_ = make_unique(filename); - rc = parser_->parse(); - if (rc) { - fprintf(stderr, "In file: %s\n", filename.c_str()); - return rc; - } - - //ebpf::cc::Printer printer(stderr); - //printer.visit(parser_->root_node_); - - ebpf::cc::TypeCheck type_check(parser_->scopes_.get(), proto_parser_->scopes_.get()); - auto ret = type_check.visit(parser_->root_node_); - if (!ret.ok() || ret.msg().size()) { - fprintf(stderr, "Type error @line=%d: %s\n", ret.code(), ret.msg().c_str()); - return -1; - } - - codegen_ = ebpf::make_unique(mod, parser_->scopes_.get(), proto_parser_->scopes_.get()); - ret = codegen_->visit(parser_->root_node_, ts, id, maps_ns); - if (!ret.ok() || ret.msg().size()) { - fprintf(stderr, "Codegen error @line=%d: %s\n", ret.code(), ret.msg().c_str()); - return ret.code(); - } - - return 0; -} - -} // namespace ebpf diff --git a/src/cc/frontends/b/loader.h b/src/cc/frontends/b/loader.h deleted file mode 100644 index 6330d5c2..00000000 --- a/src/cc/frontends/b/loader.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include - -#include "table_storage.h" - -namespace llvm { -class Module; -} - -namespace ebpf { - -namespace cc { -class Parser; -class CodegenLLVM; -} - -class BLoader { - public: - explicit BLoader(unsigned flags); - ~BLoader(); - int parse(llvm::Module *mod, const std::string &filename, const std::string &proto_filename, - TableStorage &ts, const std::string &id, const std::string &maps_ns); - - private: - unsigned flags_; - std::unique_ptr parser_; - std::unique_ptr proto_parser_; - std::unique_ptr codegen_; -}; - -} // namespace ebpf diff --git a/src/cc/frontends/b/node.cc b/src/cc/frontends/b/node.cc deleted file mode 100644 index 6dac700f..00000000 --- a/src/cc/frontends/b/node.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include - -#include "node.h" - -namespace ebpf { -namespace cc { - -#define ACCEPT(type, func) \ - STATUS_RETURN type::accept(Visitor* v) { return v->visit_##func(this); } -EXPAND_NODES(ACCEPT) -#undef ACCEPT - -VariableDeclStmtNode* StructDeclStmtNode::field(const string& name) const { - for (auto it = stmts_.begin(); it != stmts_.end(); ++it) { - if ((*it)->id_->name_ == name) { - return it->get(); - } - } - return NULL; -} - -int StructDeclStmtNode::indexof(const string& name) const { - int i = 0; - for (auto it = stmts_.begin(); it != stmts_.end(); ++it, ++i) { - if ((*it)->id_->name_ == name) { - return i; - } - } - return -1; -} - -} // namespace cc -} // namespace ebpf diff --git a/src/cc/frontends/b/node.h b/src/cc/frontends/b/node.h deleted file mode 100644 index 64905662..00000000 --- a/src/cc/frontends/b/node.h +++ /dev/null @@ -1,629 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "common.h" -#include "bcc_exception.h" -#include "scope.h" - -#define REVISION_MASK 0xfff -#define MAJOR_VER_POS 22 -#define MAJOR_VER_MASK ~((1 << MAJOR_VER_POS) - 1) -#define MINOR_VER_POS 12 -#define MINOR_VER_MASK (~((1 << MINOR_VER_POS) - 1) & (~(MAJOR_VER_MASK))) -#define GET_MAJOR_VER(version) ((version & MAJOR_VER_MASK) >> MAJOR_VER_POS) -#define GET_MINOR_VER(version) ((version & MINOR_VER_MASK) >> MINOR_VER_POS) -#define GET_REVISION(version) (version & REVISION_MASK) -#define MAKE_VERSION(major, minor, rev) \ - ((major << MAJOR_VER_POS) | \ - (minor << MINOR_VER_POS) | \ - (rev & REVISION_MASK)) - -#define STATUS_RETURN __attribute((warn_unused_result)) StatusTuple - -namespace ebpf { - -namespace cc { - -using std::unique_ptr; -using std::move; -using std::string; -using std::vector; -using std::bitset; -using std::find; - -typedef unique_ptr String; - -#define NODE_EXPRESSIONS(EXPAND) \ - EXPAND(IdentExprNode, ident_expr_node) \ - EXPAND(AssignExprNode, assign_expr_node) \ - EXPAND(PacketExprNode, packet_expr_node) \ - EXPAND(IntegerExprNode, integer_expr_node) \ - EXPAND(StringExprNode, string_expr_node) \ - EXPAND(BinopExprNode, binop_expr_node) \ - EXPAND(UnopExprNode, unop_expr_node) \ - EXPAND(BitopExprNode, bitop_expr_node) \ - EXPAND(GotoExprNode, goto_expr_node) \ - EXPAND(ReturnExprNode, return_expr_node) \ - EXPAND(MethodCallExprNode, method_call_expr_node) \ - EXPAND(TableIndexExprNode, table_index_expr_node) - -#define NODE_STATEMENTS(EXPAND) \ - EXPAND(ExprStmtNode, expr_stmt_node) \ - EXPAND(BlockStmtNode, block_stmt_node) \ - EXPAND(IfStmtNode, if_stmt_node) \ - EXPAND(OnValidStmtNode, onvalid_stmt_node) \ - EXPAND(SwitchStmtNode, switch_stmt_node) \ - EXPAND(CaseStmtNode, case_stmt_node) \ - EXPAND(StructVariableDeclStmtNode, struct_variable_decl_stmt_node) \ - EXPAND(IntegerVariableDeclStmtNode, integer_variable_decl_stmt_node) \ - EXPAND(StructDeclStmtNode, struct_decl_stmt_node) \ - EXPAND(StateDeclStmtNode, state_decl_stmt_node) \ - EXPAND(ParserStateStmtNode, parser_state_stmt_node) \ - EXPAND(MatchDeclStmtNode, match_decl_stmt_node) \ - EXPAND(MissDeclStmtNode, miss_decl_stmt_node) \ - EXPAND(FailureDeclStmtNode, failure_decl_stmt_node) \ - EXPAND(TableDeclStmtNode, table_decl_stmt_node) \ - EXPAND(FuncDeclStmtNode, func_decl_stmt_node) - -#define EXPAND_NODES(EXPAND) \ - NODE_EXPRESSIONS(EXPAND) \ - NODE_STATEMENTS(EXPAND) - -class Visitor; - -// forward declare all classes -#define FORWARD(type, func) class type; -EXPAND_NODES(FORWARD) -#undef FORWARD - -#define DECLARE(type) \ - typedef unique_ptr Ptr; \ - virtual StatusTuple accept(Visitor* v); - -class Node { - public: - typedef unique_ptr Ptr; - Node() : line_(-1), column_(-1) {} - virtual ~Node() {} - virtual StatusTuple accept(Visitor* v) = 0; - int line_; - int column_; - string text_; -}; - -template -StatusTuple mkstatus_(Node *n, const char *fmt, Args... args) { - StatusTuple status = StatusTuple(n->line_ ? n->line_ : -1, fmt, args...); - if (n->line_ > 0) - status.append_msg("\n" + n->text_); - return status; -} - -static inline StatusTuple mkstatus_(Node *n, const char *msg) { - StatusTuple status = StatusTuple(n->line_ ? n->line_ : -1, msg); - if (n->line_ > 0) - status.append_msg("\n" + n->text_); - return status; -} - -class StmtNode : public Node { - public: - typedef unique_ptr Ptr; - virtual StatusTuple accept(Visitor* v) = 0; - -}; -typedef vector StmtNodeList; - -class ExprNode : public Node { - public: - typedef unique_ptr Ptr; - virtual StatusTuple accept(Visitor* v) = 0; - enum expr_type { STRUCT, INTEGER, STRING, VOID, UNKNOWN }; - enum prop_flag { READ = 0, WRITE, PROTO, IS_LHS, IS_REF, IS_PKT, LAST }; - expr_type typeof_; - StructDeclStmtNode *struct_type_; - size_t bit_width_; - bitset flags_; - unique_ptr bitop_; - ExprNode() : typeof_(UNKNOWN), struct_type_(NULL), flags_(1 << READ) {} - void copy_type(const ExprNode& other) { - typeof_ = other.typeof_; - struct_type_ = other.struct_type_; - bit_width_ = other.bit_width_; - flags_ = other.flags_; - } - bool is_lhs() const { return flags_[IS_LHS]; } - bool is_ref() const { return flags_[IS_REF]; } - bool is_pkt() const { return flags_[IS_PKT]; } -}; - -typedef vector ExprNodeList; - -class IdentExprNode : public ExprNode { - public: - DECLARE(IdentExprNode) - - string name_; - string sub_name_; - string scope_name_; - VariableDeclStmtNode *decl_; - VariableDeclStmtNode *sub_decl_; - IdentExprNode(const IdentExprNode& other) { - name_ = other.name_; - sub_name_ = other.sub_name_; - scope_name_ = other.scope_name_; - decl_ = other.decl_; - sub_decl_ = other.sub_decl_; - } - IdentExprNode::Ptr copy() const { - return IdentExprNode::Ptr(new IdentExprNode(*this)); - } - explicit IdentExprNode(const string& id) : name_(id) {} - explicit IdentExprNode(const char* id) : name_(id) {} - void prepend_scope(const string& id) { - scope_name_ = id; - } - void append_scope(const string& id) { - scope_name_ = move(name_); - name_ = id; - } - void prepend_dot(const string& id) { - sub_name_ = move(name_); - name_ = id; - } - void append_dot(const string& id) { - // we don't support nested struct so keep all subs as single variable - if (!sub_name_.empty()) { - sub_name_ += "." + id; - } else { - sub_name_ = id; - } - } - const string& full_name() { - if (full_name_.size()) { - return full_name_; // lazy init - } - if (scope_name_.size()) { - full_name_ += scope_name_ + "::"; - } - full_name_ += name_; - if (sub_name_.size()) { - full_name_ += "." + sub_name_; - } - return full_name_; - } - const char* c_str() const { return name_.c_str(); } - private: - string full_name_; -}; - -class BitopExprNode : public ExprNode { - public: - DECLARE(BitopExprNode) - - ExprNode::Ptr expr_; - size_t bit_offset_; - size_t bit_width_; - BitopExprNode(const string& bofs, const string& bsz) - : bit_offset_(strtoul(bofs.c_str(), NULL, 0)), bit_width_(strtoul(bsz.c_str(), NULL, 0)) {} -}; - -typedef vector IdentExprNodeList; - -class AssignExprNode : public ExprNode { - public: - DECLARE(AssignExprNode) - - //IdentExprNode *id_; - ExprNode::Ptr lhs_; - ExprNode::Ptr rhs_; - AssignExprNode(IdentExprNode::Ptr id, ExprNode::Ptr rhs) - : lhs_(move(id)), rhs_(move(rhs)) { - //id_ = (IdentExprNode *)lhs_.get(); - lhs_->flags_[ExprNode::IS_LHS] = true; - } - AssignExprNode(ExprNode::Ptr lhs, ExprNode::Ptr rhs) - : lhs_(move(lhs)), rhs_(move(rhs)) { - //id_ = nullptr; - lhs_->flags_[ExprNode::IS_LHS] = true; - } -}; - -class PacketExprNode : public ExprNode { - public: - DECLARE(PacketExprNode) - - IdentExprNode::Ptr id_; - explicit PacketExprNode(IdentExprNode::Ptr id) : id_(move(id)) {} -}; - -class StringExprNode : public ExprNode { - public: - DECLARE(StringExprNode) - - string val_; - explicit StringExprNode(string *val) : val_(move(*val)) { - delete val; - } - explicit StringExprNode(const string &val) : val_(val) {} -}; - -class IntegerExprNode : public ExprNode { - public: - DECLARE(IntegerExprNode) - - size_t bits_; - string val_; - IntegerExprNode(string* val, string* bits) - : bits_(strtoul(bits->c_str(), NULL, 0)), val_(move(*val)) { - delete val; - delete bits; - } - explicit IntegerExprNode(string* val) - : bits_(0), val_(move(*val)) { - delete val; - } - explicit IntegerExprNode(const string& val) : bits_(0), val_(val) {} - explicit IntegerExprNode(const string& val, size_t bits) : bits_(bits), val_(val) {} -}; - -class BinopExprNode : public ExprNode { - public: - DECLARE(BinopExprNode) - - ExprNode::Ptr lhs_; - int op_; - ExprNode::Ptr rhs_; - BinopExprNode(ExprNode::Ptr lhs, int op, ExprNode::Ptr rhs) - : lhs_(move(lhs)), op_(op), rhs_(move(rhs)) - {} -}; - -class UnopExprNode : public ExprNode { - public: - DECLARE(UnopExprNode) - - ExprNode::Ptr expr_; - int op_; - UnopExprNode(int op, ExprNode::Ptr expr) : expr_(move(expr)), op_(op) {} -}; - -class GotoExprNode : public ExprNode { - public: - DECLARE(GotoExprNode) - - bool is_continue_; - IdentExprNode::Ptr id_; - GotoExprNode(IdentExprNode::Ptr id, bool is_continue = false) - : is_continue_(is_continue), id_(move(id)) {} -}; - -class ReturnExprNode : public ExprNode { - public: - DECLARE(ReturnExprNode) - - ExprNode::Ptr expr_; - ReturnExprNode(ExprNode::Ptr expr) - : expr_(move(expr)) {} -}; - -class BlockStmtNode : public StmtNode { - public: - DECLARE(BlockStmtNode) - - explicit BlockStmtNode(StmtNodeList stmts = StmtNodeList()) - : stmts_(move(stmts)), scope_(NULL) {} - ~BlockStmtNode() { delete scope_; } - StmtNodeList stmts_; - Scopes::VarScope* scope_; -}; - -class MethodCallExprNode : public ExprNode { - public: - DECLARE(MethodCallExprNode) - - IdentExprNode::Ptr id_; - ExprNodeList args_; - BlockStmtNode::Ptr block_; - MethodCallExprNode(IdentExprNode::Ptr id, ExprNodeList&& args, int lineno) - : id_(move(id)), args_(move(args)), block_(make_unique()) { - line_ = lineno; - } -}; - -class TableIndexExprNode : public ExprNode { - public: - DECLARE(TableIndexExprNode) - - IdentExprNode::Ptr id_; - IdentExprNode::Ptr sub_; - ExprNode::Ptr index_; - TableDeclStmtNode *table_; - VariableDeclStmtNode *sub_decl_; - TableIndexExprNode(IdentExprNode::Ptr id, ExprNode::Ptr index) - : id_(move(id)), index_(move(index)), table_(nullptr), sub_decl_(nullptr) - {} -}; - -class ExprStmtNode : public StmtNode { - public: - DECLARE(ExprStmtNode) - - ExprNode::Ptr expr_; - explicit ExprStmtNode(ExprNode::Ptr expr) : expr_(move(expr)) {} -}; - -class IfStmtNode : public StmtNode { - public: - DECLARE(IfStmtNode) - - ExprNode::Ptr cond_; - StmtNode::Ptr true_block_; - StmtNode::Ptr false_block_; - // create an if () {} expression - IfStmtNode(ExprNode::Ptr cond, StmtNode::Ptr true_block) - : cond_(move(cond)), true_block_(move(true_block)) {} - // create an if () {} else {} expression - IfStmtNode(ExprNode::Ptr cond, StmtNode::Ptr true_block, StmtNode::Ptr false_block) - : cond_(move(cond)), true_block_(move(true_block)), - false_block_(move(false_block)) {} -}; - -class OnValidStmtNode : public StmtNode { - public: - DECLARE(OnValidStmtNode) - - IdentExprNode::Ptr cond_; - StmtNode::Ptr block_; - StmtNode::Ptr else_block_; - // create an onvalid () {} expression - OnValidStmtNode(IdentExprNode::Ptr cond, StmtNode::Ptr block) - : cond_(move(cond)), block_(move(block)) {} - // create an onvalid () {} else {} expression - OnValidStmtNode(IdentExprNode::Ptr cond, StmtNode::Ptr block, StmtNode::Ptr else_block) - : cond_(move(cond)), block_(move(block)), - else_block_(move(else_block)) {} -}; - -class SwitchStmtNode : public StmtNode { - public: - DECLARE(SwitchStmtNode) - ExprNode::Ptr cond_; - BlockStmtNode::Ptr block_; - SwitchStmtNode(ExprNode::Ptr cond, BlockStmtNode::Ptr block) - : cond_(move(cond)), block_(move(block)) {} -}; - -class CaseStmtNode : public StmtNode { - public: - DECLARE(CaseStmtNode) - IntegerExprNode::Ptr value_; - BlockStmtNode::Ptr block_; - CaseStmtNode(IntegerExprNode::Ptr value, BlockStmtNode::Ptr block) - : value_(move(value)), block_(move(block)) {} - explicit CaseStmtNode(BlockStmtNode::Ptr block) : block_(move(block)) {} -}; - -class VariableDeclStmtNode : public StmtNode { - public: - typedef unique_ptr Ptr; - virtual StatusTuple accept(Visitor* v) = 0; - enum storage_type { INTEGER, STRUCT, STRUCT_REFERENCE }; - - IdentExprNode::Ptr id_; - ExprNodeList init_; - enum storage_type storage_type_; - size_t bit_width_; - size_t bit_offset_; - int slot_; - string scope_id_; - explicit VariableDeclStmtNode(IdentExprNode::Ptr id, storage_type t, size_t bit_width = 0, size_t bit_offset = 0) - : id_(move(id)), storage_type_(t), bit_width_(bit_width), bit_offset_(bit_offset), slot_(0) {} - const char* scope_id() const { return scope_id_.c_str(); } - bool is_struct() { return (storage_type_ == STRUCT || storage_type_ == STRUCT_REFERENCE); } - bool is_pointer() { return (storage_type_ == STRUCT_REFERENCE); } -}; - -typedef vector FormalList; - -class StructVariableDeclStmtNode : public VariableDeclStmtNode { - public: - DECLARE(StructVariableDeclStmtNode) - - IdentExprNode::Ptr struct_id_; - StructVariableDeclStmtNode(IdentExprNode::Ptr struct_id, IdentExprNode::Ptr id, - VariableDeclStmtNode::storage_type t = VariableDeclStmtNode::STRUCT) - : VariableDeclStmtNode(move(id), t), struct_id_(move(struct_id)) {} -}; - -class IntegerVariableDeclStmtNode : public VariableDeclStmtNode { - public: - DECLARE(IntegerVariableDeclStmtNode) - - IntegerVariableDeclStmtNode(IdentExprNode::Ptr id, const string& bits) - : VariableDeclStmtNode(move(id), VariableDeclStmtNode::INTEGER, strtoul(bits.c_str(), NULL, 0)) {} -}; - -class StructDeclStmtNode : public StmtNode { - public: - DECLARE(StructDeclStmtNode) - - IdentExprNode::Ptr id_; - FormalList stmts_; - size_t bit_width_; - bool packed_; - StructDeclStmtNode(IdentExprNode::Ptr id, FormalList&& stmts = FormalList()) - : id_(move(id)), stmts_(move(stmts)), bit_width_(0), packed_(false) {} - VariableDeclStmtNode* field(const string& name) const; - int indexof(const string& name) const; - bool is_packed() const { return packed_; } -}; - -class ParserStateStmtNode : public StmtNode { - public: - DECLARE(ParserStateStmtNode) - - IdentExprNode::Ptr id_; - StmtNode* next_state_; - string scope_id_; - explicit ParserStateStmtNode(IdentExprNode::Ptr id) - : id_(move(id)) {} - static Ptr make(const IdentExprNode::Ptr& id) { - return Ptr(new ParserStateStmtNode(id->copy())); - } - string scoped_name() const { return scope_id_ + id_->name_; } -}; - -class StateDeclStmtNode : public StmtNode { - public: - DECLARE(StateDeclStmtNode) - - struct Sub { - IdentExprNode::Ptr id_; - BlockStmtNode::Ptr block_; - ParserStateStmtNode::Ptr parser_; - Scopes::StateScope* scope_; - Sub(decltype(id_) id, decltype(block_) block, decltype(parser_) parser, decltype(scope_) scope) - : id_(move(id)), block_(move(block)), parser_(move(parser)), scope_(scope) {} - ~Sub() { delete scope_; } - Sub(Sub&& other) : scope_(NULL) { - *this = move(other); - } - Sub& operator=(Sub&& other) { - if (this == &other) { - return *this; - } - id_ = move(other.id_); - block_ = move(other.block_); - parser_ = move(other.parser_); - std::swap(scope_, other.scope_); - return *this; - } - }; - - IdentExprNode::Ptr id_; - StmtNodeList init_; - string scope_id_; - ParserStateStmtNode::Ptr parser_; - vector subs_; - StateDeclStmtNode() {} - StateDeclStmtNode(IdentExprNode::Ptr id, BlockStmtNode::Ptr block) : id_(move(id)) { - subs_.push_back(Sub(make_unique(""), move(block), ParserStateStmtNode::Ptr(), NULL)); - } - StateDeclStmtNode(IdentExprNode::Ptr id1, IdentExprNode::Ptr id2, BlockStmtNode::Ptr block) - : id_(move(id1)) { - subs_.push_back(Sub(move(id2), move(block), ParserStateStmtNode::Ptr(), NULL)); - } - string scoped_name() const { return scope_id_ + id_->name_; } - vector::iterator find_sub(const string& id) { - return find_if(subs_.begin(), subs_.end(), [&id] (const Sub& sub) { - if (sub.id_->name_ == id) - return true; - return false; - }); - - } -}; - -class MatchDeclStmtNode : public StmtNode { - public: - DECLARE(MatchDeclStmtNode) - - IdentExprNode::Ptr id_; - FormalList formals_; - BlockStmtNode::Ptr block_; - MatchDeclStmtNode(IdentExprNode::Ptr id, FormalList&& formals, BlockStmtNode::Ptr block) - : id_(move(id)), formals_(move(formals)), block_(move(block)) {} -}; - -class MissDeclStmtNode : public StmtNode { - public: - DECLARE(MissDeclStmtNode) - - IdentExprNode::Ptr id_; - FormalList formals_; - BlockStmtNode::Ptr block_; - MissDeclStmtNode(IdentExprNode::Ptr id, FormalList&& formals, BlockStmtNode::Ptr block) - : id_(move(id)), formals_(move(formals)), block_(move(block)) {} -}; - -class FailureDeclStmtNode : public StmtNode { - public: - DECLARE(FailureDeclStmtNode) - - IdentExprNode::Ptr id_; - FormalList formals_; - BlockStmtNode::Ptr block_; - FailureDeclStmtNode(IdentExprNode::Ptr id, FormalList&& formals, BlockStmtNode::Ptr block) - : id_(move(id)), formals_(move(formals)), block_(move(block)) {} -}; - -class TableDeclStmtNode : public StmtNode { - public: - DECLARE(TableDeclStmtNode) - - IdentExprNode::Ptr table_type_; - IdentExprNodeList templates_; - IdentExprNode::Ptr id_; - StructDeclStmtNode *key_type_; - StructDeclStmtNode *leaf_type_; - IdentExprNode * key_id() { return templates_.at(0).get(); } - IdentExprNode * leaf_id() { return templates_.at(1).get(); } - IdentExprNode * type_id() { return templates_.at(2).get(); } - IdentExprNode * policy_id() { return templates_.at(3).get(); } - size_t size_; - TableDeclStmtNode(IdentExprNode::Ptr table_type, IdentExprNodeList&& templates, - IdentExprNode::Ptr id, string* size) - : table_type_(move(table_type)), templates_(move(templates)), id_(move(id)), - key_type_(nullptr), leaf_type_(nullptr), size_(strtoul(size->c_str(), NULL, 0)) { - delete size; - } -}; - -class FuncDeclStmtNode : public StmtNode { - public: - DECLARE(FuncDeclStmtNode) - - IdentExprNode::Ptr id_; - FormalList formals_; - BlockStmtNode::Ptr block_; - Scopes::StateScope* scope_; - FuncDeclStmtNode(IdentExprNode::Ptr id, FormalList&& formals, BlockStmtNode::Ptr block) - : id_(move(id)), formals_(move(formals)), block_(move(block)), scope_(NULL) {} -}; - -class Visitor { - public: - typedef StatusTuple Ret; - virtual ~Visitor() {} -#define VISIT(type, func) virtual STATUS_RETURN visit_##func(type* n) = 0; - EXPAND_NODES(VISIT) -#undef VISIT -}; - -#undef DECLARE - -} // namespace cc -} // namespace ebpf diff --git a/src/cc/frontends/b/parser.cc b/src/cc/frontends/b/parser.cc deleted file mode 100644 index 8a5e1496..00000000 --- a/src/cc/frontends/b/parser.cc +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include "bcc_exception.h" -#include "parser.h" -#include "type_helper.h" - -namespace ebpf { -namespace cc { - -using std::find; -using std::move; -using std::string; -using std::unique_ptr; - -bool Parser::variable_exists(VariableDeclStmtNode *decl) const { - if (scopes_->current_var()->lookup(decl->id_->name_, SCOPE_LOCAL) == NULL) { - return false; - } - return true; -} - -VariableDeclStmtNode *Parser::variable_add(vector *types, VariableDeclStmtNode *decl) { - - if (variable_exists(decl)) { - fprintf(stderr, "redeclaration of variable %s", decl->id_->name_.c_str()); - return nullptr; - } - decl->scope_id_ = string("v") + std::to_string(scopes_->current_var()->id_) + string("_"); - scopes_->current_var()->add(decl->id_->name_, decl); - return decl; -} - -VariableDeclStmtNode *Parser::variable_add(vector *types, VariableDeclStmtNode *decl, ExprNode *init_expr) { - AssignExprNode::Ptr assign(new AssignExprNode(decl->id_->copy(), ExprNode::Ptr(init_expr))); - decl->init_.push_back(move(assign)); - - if (variable_exists(decl)) { - fprintf(stderr, "redeclaration of variable %s", decl->id_->name_.c_str()); - return nullptr; - } - decl->scope_id_ = string("v") + std::to_string(scopes_->current_var()->id_) + string("_"); - scopes_->current_var()->add(decl->id_->name_, decl); - return decl; -} - -StructVariableDeclStmtNode *Parser::variable_add(StructVariableDeclStmtNode *decl, ExprNodeList *args, bool is_kv) { - if (is_kv) { - // annotate the init expressions with the declared id - for (auto arg = args->begin(); arg != args->end(); ++arg) { - // decorate with the name of this decl - auto n = static_cast(arg->get()); - auto id = static_cast(n->lhs_.get()); - id->prepend_dot(decl->id_->name_); - } - } else { - fprintf(stderr, "must use key = value syntax\n"); - return NULL; - } - - decl->init_ = move(*args); - delete args; - - if (variable_exists(decl)) { - fprintf(stderr, "ccpg: warning: redeclaration of variable '%s'\n", decl->id_->name_.c_str()); - return nullptr; - } - decl->scope_id_ = string("v") + std::to_string(scopes_->current_var()->id_) + string("_"); - scopes_->current_var()->add(decl->id_->name_, decl); - return decl; -} - -StmtNode *Parser::state_add(Scopes::StateScope *scope, IdentExprNode *id, BlockStmtNode *body) { - if (scopes_->current_state()->lookup(id->full_name(), SCOPE_LOCAL)) { - fprintf(stderr, "redeclaration of state %s\n", id->full_name().c_str()); - // redeclaration - return NULL; - } - auto state = new StateDeclStmtNode(IdentExprNode::Ptr(id), BlockStmtNode::Ptr(body)); - // add a reference to the lower scope - state->subs_[0].scope_ = scope; - - // add me to the upper scope - scopes_->current_state()->add(state->id_->full_name(), state); - state->scope_id_ = string("s") + std::to_string(scopes_->current_state()->id_) + string("_"); - - return state; -} - -StmtNode *Parser::state_add(Scopes::StateScope *scope, IdentExprNode *id1, IdentExprNode *id2, BlockStmtNode *body) { - auto state = scopes_->current_state()->lookup(id1->full_name(), SCOPE_LOCAL); - if (!state) { - state = new StateDeclStmtNode(IdentExprNode::Ptr(id1), IdentExprNode::Ptr(id2), BlockStmtNode::Ptr(body)); - // add a reference to the lower scope - state->subs_[0].scope_ = scope; - - // add me to the upper scope - scopes_->current_state()->add(state->id_->full_name(), state); - state->scope_id_ = string("s") + std::to_string(scopes_->current_state()->id_) + string("_"); - return state; - } else { - if (state->find_sub(id2->name_) != state->subs_.end()) { - fprintf(stderr, "redeclaration of state %s, %s\n", id1->full_name().c_str(), id2->full_name().c_str()); - return NULL; - } - state->subs_.push_back(StateDeclStmtNode::Sub(IdentExprNode::Ptr(id2), BlockStmtNode::Ptr(body), - ParserStateStmtNode::Ptr(), scope)); - delete id1; - - return new StateDeclStmtNode(); // stub - } -} - -bool Parser::table_exists(TableDeclStmtNode *decl, bool search_local) { - if (scopes_->top_table()->lookup(decl->id_->name_, search_local) == NULL) { - return false; - } - return true; -} - -StmtNode *Parser::table_add(IdentExprNode *type, IdentExprNodeList *templates, - IdentExprNode *id, string *size) { - auto table = new TableDeclStmtNode(IdentExprNode::Ptr(type), - move(*templates), - IdentExprNode::Ptr(id), size); - if (table_exists(table, true)) { - fprintf(stderr, "redeclaration of table %s\n", id->name_.c_str()); - return table; - } - scopes_->top_table()->add(id->name_, table); - return table; -} - -StmtNode * Parser::struct_add(IdentExprNode *type, FormalList *formals) { - auto struct_decl = new StructDeclStmtNode(IdentExprNode::Ptr(type), move(*formals)); - if (scopes_->top_struct()->lookup(type->name_, SCOPE_LOCAL) != NULL) { - fprintf(stderr, "redeclaration of struct %s\n", type->name_.c_str()); - return struct_decl; - } - - auto pr_it = pragmas_.find("packed"); - if (pr_it != pragmas_.end() && pr_it->second == "true") - struct_decl->packed_ = true; - - int i = 0; - size_t offset = 0; - for (auto it = struct_decl->stmts_.begin(); it != struct_decl->stmts_.end(); ++it, ++i) { - FieldType ft = bits_to_enum((*it)->bit_width_); - offset = struct_decl->is_packed() ? offset : align_offset(offset, ft); - (*it)->slot_ = i; - (*it)->bit_offset_ = offset; - offset += (*it)->bit_width_; - } - struct_decl->bit_width_ = struct_decl->is_packed() ? offset : align_offset(offset, UINT32_T); - - scopes_->top_struct()->add(type->name_, struct_decl); - return struct_decl; -} - -StmtNode * Parser::result_add(int token, IdentExprNode *id, FormalList *formals, BlockStmtNode *body) { - StmtNode *stmt = NULL; - switch (token) { - case Tok::TMATCH: - stmt = new MatchDeclStmtNode(IdentExprNode::Ptr(id), move(*formals), BlockStmtNode::Ptr(body)); - break; - case Tok::TMISS: - stmt = new MissDeclStmtNode(IdentExprNode::Ptr(id), move(*formals), BlockStmtNode::Ptr(body)); - break; - case Tok::TFAILURE: - stmt = new FailureDeclStmtNode(IdentExprNode::Ptr(id), move(*formals), BlockStmtNode::Ptr(body)); - break; - default: - {} - } - return stmt; -} - -StmtNode * Parser::func_add(vector *types, Scopes::StateScope *scope, - IdentExprNode *id, FormalList *formals, BlockStmtNode *body) { - auto decl = new FuncDeclStmtNode(IdentExprNode::Ptr(id), move(*formals), BlockStmtNode::Ptr(body)); - if (scopes_->top_func()->lookup(decl->id_->name_, SCOPE_LOCAL)) { - fprintf(stderr, "redeclaration of func %s\n", id->name_.c_str()); - return decl; - } - auto cur_scope = scopes_->current_var(); - scopes_->set_current(scope); - for (auto it = formals->begin(); it != formals->end(); ++it) - if (!variable_add(nullptr, it->get())) { - delete decl; - return nullptr; - } - scopes_->set_current(cur_scope); - decl->scope_ = scope; - scopes_->top_func()->add(id->name_, decl); - return decl; -} - -void Parser::set_loc(Node *n, const BisonParser::location_type &loc) const { - n->line_ = loc.begin.line; - n->column_ = loc.begin.column; - n->text_ = lexer.text(loc); -} - -string Parser::pragma(const string &name) const { - auto it = pragmas_.find(name); - if (it == pragmas_.end()) return "main"; - return it->second; -} - -} // namespace cc -} // namespace ebpf diff --git a/src/cc/frontends/b/parser.h b/src/cc/frontends/b/parser.h deleted file mode 100644 index 21338b53..00000000 --- a/src/cc/frontends/b/parser.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include // NOLINT -#include "node.h" -#include "lexer.h" -#include "scope.h" - -namespace ebpf { -namespace cc { - -using std::pair; -using std::string; -using std::vector; - -class Parser { - public: - explicit Parser(const string& infile) - : root_node_(NULL), scopes_(new Scopes), in_(infile), lexer(&in_), parser(lexer, *this) { - // parser.set_debug_level(1); - } - ~Parser() { delete root_node_; } - int parse() { - return parser.parse(); - } - - VariableDeclStmtNode * variable_add(vector *types, VariableDeclStmtNode *decl); - VariableDeclStmtNode * variable_add(vector *types, VariableDeclStmtNode *decl, ExprNode *init_expr); - StructVariableDeclStmtNode * variable_add(StructVariableDeclStmtNode *decl, ExprNodeList *args, bool is_kv); - StmtNode * state_add(Scopes::StateScope *scope, IdentExprNode *id1, BlockStmtNode *body); - StmtNode * state_add(Scopes::StateScope *scope, IdentExprNode *id1, IdentExprNode *id2, BlockStmtNode *body); - StmtNode * func_add(std::vector *types, Scopes::StateScope *scope, - IdentExprNode *id, FormalList *formals, BlockStmtNode *body); - StmtNode * table_add(IdentExprNode *type, IdentExprNodeList *templates, IdentExprNode *id, string *size); - StmtNode * struct_add(IdentExprNode *type, FormalList *formals); - StmtNode * result_add(int token, IdentExprNode *id, FormalList *formals, BlockStmtNode *body); - bool variable_exists(VariableDeclStmtNode *decl) const; - bool table_exists(TableDeclStmtNode *decl, bool search_local = true); - void add_pragma(const std::string& pr, const std::string& v) { pragmas_[pr] = v; } - void set_loc(Node *n, const BisonParser::location_type &loc) const; - std::string pragma(const std::string &name) const; - - Node *root_node_; - Scopes::Ptr scopes_; - std::map pragmas_; - private: - std::ifstream in_; - Lexer lexer; - BisonParser parser; -}; - -} // namespace cc -} // namespace ebpf diff --git a/src/cc/frontends/b/parser.yy b/src/cc/frontends/b/parser.yy deleted file mode 100644 index e6d1592c..00000000 --- a/src/cc/frontends/b/parser.yy +++ /dev/null @@ -1,629 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -%skeleton "lalr1.cc" -%defines -%define namespace "ebpf::cc" -%define parser_class_name "BisonParser" -%parse-param { ebpf::cc::Lexer &lexer } -%parse-param { ebpf::cc::Parser &parser } -%lex-param { ebpf::cc::Lexer &lexer } -%locations - -%code requires { - #include - #include - #include - #include "node.h" - // forward declaration - namespace ebpf { namespace cc { - class Lexer; - class Parser; - } } -} - -%code { - static int yylex(ebpf::cc::BisonParser::semantic_type *yylval, - ebpf::cc::BisonParser::location_type *yylloc, - ebpf::cc::Lexer &lexer); -} - -%{ - #include "node.h" - #include "parser.h" - using std::unique_ptr; - using std::vector; - using std::string; - using std::move; -%} - -%union { - Scopes::StateScope *state_scope; - Scopes::VarScope *var_scope; - BlockStmtNode *block; - ExprNode *expr; - MethodCallExprNode *call; - StmtNode *stmt; - IdentExprNode *ident; - IntegerExprNode *numeric; - BitopExprNode *bitop; - ExprNodeList *args; - IdentExprNodeList *ident_args; - StmtNodeList *stmts; - FormalList *formals; - VariableDeclStmtNode *decl; - StructVariableDeclStmtNode *type_decl; - TableIndexExprNode *table_index; - std::vector *type_specifiers; - std::string* string; - int token; -} - -/* Define the terminal symbols. */ -%token TIDENTIFIER TINTEGER THEXINTEGER TPRAGMA TSTRING -%token TU8 TU16 TU32 TU64 -%token TEQUAL TCEQ TCNE TCLT TCLE TCGT TCGE TAND TOR -%token TLPAREN TRPAREN TLBRACE TRBRACE TLBRACK TRBRACK -%token TDOT TARROW TCOMMA TPLUS TMINUS TMUL TDIV TMOD TXOR TDOLLAR TCOLON TSCOPE TNOT TSEMI TCMPL TLAND TLOR -%token TSTRUCT TSTATE TFUNC TGOTO TCONTINUE TNEXT TTRUE TFALSE TRETURN -%token TIF TELSE TSWITCH TCASE -%token TMATCH TMISS TFAILURE TVALID -%token TAT - -/* Define non-terminal symbols as defined in the above union */ -%type ident scoped_ident dotted_ident any_ident -%type expr assign_expr return_expr init_arg_kv -%type numeric -%type bitop -%type call_args /*init_args*/ init_args_kv -%type table_decl_args -%type struct_decl_stmts formals -%type program block prog_decls -%type decl_stmt int_decl ref_stmt -%type type_decl ptr_decl -%type stmt prog_decl var_decl struct_decl state_decl func_decl -%type table_decl table_result_stmt if_stmt switch_stmt case_stmt onvalid_stmt -%type enter_varscope exit_varscope -%type enter_statescope exit_statescope -%type stmts table_result_stmts case_stmts -%type call_expr -%type table_index_expr -%type type_specifiers -%type pragma_decl -%type type_specifier - -/* taken from C++ operator precedence wiki page */ -%nonassoc TSCOPE -%left TDOT TLBRACK TLBRACE TLPAREN TINCR TDECR -%right TNOT TCMPL -%left TMUL -%left TDIV -%left TMOD -%left TPLUS -%left TMINUS -%left TCLT TCLE TCGT TCGE -%left TCEQ -%left TCNE -%left TXOR -%left TAND -%left TOR -%left TLAND -%left TLOR -%right TEQUAL - -%start program - -%% - -program - : enter_statescope enter_varscope prog_decls exit_varscope exit_statescope - { parser.root_node_ = $3; $3->scope_ = $2; } - ; - -/* program is a list of declarations */ -prog_decls - : prog_decl - { $$ = new BlockStmtNode; $$->stmts_.push_back(StmtNode::Ptr($1)); } - | prog_decls prog_decl - { $1->stmts_.push_back(StmtNode::Ptr($2)); } - ; - -/* - possible program declarations are: - "struct {}" - "state|on_miss|on_match|on_valid {}" - "var " - "Table <...> (size)" - */ -prog_decl - : var_decl TSEMI - | struct_decl TSEMI - | state_decl - | table_decl TSEMI - | pragma_decl - | func_decl - ; - -pragma_decl - : TPRAGMA TIDENTIFIER TIDENTIFIER - { $$ = new BlockStmtNode; parser.add_pragma(*$2, *$3); delete $2; delete $3; } - | TPRAGMA TIDENTIFIER TSTRING - { $$ = new BlockStmtNode; parser.add_pragma(*$2, *$3); delete $2; delete $3; } - ; - -stmts - : stmt - { $$ = new StmtNodeList; $$->push_back(StmtNode::Ptr($1)); } - | stmts stmt - { $1->push_back(StmtNode::Ptr($2)); } - ; - -stmt - : expr TSEMI - { $$ = new ExprStmtNode(ExprNode::Ptr($1)); - parser.set_loc($$, @$); } - | assign_expr TSEMI - { $$ = new ExprStmtNode(ExprNode::Ptr($1)); - parser.set_loc($$, @$); } - | return_expr TSEMI - { $$ = new ExprStmtNode(ExprNode::Ptr($1)); - parser.set_loc($$, @$); } - | call_expr TLBRACE enter_varscope table_result_stmts exit_varscope TRBRACE TSEMI - { $$ = new ExprStmtNode(ExprNode::Ptr($1)); - $1->block_->stmts_ = move(*$4); delete $4; - $1->block_->scope_ = $3; - parser.set_loc($$, @$); } - | call_expr TLBRACE TRBRACE TSEMI // support empty curly braces - { $$ = new ExprStmtNode(ExprNode::Ptr($1)); - parser.set_loc($$, @$); } - | if_stmt - | switch_stmt - | var_decl TSEMI - { $$ = $1; } - | state_decl - | onvalid_stmt - ; - -call_expr - : any_ident TLPAREN call_args TRPAREN - { $$ = new MethodCallExprNode(IdentExprNode::Ptr($1), move(*$3), lexer.lineno()); delete $3; - parser.set_loc($$, @$); } - ; - -block - : TLBRACE stmts TRBRACE - { $$ = new BlockStmtNode; $$->stmts_ = move(*$2); delete $2; - parser.set_loc($$, @$); } - | TLBRACE TRBRACE - { $$ = new BlockStmtNode; - parser.set_loc($$, @$); } - ; - -enter_varscope : /* empty */ { $$ = parser.scopes_->enter_var_scope(); } ; -exit_varscope : /* empty */ { $$ = parser.scopes_->exit_var_scope(); } ; -enter_statescope : /* empty */ { $$ = parser.scopes_->enter_state_scope(); } ; -exit_statescope : /* empty */ { $$ = parser.scopes_->exit_state_scope(); } ; - -struct_decl - : TSTRUCT ident TLBRACE struct_decl_stmts TRBRACE - { $$ = parser.struct_add($2, $4); delete $4; - parser.set_loc($$, @$); } - ; - -struct_decl_stmts - : type_specifiers decl_stmt TSEMI - { $$ = new FormalList; $$->push_back(VariableDeclStmtNode::Ptr($2)); } - | struct_decl_stmts type_specifiers decl_stmt TSEMI - { $1->push_back(VariableDeclStmtNode::Ptr($3)); } - ; - -table_decl - : ident TCLT table_decl_args TCGT ident TLPAREN TINTEGER TRPAREN - { $$ = parser.table_add($1, $3, $5, $7); delete $3; - parser.set_loc($$, @$); } - ; - -table_decl_args - : ident - { $$ = new IdentExprNodeList; $$->push_back(IdentExprNode::Ptr($1)); } - | table_decl_args TCOMMA ident - { $$->push_back(IdentExprNode::Ptr($3)); } - ; - -state_decl - : TSTATE scoped_ident enter_statescope enter_varscope block exit_varscope exit_statescope - { $$ = parser.state_add($3, $2, $5); $5->scope_ = $4; - if (!$$) YYERROR; - parser.set_loc($$, @$); } - | TSTATE scoped_ident TCOMMA TMUL enter_statescope enter_varscope block exit_varscope exit_statescope - { $$ = parser.state_add($5, $2, new IdentExprNode(""), $7); $7->scope_ = $6; - if (!$$) YYERROR; - parser.set_loc($$, @$); } - | TSTATE scoped_ident TCOMMA scoped_ident enter_statescope enter_varscope block exit_varscope exit_statescope - { $$ = parser.state_add($5, $2, $4, $7); $7->scope_ = $6; - if (!$$) YYERROR; - parser.set_loc($$, @$); } - ; - -func_decl - : type_specifiers ident enter_statescope enter_varscope TLPAREN formals TRPAREN block exit_varscope exit_statescope - { $$ = parser.func_add($1, $3, $2, $6, $8); $8->scope_ = $4; - if (!$$) YYERROR; - parser.set_loc($$, @$); } - ; - -table_result_stmts - : table_result_stmt - { $$ = new StmtNodeList; $$->push_back(StmtNode::Ptr($1)); } - | table_result_stmts table_result_stmt - { $$->push_back(StmtNode::Ptr($2)); } - ; - -table_result_stmt - : TMATCH ident enter_varscope TLPAREN formals TRPAREN block exit_varscope TSEMI - { $$ = parser.result_add($1, $2, $5, $7); delete $5; $7->scope_ = $3; - if (!$$) YYERROR; - parser.set_loc($$, @$); } - | TMISS ident enter_varscope TLPAREN TRPAREN block exit_varscope TSEMI - { $$ = parser.result_add($1, $2, new FormalList, $6); $6->scope_ = $3; - if (!$$) YYERROR; - parser.set_loc($$, @$); } - | TFAILURE ident enter_varscope TLPAREN formals TRPAREN block exit_varscope TSEMI - { $$ = parser.result_add($1, $2, $5, $7); delete $5; $7->scope_ = $3; - if (!$$) YYERROR; - parser.set_loc($$, @$); } - ; - -formals - : TSTRUCT ptr_decl - { $$ = new FormalList; $$->push_back(VariableDeclStmtNode::Ptr(parser.variable_add(nullptr, $2))); } - | formals TCOMMA TSTRUCT ptr_decl - { $1->push_back(VariableDeclStmtNode::Ptr(parser.variable_add(nullptr, $4))); } - ; - -type_specifier - : TU8 - | TU16 - | TU32 - | TU64 - ; - -type_specifiers - : type_specifier { $$ = new std::vector; $$->push_back($1); } - | type_specifiers type_specifier { $$->push_back($2); } - ; - -var_decl - : type_specifiers decl_stmt - { $$ = parser.variable_add($1, $2); - if (!$$) YYERROR; - parser.set_loc($$, @$); } - | type_specifiers int_decl TEQUAL expr - { $$ = parser.variable_add($1, $2, $4); - if (!$$) YYERROR; - parser.set_loc($$, @$); } - | TSTRUCT type_decl TEQUAL TLBRACE init_args_kv TRBRACE - { $$ = parser.variable_add($2, $5, true); - if (!$$) YYERROR; - parser.set_loc($$, @$); } - /*| TSTRUCT type_decl TEQUAL TLBRACE init_args TRBRACE - { $$ = parser.variable_add($2, $5, false); - parser.set_loc($$, @$); }*/ - | TSTRUCT ref_stmt - { $$ = parser.variable_add(nullptr, $2); - if (!$$) YYERROR; - parser.set_loc($$, @$); } - ; - -/* "id":"bitsize" or "type" "id" */ -decl_stmt : int_decl { $$ = $1; } | type_decl { $$ = $1; }; -int_decl : ident TCOLON TINTEGER - { $$ = new IntegerVariableDeclStmtNode(IdentExprNode::Ptr($1), *$3); delete $3; - parser.set_loc($$, @$); } - ; - -type_decl : scoped_ident ident - { $$ = new StructVariableDeclStmtNode(IdentExprNode::Ptr($1), IdentExprNode::Ptr($2)); - parser.set_loc($$, @$); } - ; - -/* "type" "*" "id" */ -ref_stmt : ptr_decl { $$ = $1; }; -ptr_decl : scoped_ident TMUL ident - { $$ = new StructVariableDeclStmtNode(IdentExprNode::Ptr($1), IdentExprNode::Ptr($3), - VariableDeclStmtNode::STRUCT_REFERENCE); - parser.set_loc($$, @$); } - ; - -/* normal initializer */ -/* init_args - : expr { $$ = new ExprNodeList; $$->push_back(ExprNode::Ptr($1)); } - | init_args TCOMMA expr { $$->push_back(ExprNode::Ptr($3)); } - ;*/ - -/* one or more of "field" = "expr" */ -init_args_kv - : init_arg_kv { $$ = new ExprNodeList; $$->push_back(ExprNode::Ptr($1)); } - | init_args_kv TCOMMA init_arg_kv { $$->push_back(ExprNode::Ptr($3)); } - ; -init_arg_kv - : TDOT ident TEQUAL expr - { $$ = new AssignExprNode(IdentExprNode::Ptr($2), ExprNode::Ptr($4)); - parser.set_loc($$, @$); } - | TDOT ident bitop TEQUAL expr - { $$ = new AssignExprNode(IdentExprNode::Ptr($2), ExprNode::Ptr($5)); $$->bitop_ = BitopExprNode::Ptr($3); - parser.set_loc($$, @$); } - ; - -if_stmt - : TIF expr enter_varscope block exit_varscope - { $$ = new IfStmtNode(ExprNode::Ptr($2), StmtNode::Ptr($4)); - $4->scope_ = $3; - parser.set_loc($$, @$); } - | TIF expr enter_varscope block exit_varscope TELSE enter_varscope block exit_varscope - { $$ = new IfStmtNode(ExprNode::Ptr($2), StmtNode::Ptr($4), StmtNode::Ptr($8)); - $4->scope_ = $3; $8->scope_ = $7; - parser.set_loc($$, @$); } - | TIF expr enter_varscope block exit_varscope TELSE if_stmt - { $$ = new IfStmtNode(ExprNode::Ptr($2), StmtNode::Ptr($4), StmtNode::Ptr($7)); - $4->scope_ = $3; - parser.set_loc($$, @$); } - ; - -onvalid_stmt - : TVALID TLPAREN ident TRPAREN enter_varscope block exit_varscope - { $$ = new OnValidStmtNode(IdentExprNode::Ptr($3), StmtNode::Ptr($6)); - $6->scope_ = $5; - parser.set_loc($$, @$); } - | TVALID TLPAREN ident TRPAREN enter_varscope block exit_varscope TELSE enter_varscope block exit_varscope - { $$ = new OnValidStmtNode(IdentExprNode::Ptr($3), StmtNode::Ptr($6), StmtNode::Ptr($10)); - $6->scope_ = $5; $10->scope_ = $9; - parser.set_loc($$, @$); } - ; - -switch_stmt - : TSWITCH expr TLBRACE case_stmts TRBRACE - { $$ = new SwitchStmtNode(ExprNode::Ptr($2), make_unique(move(*$4))); delete $4; - parser.set_loc($$, @$); } - ; - -case_stmts - : case_stmt - { $$ = new StmtNodeList; $$->push_back(StmtNode::Ptr($1)); } - | case_stmts case_stmt - { $$->push_back(StmtNode::Ptr($2)); } - ; - -case_stmt - : TCASE numeric block TSEMI - { $$ = new CaseStmtNode(IntegerExprNode::Ptr($2), BlockStmtNode::Ptr($3)); - parser.set_loc($$, @$); } - | TCASE TMUL block TSEMI - { $$ = new CaseStmtNode(BlockStmtNode::Ptr($3)); - parser.set_loc($$, @$); } - ; - -numeric - : TINTEGER - { $$ = new IntegerExprNode($1); - parser.set_loc($$, @$); } - | THEXINTEGER - { $$ = new IntegerExprNode($1); - parser.set_loc($$, @$); } - | TINTEGER TCOLON TINTEGER - { $$ = new IntegerExprNode($1, $3); - parser.set_loc($$, @$); } - | THEXINTEGER TCOLON TINTEGER - { $$ = new IntegerExprNode($1, $3); - parser.set_loc($$, @$); } - | TTRUE - { $$ = new IntegerExprNode(new string("1"), new string("1")); - parser.set_loc($$, @$); } - | TFALSE - { $$ = new IntegerExprNode(new string("0"), new string("1")); - parser.set_loc($$, @$); } - ; - -assign_expr - : expr TEQUAL expr - { $$ = new AssignExprNode(ExprNode::Ptr($1), ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - /* The below has a reduce/reduce conflict. - TODO: ensure the above is handled in the type check properly */ - /*| dotted_ident TEQUAL expr - { $$ = new AssignExprNode(IdentExprNode::Ptr($1), ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | dotted_ident bitop TEQUAL expr - { $$ = new AssignExprNode(IdentExprNode::Ptr($1), ExprNode::Ptr($4)); $$->bitop_ = BitopExprNode::Ptr($2); - parser.set_loc($$, @$); }*/ - ; - -return_expr - : TRETURN expr - { $$ = new ReturnExprNode(ExprNode::Ptr($2)); - parser.set_loc($$, @$); } - ; - -expr - : call_expr - { $$ = $1; } - | call_expr bitop - { $$ = $1; $$->bitop_ = BitopExprNode::Ptr($2); } - | table_index_expr - { $$ = $1; } - | table_index_expr TDOT ident - { $$ = $1; $1->sub_ = IdentExprNode::Ptr($3); } - | any_ident - { $$ = $1; } - | TAT dotted_ident - { $$ = new PacketExprNode(IdentExprNode::Ptr($2)); - $$->flags_[ExprNode::IS_REF] = true; - parser.set_loc($$, @$); } - | TDOLLAR dotted_ident - { $$ = new PacketExprNode(IdentExprNode::Ptr($2)); - $$->flags_[ExprNode::IS_PKT] = true; - parser.set_loc($$, @$); } - | TDOLLAR dotted_ident bitop - { $$ = new PacketExprNode(IdentExprNode::Ptr($2)); $$->bitop_ = BitopExprNode::Ptr($3); - $$->flags_[ExprNode::IS_PKT] = true; - parser.set_loc($$, @$); } - | TGOTO scoped_ident - { $$ = new GotoExprNode(IdentExprNode::Ptr($2), false); - parser.set_loc($$, @$); } - | TNEXT scoped_ident - { $$ = new GotoExprNode(IdentExprNode::Ptr($2), false); - parser.set_loc($$, @$); } - | TCONTINUE scoped_ident - { $$ = new GotoExprNode(IdentExprNode::Ptr($2), true); - parser.set_loc($$, @$); } - | TLPAREN expr TRPAREN - { $$ = $2; } - | TLPAREN expr TRPAREN bitop - { $$ = $2; $$->bitop_ = BitopExprNode::Ptr($4); } - | TSTRING - { $$ = new StringExprNode($1); - parser.set_loc($$, @$); } - | numeric - { $$ = $1; } - | numeric bitop - { $$ = $1; $$->bitop_ = BitopExprNode::Ptr($2); } - | expr TCLT expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | expr TCGT expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | expr TCGE expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | expr TCLE expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | expr TCNE expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | expr TCEQ expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | expr TPLUS expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | expr TMINUS expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | expr TMUL expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | expr TDIV expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | expr TMOD expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | expr TXOR expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | expr TAND expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | expr TOR expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | expr TLAND expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - | expr TLOR expr - { $$ = new BinopExprNode(ExprNode::Ptr($1), $2, ExprNode::Ptr($3)); - parser.set_loc($$, @$); } - /*| expr bitop - { $$ = $1; $$->bitop_ = BitopExprNode::Ptr($2); }*/ - | TNOT expr - { $$ = new UnopExprNode($1, ExprNode::Ptr($2)); - parser.set_loc($$, @$); } - | TCMPL expr - { $$ = new UnopExprNode($1, ExprNode::Ptr($2)); - parser.set_loc($$, @$); } - ; - -call_args - : /* empty */ - { $$ = new ExprNodeList; } - | expr - { $$ = new ExprNodeList; $$->push_back(ExprNode::Ptr($1)); } - | call_args TCOMMA expr - { $$->push_back(ExprNode::Ptr($3)); } - ; - -bitop - : TLBRACK TCOLON TPLUS TINTEGER TRBRACK - { $$ = new BitopExprNode(string("0"), *$4); delete $4; - parser.set_loc($$, @$); } - | TLBRACK TINTEGER TCOLON TPLUS TINTEGER TRBRACK - { $$ = new BitopExprNode(*$2, *$5); delete $2; delete $5; - parser.set_loc($$, @$); } - ; - -table_index_expr - : dotted_ident TLBRACK ident TRBRACK - { $$ = new TableIndexExprNode(IdentExprNode::Ptr($1), IdentExprNode::Ptr($3)); - parser.set_loc($$, @$); } - ; - -scoped_ident - : ident - { $$ = $1; } - | scoped_ident TSCOPE TIDENTIFIER - { $$->append_scope(*$3); delete $3; } - ; - -dotted_ident - : ident - { $$ = $1; } - | dotted_ident TDOT TIDENTIFIER - { $$->append_dot(*$3); delete $3; } - ; - -any_ident - : ident - { $$ = $1; } - | dotted_ident TARROW TIDENTIFIER - { $$->append_dot(*$3); delete $3; } - | dotted_ident TDOT TIDENTIFIER - { $$->append_dot(*$3); delete $3; } - | scoped_ident TSCOPE TIDENTIFIER - { $$->append_scope(*$3); delete $3; } - ; - -ident - : TIDENTIFIER - { $$ = new IdentExprNode(*$1); delete $1; - parser.set_loc($$, @$); } - ; - -%% - -void ebpf::cc::BisonParser::error(const ebpf::cc::BisonParser::location_type &loc, - const string& msg) { - std::cerr << "Error: " << loc << " " << msg << std::endl; -} - -#include "lexer.h" -static int yylex(ebpf::cc::BisonParser::semantic_type *yylval, - ebpf::cc::BisonParser::location_type *yylloc, - ebpf::cc::Lexer &lexer) { - return lexer.yylex(yylval, yylloc); -} - diff --git a/src/cc/frontends/b/printer.cc b/src/cc/frontends/b/printer.cc deleted file mode 100644 index 75ff9071..00000000 --- a/src/cc/frontends/b/printer.cc +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "printer.h" -#include "lexer.h" -#include "bcc_exception.h" - -namespace ebpf { -namespace cc { - -void Printer::print_indent() { - fprintf(out_, "%*s", indent_, ""); -} - -StatusTuple Printer::visit_block_stmt_node(BlockStmtNode* n) { - fprintf(out_, "{\n"); - - if (!n->stmts_.empty()) { - ++indent_; - for (auto it = n->stmts_.begin(); it != n->stmts_.end(); ++it) { - print_indent(); - TRY2((*it)->accept(this)); - fprintf(out_, "\n"); - } - --indent_; - } - fprintf(out_, "%*s}", indent_, ""); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_if_stmt_node(IfStmtNode* n) { - fprintf(out_, "if "); - TRY2(n->cond_->accept(this)); - fprintf(out_, " "); - TRY2(n->true_block_->accept(this)); - if (n->false_block_) { - fprintf(out_, " else "); - TRY2(n->false_block_->accept(this)); - } - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_onvalid_stmt_node(OnValidStmtNode* n) { - fprintf(out_, "if "); - TRY2(n->cond_->accept(this)); - fprintf(out_, " "); - TRY2(n->block_->accept(this)); - if (n->else_block_) { - fprintf(out_, " else "); - TRY2(n->else_block_->accept(this)); - } - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_switch_stmt_node(SwitchStmtNode* n) { - fprintf(out_, "switch ("); - TRY2(n->cond_->accept(this)); - fprintf(out_, ") "); - TRY2(n->block_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_case_stmt_node(CaseStmtNode* n) { - if (n->value_) { - fprintf(out_, "case "); - TRY2(n->value_->accept(this)); - } else { - fprintf(out_, "default"); - } - TRY2(n->block_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_ident_expr_node(IdentExprNode* n) { - if (n->scope_name_.size()) { - fprintf(out_, "%s::", n->scope_name_.c_str()); - } - fprintf(out_, "%s", n->name_.c_str()); - if (n->sub_name_.size()) { - fprintf(out_, ".%s", n->sub_name_.c_str()); - } - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_assign_expr_node(AssignExprNode* n) { - TRY2(n->lhs_->accept(this)); - fprintf(out_, " = "); - TRY2(n->rhs_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_packet_expr_node(PacketExprNode* n) { - fprintf(out_, "$"); - TRY2(n->id_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_integer_expr_node(IntegerExprNode* n) { - fprintf(out_, "%s:%zu", n->val_.c_str(), n->bits_); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_string_expr_node(StringExprNode *n) { - fprintf(out_, "%s", n->val_.c_str()); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_binop_expr_node(BinopExprNode* n) { - TRY2(n->lhs_->accept(this)); - fprintf(out_, "%d", n->op_); - TRY2(n->rhs_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_unop_expr_node(UnopExprNode* n) { - const char* s = ""; - switch (n->op_) { - case Tok::TNOT: s = "!"; break; - case Tok::TCMPL: s = "~"; break; - case Tok::TMOD: s = "%"; break; - default: {} - } - fprintf(out_, "%s", s); - TRY2(n->expr_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_bitop_expr_node(BitopExprNode* n) { - - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_return_expr_node(ReturnExprNode* n) { - fprintf(out_, "return "); - TRY2(n->expr_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_goto_expr_node(GotoExprNode* n) { - const char* s = n->is_continue_ ? "continue " : "goto "; - fprintf(out_, "%s", s); - TRY2(n->id_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_method_call_expr_node(MethodCallExprNode* n) { - TRY2(n->id_->accept(this)); - fprintf(out_, "("); - for (auto it = n->args_.begin(); it != n->args_.end(); ++it) { - TRY2((*it)->accept(this)); - if (it + 1 != n->args_.end()) { - fprintf(out_, ", "); - } - } - fprintf(out_, ")"); - if (!n->block_->stmts_.empty()) { - fprintf(out_, " {\n"); - ++indent_; - for (auto it = n->block_->stmts_.begin(); it != n->block_->stmts_.end(); ++it) { - print_indent(); - TRY2((*it)->accept(this)); - fprintf(out_, "\n"); - } - --indent_; - fprintf(out_, "%*s}", indent_, ""); - } - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_table_index_expr_node(TableIndexExprNode *n) { - fprintf(out_, "%s[", n->id_->c_str()); - TRY2(n->index_->accept(this)); - fprintf(out_, "]"); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_expr_stmt_node(ExprStmtNode* n) { - TRY2(n->expr_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_struct_variable_decl_stmt_node(StructVariableDeclStmtNode* n) { - fprintf(out_, "var "); - TRY2(n->struct_id_->accept(this)); - fprintf(out_, " "); - TRY2(n->id_->accept(this)); - if (!n->init_.empty()) { - fprintf(out_, "{"); - for (auto it = n->init_.begin(); it != n->init_.end(); ++it) { - TRY2((*it)->accept(this)); - if (it + 1 != n->init_.end()) { - fprintf(out_, ", "); - } - } - fprintf(out_, "}"); - } - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_integer_variable_decl_stmt_node(IntegerVariableDeclStmtNode* n) { - fprintf(out_, "var "); - TRY2(n->id_->accept(this)); - fprintf(out_, ":%zu", n->bit_width_); - if (!n->init_.empty()) { - fprintf(out_, "; "); - TRY2(n->init_[0]->accept(this)); - } - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_struct_decl_stmt_node(StructDeclStmtNode* n) { - fprintf(out_, "struct "); - TRY2(n->id_->accept(this)); - fprintf(out_, " {\n"); - ++indent_; - for (auto it = n->stmts_.begin(); it != n->stmts_.end(); ++it) { - print_indent(); - TRY2((*it)->accept(this)); - fprintf(out_, "\n"); - } - --indent_; - fprintf(out_, "%*s}", indent_, ""); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_state_decl_stmt_node(StateDeclStmtNode* n) { - if (!n->id_) { - return StatusTuple::OK(); - } - fprintf(out_, "state "); - TRY2(n->id_->accept(this)); - //if (!n->id2_) { - // fprintf(out_, ", * "); - //} else { - // fprintf(out_, ", "); - // TRY2(n->id2_->accept(this)); - //} - //TRY2(n->block_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_parser_state_stmt_node(ParserStateStmtNode* n) { - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_match_decl_stmt_node(MatchDeclStmtNode* n) { - fprintf(out_, "on_match "); - TRY2(n->id_->accept(this)); - fprintf(out_, " ("); - for (auto it = n->formals_.begin(); it != n->formals_.end(); ++it) { - TRY2((*it)->accept(this)); - if (it + 1 != n->formals_.end()) { - fprintf(out_, ", "); - } - } - fprintf(out_, ") "); - TRY2(n->block_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_miss_decl_stmt_node(MissDeclStmtNode* n) { - fprintf(out_, "on_miss "); - TRY2(n->id_->accept(this)); - fprintf(out_, " ("); - for (auto it = n->formals_.begin(); it != n->formals_.end(); ++it) { - TRY2((*it)->accept(this)); - if (it + 1 != n->formals_.end()) { - fprintf(out_, ", "); - } - } - fprintf(out_, ") "); - TRY2(n->block_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_failure_decl_stmt_node(FailureDeclStmtNode* n) { - fprintf(out_, "on_failure "); - TRY2(n->id_->accept(this)); - fprintf(out_, " ("); - for (auto it = n->formals_.begin(); it != n->formals_.end(); ++it) { - TRY2((*it)->accept(this)); - if (it + 1 != n->formals_.end()) { - fprintf(out_, ", "); - } - } - fprintf(out_, ") "); - TRY2(n->block_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_table_decl_stmt_node(TableDeclStmtNode* n) { - TRY2(n->table_type_->accept(this)); - fprintf(out_, "<"); - for (auto it = n->templates_.begin(); it != n->templates_.end(); ++it) { - TRY2((*it)->accept(this)); - if (it + 1 != n->templates_.end()) { - fprintf(out_, ", "); - } - } - fprintf(out_, "> "); - TRY2(n->id_->accept(this)); - fprintf(out_, "(%zu)", n->size_); - return StatusTuple::OK(); -} - -StatusTuple Printer::visit_func_decl_stmt_node(FuncDeclStmtNode *n) { - fprintf(out_, "func "); - TRY2(n->id_->accept(this)); - fprintf(out_, "("); - for (auto it = n->formals_.begin(); it != n->formals_.end(); ++it) { - TRY2((*it)->accept(this)); - if (it + 1 != n->formals_.end()) { - fprintf(out_, ", "); - } - } - fprintf(out_, ") "); - TRY2(n->block_->accept(this)); - return StatusTuple::OK(); -} - -} // namespace cc -} // namespace ebpf diff --git a/src/cc/frontends/b/printer.h b/src/cc/frontends/b/printer.h deleted file mode 100644 index 6dd4894b..00000000 --- a/src/cc/frontends/b/printer.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -#include "node.h" - -namespace ebpf { -namespace cc { - -class Printer : public Visitor { - public: - explicit Printer(FILE* out) : out_(out), indent_(0) {} - - void print_indent(); - -#define VISIT(type, func) virtual STATUS_RETURN visit_##func(type* n); - EXPAND_NODES(VISIT) -#undef VISIT - - private: - FILE* out_; - int indent_; -}; - -} // namespace cc -} // namespace ebpf diff --git a/src/cc/frontends/b/scope.h b/src/cc/frontends/b/scope.h deleted file mode 100644 index b0358b88..00000000 --- a/src/cc/frontends/b/scope.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include - -namespace ebpf { -namespace cc { - -using std::string; -using std::vector; -using std::map; -using std::pair; -using std::unique_ptr; - -class StateDeclStmtNode; -class VariableDeclStmtNode; -class TableDeclStmtNode; -class StructDeclStmtNode; -class FuncDeclStmtNode; - -enum search_type { SCOPE_LOCAL, SCOPE_GLOBAL }; - -template -class Scope { - public: - Scope() {} - Scope(Scope* scope, int id) : parent_(scope), id_(id) {} - - T* lookup(const string &name, bool search_local = true) { - return lookup(name, search_local ? SCOPE_LOCAL : SCOPE_GLOBAL); - } - T * lookup(const string &name, search_type stype) { - auto it = elems_.find(name); - if (it != elems_.end()) - return it->second; - - if (stype == SCOPE_LOCAL || !parent_) - return nullptr; - return parent_->lookup(name, stype); - } - void add(const string& name, T* n) { - elems_[name] = n; - elems_ordered_.push_back(n); - } - typename map::iterator begin() { return elems_.begin(); } - typename map::iterator end() { return elems_.end(); } - typename vector::iterator obegin() { return elems_ordered_.begin(); } - typename vector::iterator oend() { return elems_ordered_.end(); } - - Scope *parent_; - int id_; - map elems_; - vector elems_ordered_; -}; - -/** - * Hold the current stack of scope pointers. Lookups search upwards. - * Actual scope pointers are kept in the AST. - */ -class Scopes { - public: - typedef unique_ptr Ptr; - typedef Scope StructScope; - typedef Scope StateScope; - typedef Scope VarScope; - typedef Scope TableScope; - typedef Scope FuncScope; - - Scopes() : var_id__(0), state_id_(0), var_id_(0), - current_var_scope_(nullptr), top_var_scope_(nullptr), - current_state_scope_(nullptr), top_state_scope_(nullptr), - top_struct_scope_(new StructScope(nullptr, 1)), - top_table_scope_(new TableScope(nullptr, 1)), - top_func_scope_(new FuncScope(nullptr, 1)) {} - ~Scopes() { - delete top_func_scope_; - delete top_struct_scope_; - delete top_table_scope_; - delete top_state_scope_; - } - - void push_var(VarScope *scope) { - if (scope == top_var_scope_) - return; - scope->parent_ = current_var_scope_; - current_var_scope_ = scope; - } - void pop_var() { - if (current_var_scope_ == top_var_scope_) - return; - VarScope *old = current_var_scope_; - current_var_scope_ = old->parent_; - old->parent_ = nullptr; - } - - void push_state(StateScope *scope) { - if (scope == top_state_scope_) - return; - scope->parent_ = current_state_scope_; - current_state_scope_ = scope; - } - void pop_state() { - if (current_state_scope_ == top_state_scope_) - return; - StateScope *old = current_state_scope_; - current_state_scope_ = old->parent_; - old->parent_ = nullptr; - } - - /// While building the AST, allocate a new scope - VarScope* enter_var_scope() { - current_var_scope_ = new VarScope(current_var_scope_, next_var_id()); - if (!top_var_scope_) { - top_var_scope_ = current_var_scope_; - } - return current_var_scope_; - } - - VarScope* exit_var_scope() { - current_var_scope_ = current_var_scope_->parent_; - return current_var_scope_; - } - - StateScope* enter_state_scope() { - current_state_scope_ = new StateScope(current_state_scope_, next_state_id()); - if (!top_state_scope_) { - top_state_scope_ = current_state_scope_; - } - return current_state_scope_; - } - - StateScope* exit_state_scope() { - current_state_scope_ = current_state_scope_->parent_; - return current_state_scope_; - } - - void set_current(VarScope* s) { current_var_scope_ = s; } - VarScope* current_var() const { return current_var_scope_; } - VarScope* top_var() const { return top_var_scope_; } - - void set_current(StateScope* s) { current_state_scope_ = s; } - StateScope* current_state() const { return current_state_scope_; } - StateScope* top_state() const { return top_state_scope_; } - - StructScope* top_struct() const { return top_struct_scope_; } - - TableScope* top_table() const { return top_table_scope_; } - FuncScope* top_func() const { return top_func_scope_; } - - int next_id() { return ++var_id__; } - int next_state_id() { return ++state_id_; } - int next_var_id() { return ++var_id_; } - - int var_id__; - int state_id_; - int var_id_; - VarScope* current_var_scope_; - VarScope* top_var_scope_; - StateScope* current_state_scope_; - StateScope* top_state_scope_; - StructScope* top_struct_scope_; - TableScope* top_table_scope_; - FuncScope* top_func_scope_; -}; - -} // namespace cc -} // namespace ebpf diff --git a/src/cc/frontends/b/type_check.cc b/src/cc/frontends/b/type_check.cc deleted file mode 100644 index 4300c768..00000000 --- a/src/cc/frontends/b/type_check.cc +++ /dev/null @@ -1,587 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include "bcc_exception.h" -#include "type_check.h" -#include "lexer.h" - -namespace ebpf { -namespace cc { - -using std::for_each; -using std::set; - -StatusTuple TypeCheck::visit_block_stmt_node(BlockStmtNode *n) { - // enter scope - if (n->scope_) - scopes_->push_var(n->scope_); - if (!n->stmts_.empty()) { - for (auto it = n->stmts_.begin(); it != n->stmts_.end(); ++it) - TRY2((*it)->accept(this)); - } - - if (n->scope_) - scopes_->pop_var(); - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_if_stmt_node(IfStmtNode *n) { - TRY2(n->cond_->accept(this)); - //if (n->cond_->typeof_ != ExprNode::INTEGER) - // return mkstatus_(n, "If condition must be a numeric type"); - TRY2(n->true_block_->accept(this)); - if (n->false_block_) { - TRY2(n->false_block_->accept(this)); - } - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_onvalid_stmt_node(OnValidStmtNode *n) { - TRY2(n->cond_->accept(this)); - auto sdecl = static_cast(n->cond_->decl_); - if (sdecl->storage_type_ != StructVariableDeclStmtNode::STRUCT_REFERENCE) - return mkstatus_(n, "on_valid condition must be a reference type"); - TRY2(n->block_->accept(this)); - if (n->else_block_) { - TRY2(n->else_block_->accept(this)); - } - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_switch_stmt_node(SwitchStmtNode *n) { - TRY2(n->cond_->accept(this)); - if (n->cond_->typeof_ != ExprNode::INTEGER) - return mkstatus_(n, "Switch condition must be a numeric type"); - TRY2(n->block_->accept(this)); - for (auto it = n->block_->stmts_.begin(); it != n->block_->stmts_.end(); ++it) { - /// @todo check for duplicates - } - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_case_stmt_node(CaseStmtNode *n) { - if (n->value_) { - TRY2(n->value_->accept(this)); - if (n->value_->typeof_ != ExprNode::INTEGER) - return mkstatus_(n, "Switch condition must be a numeric type"); - } - TRY2(n->block_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_ident_expr_node(IdentExprNode *n) { - n->decl_ = scopes_->current_var()->lookup(n->name_, SCOPE_GLOBAL); - if (!n->decl_) - return mkstatus_(n, "Variable %s lookup failed", n->c_str()); - - n->typeof_ = ExprNode::UNKNOWN; - if (n->sub_name_.empty()) { - if (n->decl_->storage_type_ == VariableDeclStmtNode::INTEGER) { - n->typeof_ = ExprNode::INTEGER; - n->bit_width_ = n->decl_->bit_width_; - n->flags_[ExprNode::WRITE] = true; - } else if (n->decl_->is_struct()) { - n->typeof_ = ExprNode::STRUCT; - auto sdecl = static_cast(n->decl_); - if (sdecl->struct_id_->scope_name_ == "proto") { - n->struct_type_ = proto_scopes_->top_struct()->lookup(sdecl->struct_id_->name_, true); - n->flags_[ExprNode::PROTO] = true; - } else { - n->struct_type_ = scopes_->top_struct()->lookup(sdecl->struct_id_->name_, true); - } - if (!n->struct_type_) - return mkstatus_(n, "Type %s has not been declared", sdecl->struct_id_->full_name().c_str()); - n->bit_width_ = n->struct_type_->bit_width_; - } - } else { - if (n->decl_->storage_type_ == VariableDeclStmtNode::INTEGER) - return mkstatus_(n, "Subfield access not valid for numeric types"); - auto sdecl = static_cast(n->decl_); - if (sdecl->struct_id_->scope_name_ == "proto") { - n->struct_type_ = proto_scopes_->top_struct()->lookup(sdecl->struct_id_->name_, true); - n->flags_[ExprNode::PROTO] = true; - } else { - n->struct_type_ = scopes_->top_struct()->lookup(sdecl->struct_id_->name_, true); - } - if (!n->struct_type_) - return mkstatus_(n, "Type %s has not been declared", sdecl->struct_id_->full_name().c_str()); - n->sub_decl_ = n->struct_type_->field(n->sub_name_); - - if (!n->sub_decl_) - return mkstatus_(n, "Access to invalid subfield %s.%s", n->c_str(), n->sub_name_.c_str()); - if (n->sub_decl_->storage_type_ != VariableDeclStmtNode::INTEGER) - return mkstatus_(n, "Accessing non-numeric subfield %s.%s", n->c_str(), n->sub_name_.c_str()); - - n->typeof_ = ExprNode::INTEGER; - n->bit_width_ = n->sub_decl_->bit_width_; - n->flags_[ExprNode::WRITE] = true; - } - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_assign_expr_node(AssignExprNode *n) { - /// @todo check lhs is assignable - TRY2(n->lhs_->accept(this)); - if (n->lhs_->typeof_ == ExprNode::STRUCT) { - TRY2(n->rhs_->accept(this)); - if (n->rhs_->typeof_ != ExprNode::STRUCT) - return mkstatus_(n, "Right-hand side of assignment must be a struct"); - } else { - if (n->lhs_->typeof_ != ExprNode::INTEGER) - return mkstatus_(n, "Left-hand side of assignment must be a numeric type"); - if (!n->lhs_->flags_[ExprNode::WRITE]) - return mkstatus_(n, "Left-hand side of assignment is read-only"); - TRY2(n->rhs_->accept(this)); - if (n->rhs_->typeof_ != ExprNode::INTEGER) - return mkstatus_(n, "Right-hand side of assignment must be a numeric type"); - } - n->typeof_ = ExprNode::VOID; - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_packet_expr_node(PacketExprNode *n) { - StructDeclStmtNode *struct_type = proto_scopes_->top_struct()->lookup(n->id_->name_, true); - if (!struct_type) - return mkstatus_(n, "Undefined packet header %s", n->id_->c_str()); - if (n->id_->sub_name_.empty()) { - n->typeof_ = ExprNode::STRUCT; - n->struct_type_ = struct_type; - } else { - VariableDeclStmtNode *sub_decl = struct_type->field(n->id_->sub_name_); - if (!sub_decl) - return mkstatus_(n, "Access to invalid subfield %s.%s", n->id_->c_str(), n->id_->sub_name_.c_str()); - n->typeof_ = ExprNode::INTEGER; - if (n->is_ref()) - n->bit_width_ = 64; - else - n->bit_width_ = sub_decl->bit_width_; - } - n->flags_[ExprNode::WRITE] = true; - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_integer_expr_node(IntegerExprNode *n) { - n->typeof_ = ExprNode::INTEGER; - n->bit_width_ = n->bits_; - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_string_expr_node(StringExprNode *n) { - n->typeof_ = ExprNode::STRING; - n->flags_[ExprNode::IS_REF] = true; - n->bit_width_ = n->val_.size() << 3; - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_binop_expr_node(BinopExprNode *n) { - TRY2(n->lhs_->accept(this)); - if (n->lhs_->typeof_ != ExprNode::INTEGER) - return mkstatus_(n, "Left-hand side of binary expression must be a numeric type"); - TRY2(n->rhs_->accept(this)); - if (n->rhs_->typeof_ != ExprNode::INTEGER) - return mkstatus_(n, "Right-hand side of binary expression must be a numeric type"); - n->typeof_ = ExprNode::INTEGER; - switch(n->op_) { - case Tok::TCEQ: - case Tok::TCNE: - case Tok::TCLT: - case Tok::TCLE: - case Tok::TCGT: - case Tok::TCGE: - n->bit_width_ = 1; - break; - default: - n->bit_width_ = std::max(n->lhs_->bit_width_, n->rhs_->bit_width_); - } - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_unop_expr_node(UnopExprNode *n) { - TRY2(n->expr_->accept(this)); - if (n->expr_->typeof_ != ExprNode::INTEGER) - return mkstatus_(n, "Unary operand must be a numeric type"); - n->copy_type(*n->expr_); - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_bitop_expr_node(BitopExprNode *n) { - if (n->expr_->typeof_ != ExprNode::INTEGER) - return mkstatus_(n, "Bitop [] can only operate on numeric types"); - n->typeof_ = ExprNode::INTEGER; - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_goto_expr_node(GotoExprNode *n) { - //n->id_->accept(this); - n->typeof_ = ExprNode::VOID; - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_return_expr_node(ReturnExprNode *n) { - TRY2(n->expr_->accept(this)); - n->typeof_ = ExprNode::VOID; - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::expect_method_arg(MethodCallExprNode *n, size_t num, size_t num_def_args = 0) { - if (num_def_args == 0) { - if (n->args_.size() != num) - return mkstatus_(n, "%s expected %d argument%s, %zu given", n->id_->sub_name_.c_str(), - num, num == 1 ? "" : "s", n->args_.size()); - } else { - if (n->args_.size() < num - num_def_args || n->args_.size() > num) - return mkstatus_(n, "%s expected %d argument%s (%d default), %zu given", n->id_->sub_name_.c_str(), - num, num == 1 ? "" : "s", num_def_args, n->args_.size()); - } - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::check_lookup_method(MethodCallExprNode *n) { - auto table = scopes_->top_table()->lookup(n->id_->name_); - if (!table) - return mkstatus_(n, "Unknown table name %s", n->id_->c_str()); - TRY2(expect_method_arg(n, 2, 1)); - if (table->type_id()->name_ == "LPM") - return mkstatus_(n, "LPM unsupported"); - if (n->block_->scope_) { - auto result = make_unique(table->leaf_id()->copy(), make_unique("_result"), - VariableDeclStmtNode::STRUCT_REFERENCE); - n->block_->scope_->add("_result", result.get()); - n->block_->stmts_.insert(n->block_->stmts_.begin(), move(result)); - } - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::check_update_method(MethodCallExprNode *n) { - auto table = scopes_->top_table()->lookup(n->id_->name_); - if (!table) - return mkstatus_(n, "Unknown table name %s", n->id_->c_str()); - if (table->type_id()->name_ == "FIXED_MATCH" || table->type_id()->name_ == "INDEXED") - TRY2(expect_method_arg(n, 2)); - else if (table->type_id()->name_ == "LPM") - TRY2(expect_method_arg(n, 3)); - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::check_delete_method(MethodCallExprNode *n) { - auto table = scopes_->top_table()->lookup(n->id_->name_); - if (!table) - return mkstatus_(n, "Unknown table name %s", n->id_->c_str()); - if (table->type_id()->name_ == "FIXED_MATCH" || table->type_id()->name_ == "INDEXED") - TRY2(expect_method_arg(n, 1)); - else if (table->type_id()->name_ == "LPM") - {} - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_method_call_expr_node(MethodCallExprNode *n) { - // be sure to visit those child nodes ASAP, so their properties can - // be propagated up to this node and be ready to be used - for (auto it = n->args_.begin(); it != n->args_.end(); ++it) { - TRY2((*it)->accept(this)); - } - - n->typeof_ = ExprNode::VOID; - if (n->id_->sub_name_.size()) { - if (n->id_->sub_name_ == "lookup") { - TRY2(check_lookup_method(n)); - } else if (n->id_->sub_name_ == "update") { - TRY2(check_update_method(n)); - } else if (n->id_->sub_name_ == "delete") { - TRY2(check_delete_method(n)); - } else if (n->id_->sub_name_ == "rewrite_field" && n->id_->name_ == "pkt") { - TRY2(expect_method_arg(n, 2)); - n->args_[0]->flags_[ExprNode::IS_LHS] = true; - } - } else if (n->id_->name_ == "log") { - if (n->args_.size() < 1) - return mkstatus_(n, "%s expected at least 1 argument", n->id_->c_str()); - if (n->args_[0]->typeof_ != ExprNode::STRING) - return mkstatus_(n, "%s expected a string for argument 1", n->id_->c_str()); - n->typeof_ = ExprNode::INTEGER; - n->bit_width_ = 32; - } else if (n->id_->name_ == "atomic_add") { - TRY2(expect_method_arg(n, 2)); - n->typeof_ = ExprNode::INTEGER; - n->bit_width_ = n->args_[0]->bit_width_; - n->args_[0]->flags_[ExprNode::IS_LHS] = true; - } else if (n->id_->name_ == "incr_cksum") { - TRY2(expect_method_arg(n, 4, 1)); - n->typeof_ = ExprNode::INTEGER; - n->bit_width_ = 16; - } else if (n->id_->name_ == "sizeof") { - TRY2(expect_method_arg(n, 1)); - n->typeof_ = ExprNode::INTEGER; - n->bit_width_ = 32; - } else if (n->id_->name_ == "get_usec_time") { - TRY2(expect_method_arg(n, 0)); - n->typeof_ = ExprNode::INTEGER; - n->bit_width_ = 64; - } - - if (!n->block_->stmts_.empty()) { - if (n->id_->sub_name_ != "update" && n->id_->sub_name_ != "lookup") - return mkstatus_(n, "%s does not allow trailing block statements", n->id_->full_name().c_str()); - TRY2(n->block_->accept(this)); - } - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_table_index_expr_node(TableIndexExprNode *n) { - n->table_ = scopes_->top_table()->lookup(n->id_->name_); - if (!n->table_) return mkstatus_(n, "Unknown table name %s", n->id_->c_str()); - TRY2(n->index_->accept(this)); - if (n->index_->struct_type_ != n->table_->key_type_) - return mkstatus_(n, "Key to table %s lookup must be of type %s", n->id_->c_str(), n->table_->key_id()->c_str()); - - if (n->sub_) { - n->sub_decl_ = n->table_->leaf_type_->field(n->sub_->name_); - if (!n->sub_decl_) - return mkstatus_(n, "Field %s is not a member of %s", n->sub_->c_str(), n->table_->leaf_id()->c_str()); - n->typeof_ = ExprNode::INTEGER; - } else { - n->typeof_ = ExprNode::STRUCT; - n->flags_[ExprNode::IS_REF] = true; - n->struct_type_ = n->table_->leaf_type_; - } - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_expr_stmt_node(ExprStmtNode *n) { - TRY2(n->expr_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_struct_variable_decl_stmt_node(StructVariableDeclStmtNode *n) { - //TRY2(n->struct_id_->accept(this)); - //TRY2(n->id_->accept(this)); - if (!n->init_.empty()) { - StructDeclStmtNode *type; - if (n->struct_id_->scope_name_ == "proto") - type = proto_scopes_->top_struct()->lookup(n->struct_id_->name_, true); - else - type = scopes_->top_struct()->lookup(n->struct_id_->name_, true); - - if (!type) - return mkstatus_(n, "type %s does not exist", n->struct_id_->full_name().c_str()); - - // init remaining fields to 0 - set used; - for (auto i = n->init_.begin(); i != n->init_.end(); ++i) { - auto asn = static_cast(i->get()); - auto id = static_cast(asn->lhs_.get()); - used.insert(id->sub_name_); - } - for (auto f = type->stmts_.begin(); f != type->stmts_.end(); ++f) { - if (used.find((*f)->id_->name_) == used.end()) { - auto id = make_unique(n->id_->name_); - id->append_dot((*f)->id_->name_); - n->init_.push_back(make_unique(move(id), make_unique("0"))); - } - } - - for (auto it = n->init_.begin(); it != n->init_.end(); ++it) { - TRY2((*it)->accept(this)); - } - } - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_integer_variable_decl_stmt_node(IntegerVariableDeclStmtNode *n) { - //TRY2(n->id_->accept(this)); - if (!n->init_.empty()) { - TRY2(n->init_[0]->accept(this)); - } - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_struct_decl_stmt_node(StructDeclStmtNode *n) { - //TRY2(n->id_->accept(this)); - for (auto it = n->stmts_.begin(); it != n->stmts_.end(); ++it) { - TRY2((*it)->accept(this)); - } - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_parser_state_stmt_node(ParserStateStmtNode *n) { - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_state_decl_stmt_node(StateDeclStmtNode *n) { - if (!n->id_) { - return StatusTuple::OK(); - } - auto s1 = proto_scopes_->top_state()->lookup(n->id_->name_, true); - if (s1) { - const string &name = n->id_->name_; - auto offset_var = make_unique(make_unique("$" + name), "64"); - offset_var->init_.push_back(make_unique(offset_var->id_->copy(), make_unique("0"))); - scopes_->current_var()->add("$" + name, offset_var.get()); - s1->subs_[0].block_->scope_->add("$" + name, offset_var.get()); - n->init_.push_back(move(offset_var)); - - n->parser_ = ParserStateStmtNode::make(n->id_); - n->parser_->next_state_ = s1->subs_[0].block_.get(); - n->parser_->scope_id_ = n->scope_id_; - - auto p = proto_scopes_->top_struct()->lookup(n->id_->name_, true); - if (!p) return mkstatus_(n, "unable to find struct decl for parser state %s", n->id_->full_name().c_str()); - - // $proto = parsed_bytes; parsed_bytes += sizeof($proto); - auto asn1 = make_unique(make_unique("$" + n->id_->name_), - make_unique("parsed_bytes")); - n->init_.push_back(make_unique(move(asn1))); - auto add_expr = make_unique(make_unique("parsed_bytes"), Tok::TPLUS, - make_unique(std::to_string(p->bit_width_ >> 3), 64)); - auto asn2 = make_unique(make_unique("parsed_bytes"), move(add_expr)); - n->init_.push_back(make_unique(move(asn2))); - } - - for (auto it = n->init_.begin(); it != n->init_.end(); ++it) { - TRY2((*it)->accept(this)); - } - - for (auto it = n->subs_.begin(); it != n->subs_.end(); ++it) { - scopes_->push_state(it->scope_); - - TRY2(it->block_->accept(this)); - - if (s1) { - if (it->id_->name_ == "") { - it->parser_ = ParserStateStmtNode::make(it->id_); - it->parser_->next_state_ = s1->subs_[0].block_.get(); - it->parser_->scope_id_ = n->scope_id_ + n->id_->name_ + "_"; - } else if (auto s2 = proto_scopes_->top_state()->lookup(it->id_->name_, true)) { - it->parser_ = ParserStateStmtNode::make(it->id_); - it->parser_->next_state_ = s2->subs_[0].block_.get(); - it->parser_->scope_id_ = n->scope_id_ + n->id_->name_ + "_"; - } - - if (it->parser_) { - TRY2(it->parser_->accept(this)); - } - } - - scopes_->pop_state(); - } - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_match_decl_stmt_node(MatchDeclStmtNode *n) { - //TRY2(n->id_->accept(this)); - for (auto it = n->formals_.begin(); it != n->formals_.end(); ++it) { - TRY2((*it)->accept(this)); - } - TRY2(n->block_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_miss_decl_stmt_node(MissDeclStmtNode *n) { - //TRY2(n->id_->accept(this)); - for (auto it = n->formals_.begin(); it != n->formals_.end(); ++it) { - TRY2((*it)->accept(this)); - } - TRY2(n->block_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_failure_decl_stmt_node(FailureDeclStmtNode *n) { - //TRY2(n->id_->accept(this)); - for (auto it = n->formals_.begin(); it != n->formals_.end(); ++it) { - TRY2((*it)->accept(this)); - } - TRY2(n->block_->accept(this)); - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_table_decl_stmt_node(TableDeclStmtNode *n) { - n->key_type_ = scopes_->top_struct()->lookup(n->key_id()->name_, true); - if (!n->key_type_) - return mkstatus_(n, "Table key type %s undefined", n->key_id()->c_str()); - n->key_id()->bit_width_ = n->key_type_->bit_width_; - n->leaf_type_ = scopes_->top_struct()->lookup(n->leaf_id()->name_, true); - if (!n->leaf_type_) - return mkstatus_(n, "Table leaf type %s undefined", n->leaf_id()->c_str()); - n->leaf_id()->bit_width_ = n->leaf_type_->bit_width_; - if (n->type_id()->name_ == "INDEXED" && n->policy_id()->name_ != "AUTO") { - fprintf(stderr, "Table %s is INDEXED, policy should be AUTO\n", n->id_->c_str()); - n->policy_id()->name_ = "AUTO"; - } - if (n->policy_id()->name_ != "AUTO" && n->policy_id()->name_ != "NONE") - return mkstatus_(n, "Unsupported policy type %s", n->policy_id()->c_str()); - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit_func_decl_stmt_node(FuncDeclStmtNode *n) { - for (auto it = n->formals_.begin(); it != n->formals_.end(); ++it) { - VariableDeclStmtNode *var = it->get(); - TRY2(var->accept(this)); - if (var->is_struct()) { - if (!var->is_pointer()) - return mkstatus_(n, "Only struct references allowed in function definitions"); - } - } - scopes_->push_state(n->scope_); - TRY2(n->block_->accept(this)); - scopes_->pop_state(); - return StatusTuple::OK(); -} - -StatusTuple TypeCheck::visit(Node *root) { - BlockStmtNode *b = static_cast(root); - - scopes_->set_current(scopes_->top_state()); - scopes_->set_current(scopes_->top_var()); - - // // packet data in bpf socket - // if (scopes_->top_struct()->lookup("_skbuff", true)) { - // return StatusTuple(-1, "_skbuff already defined"); - // } - // auto skb_type = make_unique(make_unique("_skbuff")); - // scopes_->top_struct()->add("_skbuff", skb_type.get()); - // b->stmts_.push_back(move(skb_type)); - - // if (scopes_->current_var()->lookup("skb", true)) { - // return StatusTuple(-1, "skb already defined"); - // } - // auto skb = make_unique(make_unique("_skbuff"), - // make_unique("skb")); - // skb->storage_type_ = VariableDeclStmtNode::STRUCT_REFERENCE; - // scopes_->current_var()->add("skb", skb.get()); - // b->stmts_.push_back(move(skb)); - - // offset counter - auto parsed_bytes = make_unique( - make_unique("parsed_bytes"), "64"); - parsed_bytes->init_.push_back(make_unique(parsed_bytes->id_->copy(), make_unique("0"))); - scopes_->current_var()->add("parsed_bytes", parsed_bytes.get()); - b->stmts_.push_back(move(parsed_bytes)); - - TRY2(b->accept(this)); - - if (!errors_.empty()) { - for (auto it = errors_.begin(); it != errors_.end(); ++it) { - fprintf(stderr, "%s\n", it->c_str()); - } - return StatusTuple(-1, errors_.begin()->c_str()); - } - return StatusTuple::OK(); -} - -} // namespace cc -} // namespace ebpf diff --git a/src/cc/frontends/b/type_check.h b/src/cc/frontends/b/type_check.h deleted file mode 100644 index dbf427aa..00000000 --- a/src/cc/frontends/b/type_check.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include "node.h" -#include "scope.h" - -namespace ebpf { -namespace cc { - -class TypeCheck : public Visitor { - public: - TypeCheck(Scopes *scopes, Scopes *proto_scopes) - : scopes_(scopes), proto_scopes_(proto_scopes) {} - - virtual STATUS_RETURN visit(Node* n); - STATUS_RETURN expect_method_arg(MethodCallExprNode* n, size_t num, size_t num_def_args); - STATUS_RETURN check_lookup_method(MethodCallExprNode* n); - STATUS_RETURN check_update_method(MethodCallExprNode* n); - STATUS_RETURN check_delete_method(MethodCallExprNode* n); - -#define VISIT(type, func) virtual STATUS_RETURN visit_##func(type* n); - EXPAND_NODES(VISIT) -#undef VISIT - - private: - Scopes *scopes_; - Scopes *proto_scopes_; - vector errors_; -}; - -} // namespace cc -} // namespace ebpf diff --git a/src/cc/frontends/b/type_helper.h b/src/cc/frontends/b/type_helper.h deleted file mode 100644 index ce96cc43..00000000 --- a/src/cc/frontends/b/type_helper.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2015 PLUMgrid, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -namespace ebpf { -namespace cc { - -// Represent the numeric type of a protocol field -enum FieldType { - INVALID = 0, - UINT8_T, - UINT16_T, - UINT32_T, - UINT64_T, -#ifdef __SIZEOF_INT128__ - UINT128_T, -#endif - VOID -}; - -static inline size_t enum_to_size(const FieldType t) { - switch (t) { - case UINT8_T: return sizeof(uint8_t); - case UINT16_T: return sizeof(uint16_t); - case UINT32_T: return sizeof(uint32_t); - case UINT64_T: return sizeof(uint64_t); -#ifdef __SIZEOF_INT128__ - case UINT128_T: return sizeof(__uint128_t); -#endif - default: - return 0; - } -} - -/// Convert a bit size to the next highest power of 2 -static inline int next_base2(int v) { - --v; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - ++v; - return v; -} - -static inline const char* bits_to_uint(int v) { - v = next_base2(v); - if (v <= 8) { - return "uint8_t"; - } else if (v == 16) { - return "uint16_t"; - } else if (v == 32) { - return "uint32_t"; - } else if (v == 64) { - return "uint64_t"; - } else if (v >= 128) { - /* in plumlet 128-bit integers should be 8-byte aligned, - * all other ints should have natural alignment */ - return "unsigned __int128 __attribute__((packed, aligned(8)))"; - } - return "void"; -} - -static inline FieldType bits_to_enum(int v) { - v = next_base2(v); - if (v <= 8) { - return UINT8_T; - } else if (v == 16) { - return UINT16_T; - } else if (v == 32) { - return UINT32_T; - } else if (v == 64) { - return UINT64_T; -#ifdef __SIZEOF_INT128__ - } else if (v >= 128) { - return UINT128_T; -#endif - } - return VOID; -} - -static inline size_t bits_to_size(int v) { - return enum_to_size(bits_to_enum(v)); -} - -static inline size_t align_offset(size_t offset, FieldType ft) { - switch (ft) { - case UINT8_T: - return offset % 8 > 0 ? offset + (8 - offset % 8) : offset; - case UINT16_T: - return offset % 16 > 0 ? offset + (16 - offset % 16) : offset; - case UINT32_T: - return offset % 32 > 0 ? offset + (32 - offset % 32) : offset; - case UINT64_T: -#ifdef __SIZEOF_INT128__ - case UINT128_T: -#endif - return offset % 64 > 0 ? offset + (64 - offset % 64) : offset; - default: - ; - } - return offset; -} - -} // namespace cc -} // namespace ebpf diff --git a/src/lua/bcc/bpf.lua b/src/lua/bcc/bpf.lua index 89170f31..45be2728 100644 --- a/src/lua/bcc/bpf.lua +++ b/src/lua/bcc/bpf.lua @@ -125,12 +125,7 @@ function Bpf:initialize(args) elseif args.src_file then local src = _find_file(Bpf.SCRIPT_ROOT, args.src_file) - if src:ends(".b") then - local hdr = _find_file(Bpf.SCRIPT_ROOT, args.hdr_file) - self.module = libbcc.bpf_module_create_b(src, hdr, llvm_debug) - else - self.module = libbcc.bpf_module_create_c(src, llvm_debug, cflags_ary, #cflags, true) - end + self.module = libbcc.bpf_module_create_c(src, llvm_debug, cflags_ary, #cflags, true) end assert(self.module ~= nil, "failed to compile BPF module") diff --git a/src/lua/bcc/libbcc.lua b/src/lua/bcc/libbcc.lua index b2b5ee90..f34fbd05 100644 --- a/src/lua/bcc/libbcc.lua +++ b/src/lua/bcc/libbcc.lua @@ -58,7 +58,6 @@ int bpf_close_perf_event_fd(int fd); ]] ffi.cdef[[ -void * bpf_module_create_b(const char *filename, const char *proto_filename, unsigned flags); void * bpf_module_create_c(const char *filename, unsigned flags, const char *cflags[], int ncflags, bool allow_rlimit); void * bpf_module_create_c_from_string(const char *text, unsigned flags, const char *cflags[], int ncflags, bool allow_rlimit); void bpf_module_destroy(void *program); diff --git a/src/python/bcc/__init__.py b/src/python/bcc/__init__.py index 389bc8ba..ceb28841 100644 --- a/src/python/bcc/__init__.py +++ b/src/python/bcc/__init__.py @@ -449,32 +449,28 @@ class BPF(object): src_file = BPF._find_file(src_file) hdr_file = BPF._find_file(hdr_file) - # files that end in ".b" are treated as B files. Everything else is a (BPF-)C file - if src_file.endswith(b".b"): - self.module = lib.bpf_module_create_b(src_file, hdr_file, self.debug, device) - else: - if src_file: - # Read the BPF C source file into the text variable. This ensures, - # that files and inline text are treated equally. - with open(src_file, mode="rb") as file: - text = file.read() - - ctx_array = (ct.c_void_p * len(usdt_contexts))() - for i, usdt in enumerate(usdt_contexts): - ctx_array[i] = ct.c_void_p(usdt.get_context()) - usdt_text = lib.bcc_usdt_genargs(ctx_array, len(usdt_contexts)) - if usdt_text is None: - raise Exception("can't generate USDT probe arguments; " + - "possible cause is missing pid when a " + - "probe in a shared object has multiple " + - "locations") - text = usdt_text + text - - - self.module = lib.bpf_module_create_c_from_string(text, - self.debug, - cflags_array, len(cflags_array), - allow_rlimit, device) + if src_file: + # Read the BPF C source file into the text variable. This ensures, + # that files and inline text are treated equally. + with open(src_file, mode="rb") as file: + text = file.read() + + ctx_array = (ct.c_void_p * len(usdt_contexts))() + for i, usdt in enumerate(usdt_contexts): + ctx_array[i] = ct.c_void_p(usdt.get_context()) + usdt_text = lib.bcc_usdt_genargs(ctx_array, len(usdt_contexts)) + if usdt_text is None: + raise Exception("can't generate USDT probe arguments; " + + "possible cause is missing pid when a " + + "probe in a shared object has multiple " + + "locations") + text = usdt_text + text + + + self.module = lib.bpf_module_create_c_from_string(text, + self.debug, + cflags_array, len(cflags_array), + allow_rlimit, device) if not self.module: raise Exception("Failed to compile BPF module %s" % (src_file or "")) diff --git a/src/python/bcc/libbcc.py b/src/python/bcc/libbcc.py index 3a39d044..fdea8a12 100644 --- a/src/python/bcc/libbcc.py +++ b/src/python/bcc/libbcc.py @@ -20,9 +20,6 @@ lib = ct.CDLL("libbcc.so.0", use_errno=True) from .perf import Perf # keep in sync with bcc_common.h -lib.bpf_module_create_b.restype = ct.c_void_p -lib.bpf_module_create_b.argtypes = [ct.c_char_p, ct.c_char_p, ct.c_uint, - ct.c_char_p] lib.bpf_module_create_c.restype = ct.c_void_p lib.bpf_module_create_c.argtypes = [ct.c_char_p, ct.c_uint, ct.POINTER(ct.c_char_p), ct.c_int, ct.c_bool, ct.c_char_p] diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index d86fcab6..a42a16ce 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -17,20 +17,14 @@ if(IPERF STREQUAL "IPERF-NOTFOUND") endif() endif() -add_test(NAME py_test_stat1_b WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMAND ${TEST_WRAPPER} py_stat1_b namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_stat1.py test_stat1.b proto.b) add_test(NAME py_test_bpf_log WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${TEST_WRAPPER} py_bpf_prog sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_bpf_log.py) add_test(NAME py_test_stat1_c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${TEST_WRAPPER} py_stat1_c namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_stat1.py test_stat1.c) -#add_test(NAME py_test_xlate1_b WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} -# COMMAND ${TEST_WRAPPER} py_xlate1_b namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_xlate1.py test_xlate1.b proto.b) add_test(NAME py_test_xlate1_c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${TEST_WRAPPER} py_xlate1_c namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_xlate1.py test_xlate1.c) add_test(NAME py_test_call1 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${TEST_WRAPPER} py_call1_c namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_call1.py test_call1.c) -add_test(NAME py_test_trace1 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMAND ${TEST_WRAPPER} py_trace1 sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_trace1.py test_trace1.b kprobe.b) add_test(NAME py_test_trace2 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMAND ${TEST_WRAPPER} py_trace2 sudo ${CMAKE_CURRENT_SOURCE_DIR}/test_trace2.py) add_test(NAME py_test_trace3_c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/tests/python/kprobe.b b/tests/python/kprobe.b deleted file mode 100644 index 74a996b5..00000000 --- a/tests/python/kprobe.b +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) PLUMgrid, Inc. -// Licensed under the Apache License, Version 2.0 (the "License") - -#packed "false" - -struct pt_regs { - u64 r15:64; - u64 r14:64; - u64 r13:64; - u64 r12:64; - u64 bp:64; - u64 bx:64; - u64 r11:64; - u64 r10:64; - u64 r9:64; - u64 r8:64; - u64 ax:64; - u64 cx:64; - u64 dx:64; - u64 si:64; - u64 di:64; -}; - - diff --git a/tests/python/proto.b b/tests/python/proto.b deleted file mode 100644 index 78cfa5f1..00000000 --- a/tests/python/proto.b +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) PLUMgrid, Inc. -// Licensed under the Apache License, Version 2.0 (the "License") - -#packed "true" - -struct ethernet { - u64 dst:48; - u64 src:48; - u32 type:16; -}; - -state ethernet { - switch $ethernet.type { - case 0x0800 { - next proto::ip; - }; - case 0x8100 { - next proto::dot1q; - }; - case * { - goto EOP; - }; - } -} - - -struct dot1q { - u32 pri:3; - u32 cfi:1; - u32 vlanid:12; - u32 type:16; -}; - -state dot1q { - switch $dot1q.type { - case 0x0800 { - next proto::ip; - }; - case * { - goto EOP; - }; - } -} - - -struct ip { - u32 ver:4; - u32 hlen:4; - u32 tos:8; - u32 tlen:16; - u32 identification:16; - u32 ffo_unused:1; - u32 df:1; - u32 mf:1; - u32 foffset:13; - u32 ttl:8; - u32 nextp:8; - u32 hchecksum:16; - u32 src:32; - u32 dst:32; -}; - -state ip { - switch $ip.nextp { - case 6 { - next proto::tcp; - }; - case 17 { - next proto::udp; - }; - case 47 { - next proto::gre; - }; - case * { - goto EOP; - }; - } -} - - -struct udp { - u32 sport:16; - u32 dport:16; - u32 length:16; - u32 crc:16; -}; - -state udp { - switch $udp.dport { - case 8472 { - next proto::vxlan; - }; - case * { - goto EOP; - }; - } -} - -struct tcp { - u16 src_port:16; - u16 dst_port:16; - u32 seq_num:32; - u32 ack_num:32; - u8 offset:4; - u8 reserved:4; - u8 flag_cwr:1; - u8 flag_ece:1; - u8 flag_urg:1; - u8 flag_ack:1; - u8 flag_psh:1; - u8 flag_rst:1; - u8 flag_syn:1; - u8 flag_fin:1; - u16 rcv_wnd:16; - u16 cksum:16; - u16 urg_ptr:16; -}; - -state tcp { - goto EOP; -} - -struct vxlan { - u32 rsv1:4; - u32 iflag:1; - u32 rsv2:3; - u32 rsv3:24; - u32 key:24; - u32 rsv4:8; -}; - -state vxlan { - goto EOP; -} - - -struct gre { - u32 cflag:1; - u32 rflag:1; - u32 kflag:1; - u32 snflag:1; - u32 srflag:1; - u32 recurflag:3; - u32 reserved:5; - u32 vflag:3; - u32 protocol:16; - u32 key:32; -}; - -state gre { - switch $gre.protocol { - case * { - goto EOP; - }; - } -} - diff --git a/tests/python/test_stat1.b b/tests/python/test_stat1.b deleted file mode 100644 index fb505d6c..00000000 --- a/tests/python/test_stat1.b +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) PLUMgrid, Inc. -// Licensed under the Apache License, Version 2.0 (the "License") -struct IPKey { - u32 dip:32; - u32 sip:32; -}; -struct IPLeaf { - u32 rx_pkts:64; - u32 tx_pkts:64; -}; -Table stats(1024); - -struct skbuff { - u32 type:32; -}; - -u32 on_packet(struct skbuff *skb) { - u32 ret:32 = 0; - - goto proto::ethernet; - - state proto::ethernet { - } - - state proto::dot1q { - } - - state proto::ip { - u32 rx:32 = 0; - u32 tx:32 = 0; - u32 IPKey key; - if $ip.dst > $ip.src { - key.dip = $ip.dst; - key.sip = $ip.src; - rx = 1; - // test arbitrary return stmt - if false { - return 3; - } - } else { - key.dip = $ip.src; - key.sip = $ip.dst; - tx = 1; - ret = 1; - } - struct IPLeaf *leaf; - leaf = stats[key]; - on_valid(leaf) { - atomic_add(leaf.rx_pkts, rx); - atomic_add(leaf.tx_pkts, tx); - } - } - - state proto::udp { - } - - state proto::vxlan { - } - - state proto::gre { - } - - state EOP { - return ret; - } -} diff --git a/tests/python/test_stat1.py b/tests/python/test_stat1.py index 23b3a291..10433099 100755 --- a/tests/python/test_stat1.py +++ b/tests/python/test_stat1.py @@ -19,13 +19,6 @@ if len(sys.argv) > 1: Key = None Leaf = None -if arg1.endswith(".b"): - class Key(Structure): - _fields_ = [("dip", c_uint), - ("sip", c_uint)] - class Leaf(Structure): - _fields_ = [("rx_pkts", c_ulong), - ("tx_pkts", c_ulong)] class TestBPFSocket(TestCase): def setUp(self): diff --git a/tests/python/test_trace1.b b/tests/python/test_trace1.b deleted file mode 100644 index 05ddda6b..00000000 --- a/tests/python/test_trace1.b +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) PLUMgrid, Inc. -// Licensed under the Apache License, Version 2.0 (the "License") -struct Ptr { - u64 ptr:64; -}; -struct Counters { - u64 stat1:64; - u64 stat2:64; -}; -Table stats(1024); - -// example with on_valid syntax -u32 sys_wr (struct proto::pt_regs *ctx) { - struct Ptr key = {.ptr=ctx->di}; - struct Counters *leaf; - leaf = stats[key]; - if leaf { - atomic_add(leaf->stat2, 1); - } - log("sys_wr: %p\n", ctx->di); - return 0; -} - -// example with smallest available syntax -// note: if stats[key] fails, program returns early -u32 sys_rd (struct proto::pt_regs *ctx) { - struct Ptr key = {.ptr=ctx->di}; - atomic_add(stats[key].stat1, 1); -} - -// example with if/else case -u32 sys_bpf (struct proto::pt_regs *ctx) { - struct Ptr key = {.ptr=ctx->di}; - struct Counters *leaf; - leaf = stats[key]; - if leaf { - atomic_add(leaf->stat1, 1); - } else { - log("update %llx failed\n", ctx->di); - } - return 0; -} - diff --git a/tests/python/test_trace1.py b/tests/python/test_trace1.py deleted file mode 100755 index dc005c5c..00000000 --- a/tests/python/test_trace1.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) PLUMgrid, Inc. -# Licensed under the Apache License, Version 2.0 (the "License") - -from ctypes import c_uint, c_ulong, Structure -from bcc import BPF -import os -from time import sleep -import sys -from unittest import main, TestCase - -arg1 = sys.argv.pop(1) -arg2 = "" -if len(sys.argv) > 1: - arg2 = sys.argv.pop(1) - -Key = None -Leaf = None -if arg1.endswith(".b"): - class Key(Structure): - _fields_ = [("fd", c_ulong)] - class Leaf(Structure): - _fields_ = [("stat1", c_ulong), - ("stat2", c_ulong)] - -class TestKprobe(TestCase): - def setUp(self): - b = BPF(arg1, arg2, debug=0) - self.stats = b.get_table("stats", Key, Leaf) - b.attach_kprobe(event=b.get_syscall_fnname("write"), fn_name="sys_wr") - b.attach_kprobe(event=b.get_syscall_fnname("read"), fn_name="sys_rd") - b.attach_kprobe(event="htab_map_get_next_key", fn_name="sys_rd") - - def test_trace1(self): - with open("/dev/null", "a") as f: - for i in range(0, 100): - os.write(f.fileno(), b"") - with open("/etc/services", "r") as f: - for i in range(0, 200): - os.read(f.fileno(), 1) - for key, leaf in self.stats.items(): - print("fd %x:" % key.fd, "stat1 %d" % leaf.stat1, "stat2 %d" % leaf.stat2) - -if __name__ == "__main__": - main() diff --git a/tests/python/test_trace2.b b/tests/python/test_trace2.b deleted file mode 100644 index 1e4bcd13..00000000 --- a/tests/python/test_trace2.b +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) PLUMgrid, Inc. -// Licensed under the Apache License, Version 2.0 (the "License") -#include "kprobe.b" -struct Ptr { u64 ptr:64; }; -struct Counters { u64 stat1:64; }; -Table stats(1024); - -u32 count_sched (struct proto::pt_regs *ctx) { - struct Ptr key = {.ptr=ctx->bx}; - atomic_add(stats[key].stat1, 1); -} diff --git a/tests/python/test_xlate1.b b/tests/python/test_xlate1.b deleted file mode 100644 index 2db00463..00000000 --- a/tests/python/test_xlate1.b +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) PLUMgrid, Inc. -// Licensed under the Apache License, Version 2.0 (the "License") -// test for packet modification - -#packed "false" - -struct IPKey { - u32 dip:32; - u32 sip:32; -}; -struct IPLeaf { - u32 xdip:32; - u32 xsip:32; - u64 xlated_pkts:64; -}; -Table xlate(1024); - -struct skbuff { - u32 type:32; -}; - -u32 on_packet (struct skbuff *skb) { - u32 ret:32 = 1; - - u32 orig_dip:32 = 0; - u32 orig_sip:32 = 0; - struct IPLeaf *xleaf; - - goto proto::ethernet; - - state proto::ethernet { - } - - state proto::dot1q { - } - - state proto::ip { - orig_dip = $ip.dst; - orig_sip = $ip.src; - struct IPKey key = {.dip=orig_dip, .sip=orig_sip}; - xlate.lookup(key, xleaf) {}; - on_valid(xleaf) { - incr_cksum(@ip.hchecksum, orig_dip, xleaf.xdip); - incr_cksum(@ip.hchecksum, orig_sip, xleaf.xsip); - // the below are equivalent - pkt.rewrite_field($ip.dst, xleaf.xdip); - $ip.src = xleaf.xsip; - atomic_add(xleaf.xlated_pkts, 1); - } - } - - state proto::udp { - on_valid(xleaf) { - incr_cksum(@udp.crc, orig_dip, xleaf.xdip, 1); - incr_cksum(@udp.crc, orig_sip, xleaf.xsip, 1); - } - } - - state proto::tcp { - on_valid(xleaf) { - incr_cksum(@tcp.cksum, orig_dip, xleaf.xdip, 1); - incr_cksum(@tcp.cksum, orig_sip, xleaf.xsip, 1); - } - } - - state proto::vxlan { - } - - state proto::gre { - } - - state EOP { - return ret; - } -}