| // Generated by llvm2cpp - DO NOT MODIFY! |
| |
| #include <algorithm> |
| #include <map> |
| #include <string> |
| |
| #include <llvm/ADT/STLExtras.h> |
| #include <llvm/ExecutionEngine/MCJIT.h> |
| #include <llvm/ExecutionEngine/SectionMemoryManager.h> |
| #include <llvm/IRReader/IRReader.h> |
| #include <llvm/IR/IRPrintingPasses.h> |
| #include <llvm/IR/LegacyPassManager.h> |
| #include <llvm/IR/LLVMContext.h> |
| #include <llvm/IR/Module.h> |
| #include <llvm/IR/Verifier.h> |
| #include <llvm/Object/ObjectFile.h> |
| #include <llvm/Support/FormattedStream.h> |
| #include <llvm/Support/SourceMgr.h> |
| #include <llvm/Transforms/IPO.h> |
| #include <llvm/Transforms/IPO/PassManagerBuilder.h> |
| |
| #include "exception.h" |
| #include "parser.h" |
| #include "type_check.h" |
| #include "codegen_llvm.h" |
| #include "bpf_program.h" |
| |
| namespace ebpf { |
| |
| using std::get; |
| using std::make_tuple; |
| using std::map; |
| using std::move; |
| using std::string; |
| using std::tuple; |
| using std::unique_ptr; |
| using namespace llvm; |
| |
| // Snooping class to remember the sections as the JIT creates them |
| class MyMemoryManager : public SectionMemoryManager { |
| public: |
| |
| explicit MyMemoryManager(map<string, tuple<uint8_t *, uintptr_t>> *sections) |
| : sections_(sections) { |
| } |
| |
| virtual ~MyMemoryManager() {} |
| uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, |
| unsigned SectionID, |
| StringRef SectionName) override { |
| uint8_t *Addr = SectionMemoryManager::allocateCodeSection(Size, Alignment, SectionID, SectionName); |
| //printf("allocateCodeSection: %s Addr %p Size %ld Alignment %d SectionID %d\n", |
| // SectionName.str().c_str(), (void *)Addr, Size, Alignment, SectionID); |
| (*sections_)[SectionName.str()] = make_tuple(Addr, Size); |
| return Addr; |
| } |
| uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, |
| unsigned SectionID, StringRef SectionName, |
| bool isReadOnly) override { |
| uint8_t *Addr = SectionMemoryManager::allocateDataSection(Size, Alignment, SectionID, SectionName, isReadOnly); |
| //printf("allocateDataSection: %s Addr %p Size %ld Alignment %d SectionID %d RO %d\n", |
| // SectionName.str().c_str(), (void *)Addr, Size, Alignment, SectionID, isReadOnly); |
| (*sections_)[SectionName.str()] = make_tuple(Addr, Size); |
| return Addr; |
| } |
| map<string, tuple<uint8_t *, uintptr_t>> *sections_; |
| }; |
| |
| BPFProgram::BPFProgram(unsigned flags) |
| : flags_(flags) { |
| LLVMInitializeBPFTarget(); |
| LLVMInitializeBPFTargetMC(); |
| LLVMInitializeBPFTargetInfo(); |
| LLVMInitializeBPFAsmPrinter(); |
| LLVMLinkInMCJIT(); /* call empty function to force linking of MCJIT */ |
| } |
| |
| BPFProgram::~BPFProgram() { |
| engine_.reset(); |
| LLVMShutdown(); |
| } |
| |
| int BPFProgram::parse() { |
| int rc; |
| |
| proto_parser_ = make_unique<ebpf::cc::Parser>(proto_filename_); |
| rc = proto_parser_->parse(); |
| if (rc) return rc; |
| |
| parser_ = make_unique<ebpf::cc::Parser>(filename_); |
| rc = parser_->parse(); |
| if (rc) return rc; |
| |
| //ebpf::cc::Printer printer(stderr); |
| //printer.visit(parser_->root_node_); |
| |
| ebpf::cc::TypeCheck type_check(parser_->scopes_.get(), proto_parser_->scopes_.get(), parser_->pragmas_); |
| auto ret = type_check.visit(parser_->root_node_); |
| if (get<0>(ret) != 0 || get<1>(ret).size()) { |
| fprintf(stderr, "Type error @line=%d: %s\n", get<0>(ret), get<1>(ret).c_str()); |
| exit(1); |
| } |
| |
| codegen_ = ebpf::make_unique<ebpf::cc::CodegenLLVM>(mod_, parser_->scopes_.get(), |
| proto_parser_->scopes_.get(), |
| /*use_pre_header*/false, |
| parser_->pragma("name")); |
| ret = codegen_->visit(parser_->root_node_); |
| if (get<0>(ret) != 0 || get<1>(ret).size()) { |
| fprintf(stderr, "Codegen error @line=%d: %s\n", get<0>(ret), get<1>(ret).c_str()); |
| return get<0>(ret); |
| } |
| |
| return 0; |
| } |
| |
| string BPFProgram::load_helper() const { |
| // generated from bitops.cc -> bitops.bc -> hexdump -> bitops.h |
| #include "cc/bitops.h" |
| return string((const char *)bitops_bc, bitops_bc_len); |
| } |
| |
| // Load in a pre-built list of functions into the initial Module object, then |
| // build an ExecutionEngine. |
| int BPFProgram::init_engine() { |
| SMDiagnostic diag; |
| string helper = load_helper(); |
| MemoryBufferRef helper_mem(helper, "helper"); |
| unique_ptr<Module> mod = parseIR(helper_mem, diag, getGlobalContext()); |
| if (!mod) { |
| diag.print("bitops", errs()); |
| exit(1); |
| } |
| mod_ = mod.get(); |
| |
| mod_->setDataLayout("e-m:e-i64:64-f80:128-n8:16:32:64-S128"); |
| mod_->setTargetTriple("bpf"); |
| |
| for (auto fn = mod_->getFunctionList().begin(); fn != mod_->getFunctionList().end(); ++fn) |
| fn->addFnAttr(Attribute::AlwaysInline); |
| |
| string err; |
| engine_ = unique_ptr<ExecutionEngine>(EngineBuilder(move(mod)) |
| .setErrorStr(&err) |
| .setMCJITMemoryManager(make_unique<MyMemoryManager>(§ions_)) |
| .setMArch("bpf") |
| .create()); |
| if (!engine_) { |
| fprintf(stderr, "Could not create ExecutionEngine: %s\n", err.c_str()); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| void BPFProgram::dump_ir() { |
| legacy::PassManager PM; |
| PM.add(createPrintModulePass(outs())); |
| PM.run(*mod_); |
| } |
| |
| int BPFProgram::finalize() { |
| if (verifyModule(*mod_, &errs())) { |
| if (flags_ & 1) |
| dump_ir(); |
| return -1; |
| } |
| |
| legacy::PassManager PM; |
| PassManagerBuilder PMB; |
| PMB.OptLevel = 3; |
| PM.add(createFunctionInliningPass()); |
| PM.add(createAlwaysInlinerPass()); |
| PMB.populateModulePassManager(PM); |
| if (flags_ & 1) |
| PM.add(createPrintModulePass(outs())); |
| PM.run(*mod_); |
| |
| engine_->finalizeObject(); |
| |
| return 0; |
| } |
| |
| uint8_t * BPFProgram::start(const string &name) const { |
| auto section = sections_.find(name); |
| if (section == sections_.end()) |
| return nullptr; |
| |
| return get<0>(section->second); |
| } |
| |
| size_t BPFProgram::size(const string &name) const { |
| auto section = sections_.find(name); |
| if (section == sections_.end()) |
| return 0; |
| |
| return get<1>(section->second); |
| } |
| |
| char * BPFProgram::license() const { |
| auto section = sections_.find("license"); |
| if (section == sections_.end()) |
| return nullptr; |
| |
| return (char *)get<0>(section->second); |
| } |
| |
| int BPFProgram::table_fd(const string &name) const { |
| return codegen_->get_table_fd(name); |
| } |
| |
| int BPFProgram::load(const string &filename, const string &proto_filename) { |
| if (!sections_.empty()) { |
| fprintf(stderr, "Program already initialized\n"); |
| return -1; |
| } |
| filename_ = filename; |
| proto_filename_ = proto_filename; |
| if (int rc = init_engine()) |
| return rc; |
| if (int rc = parse()) |
| return rc; |
| if (int rc = finalize()) |
| return rc; |
| return 0; |
| } |
| |
| } // namespace ebpf |