Commit 52b0a903 authored by Brenden Blanco's avatar Brenden Blanco

Add framework to support map string reader (fuse feature)

Signed-off-by: default avatarBrenden Blanco <bblanco@plumgrid.com>
parent fdb3f74e
...@@ -16,6 +16,7 @@ configure_file(libbpfprog.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libbpfprog.pc @ONLY) ...@@ -16,6 +16,7 @@ configure_file(libbpfprog.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libbpfprog.pc @ONLY)
# prune unused llvm static library stuff when linking into the new .so # prune unused llvm static library stuff when linking into the new .so
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--exclude-libs=ALL") set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--exclude-libs=ALL")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-strict-aliasing")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
# if gcc 4.9 or higher is used, static libstdc++ is a good option # if gcc 4.9 or higher is used, static libstdc++ is a good option
...@@ -33,7 +34,9 @@ add_library(bpfprog SHARED bpf_common.cc bpf_module.cc libbpf.c) ...@@ -33,7 +34,9 @@ add_library(bpfprog SHARED bpf_common.cc bpf_module.cc libbpf.c)
# BPF is still experimental otherwise it should be available # BPF is still experimental otherwise it should be available
#llvm_map_components_to_libnames(llvm_libs bpf mcjit irreader passes) #llvm_map_components_to_libnames(llvm_libs bpf mcjit irreader passes)
llvm_map_components_to_libnames(llvm_libs mcjit irreader passes linker instrumentation objcarcopts bitwriter option) llvm_map_components_to_libnames(llvm_libs mcjit irreader passes linker
instrumentation objcarcopts bitwriter option x86codegen)
message(STATUS "llvm_libs=${llvm_libs}")
# order is important # order is important
set(clang_libs ${libclangFrontend} ${libclangSerialization} ${libclangDriver} ${libclangParse} set(clang_libs ${libclangFrontend} ${libclangSerialization} ${libclangDriver} ${libclangParse}
${libclangSema} ${libclangCodeGen} ${libclangAnalysis} ${libclangRewrite} ${libclangEdit} ${libclangSema} ${libclangCodeGen} ${libclangAnalysis} ${libclangRewrite} ${libclangEdit}
......
...@@ -146,4 +146,28 @@ const char * bpf_table_leaf_desc_id(void *program, size_t id) { ...@@ -146,4 +146,28 @@ const char * bpf_table_leaf_desc_id(void *program, size_t id) {
return mod->table_leaf_desc(id); return mod->table_leaf_desc(id);
} }
size_t bpf_table_key_size(void *program, const char *table_name) {
auto mod = static_cast<ebpf::BPFModule *>(program);
if (!mod) return 0;
return mod->table_key_size(table_name);
}
size_t bpf_table_key_size_id(void *program, size_t id) {
auto mod = static_cast<ebpf::BPFModule *>(program);
if (!mod) return 0;
return mod->table_key_size(id);
}
size_t bpf_table_leaf_size(void *program, const char *table_name) {
auto mod = static_cast<ebpf::BPFModule *>(program);
if (!mod) return 0;
return mod->table_leaf_size(table_name);
}
size_t bpf_table_leaf_size_id(void *program, size_t id) {
auto mod = static_cast<ebpf::BPFModule *>(program);
if (!mod) return 0;
return mod->table_leaf_size(id);
}
} }
...@@ -44,6 +44,10 @@ const char * bpf_table_key_desc(void *program, const char *table_name); ...@@ -44,6 +44,10 @@ const char * bpf_table_key_desc(void *program, const char *table_name);
const char * bpf_table_key_desc_id(void *program, size_t id); const char * bpf_table_key_desc_id(void *program, size_t id);
const char * bpf_table_leaf_desc(void *program, const char *table_name); const char * bpf_table_leaf_desc(void *program, const char *table_name);
const char * bpf_table_leaf_desc_id(void *program, size_t id); const char * bpf_table_leaf_desc_id(void *program, size_t id);
size_t bpf_table_key_size(void *program, const char *table_name);
size_t bpf_table_key_size_id(void *program, size_t id);
size_t bpf_table_leaf_size(void *program, const char *table_name);
size_t bpf_table_leaf_size_id(void *program, size_t id);
#ifdef __cplusplus #ifdef __cplusplus
} }
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <llvm/Support/FormattedStream.h> #include <llvm/Support/FormattedStream.h>
#include <llvm/Support/Host.h> #include <llvm/Support/Host.h>
#include <llvm/Support/SourceMgr.h> #include <llvm/Support/SourceMgr.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Transforms/IPO.h> #include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h> #include <llvm/Transforms/IPO/PassManagerBuilder.h>
...@@ -95,6 +96,8 @@ class MyMemoryManager : public SectionMemoryManager { ...@@ -95,6 +96,8 @@ class MyMemoryManager : public SectionMemoryManager {
BPFModule::BPFModule(unsigned flags) BPFModule::BPFModule(unsigned flags)
: flags_(flags), ctx_(new LLVMContext) { : flags_(flags), ctx_(new LLVMContext) {
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
LLVMInitializeBPFTarget(); LLVMInitializeBPFTarget();
LLVMInitializeBPFTargetMC(); LLVMInitializeBPFTargetMC();
LLVMInitializeBPFTargetInfo(); LLVMInitializeBPFTargetInfo();
...@@ -107,31 +110,34 @@ BPFModule::~BPFModule() { ...@@ -107,31 +110,34 @@ BPFModule::~BPFModule() {
ctx_.reset(); ctx_.reset();
} }
// load an entire c file as a module unique_ptr<ExecutionEngine> BPFModule::make_reader(LLVMContext &ctx) {
int BPFModule::load_cfile(const string &file, bool in_memory) { auto m = make_unique<Module>("scanf_reader", ctx);
clang_loader_ = make_unique<ClangLoader>(&*ctx_); Module *mod = &*m;
unique_ptr<Module> mod; auto structs = mod->getIdentifiedStructTypes();
if (clang_loader_->parse(&mod, &tables_, file, in_memory)) for (auto s : structs) {
return -1; fprintf(stderr, "struct %s\n", s->getName().str().c_str());
mod_ = &*mod; }
mod_->setDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128");
mod_->setTargetTriple("bpf-pc-linux");
for (auto fn = mod_->getFunctionList().begin(); fn != mod_->getFunctionList().end(); ++fn) dump_ir(*mod);
fn->addFnAttr(Attribute::AlwaysInline); run_pass_manager(*mod);
string err; string err;
engine_ = unique_ptr<ExecutionEngine>(EngineBuilder(move(mod)) map<string, tuple<uint8_t *, uintptr_t>> sections;
.setErrorStr(&err) EngineBuilder builder(move(m));
.setMCJITMemoryManager(make_unique<MyMemoryManager>(&sections_)) builder.setErrorStr(&err);
.setMArch("bpf") builder.setMCJITMemoryManager(make_unique<MyMemoryManager>(&sections));
.create()); builder.setUseOrcMCJITReplacement(true);
if (!engine_) { auto engine = unique_ptr<ExecutionEngine>(builder.create());
if (!engine)
fprintf(stderr, "Could not create ExecutionEngine: %s\n", err.c_str()); fprintf(stderr, "Could not create ExecutionEngine: %s\n", err.c_str());
return -1; return engine;
} }
// load an entire c file as a module
int BPFModule::load_cfile(const string &file, bool in_memory) {
clang_loader_ = make_unique<ClangLoader>(&*ctx_);
if (clang_loader_->parse(&mod_, &tables_, file, in_memory))
return -1;
return 0; return 0;
} }
...@@ -142,41 +148,44 @@ int BPFModule::load_cfile(const string &file, bool in_memory) { ...@@ -142,41 +148,44 @@ int BPFModule::load_cfile(const string &file, bool in_memory) {
// build an ExecutionEngine. // build an ExecutionEngine.
int BPFModule::load_includes(const string &tmpfile) { int BPFModule::load_includes(const string &tmpfile) {
clang_loader_ = make_unique<ClangLoader>(&*ctx_); clang_loader_ = make_unique<ClangLoader>(&*ctx_);
unique_ptr<Module> mod; if (clang_loader_->parse(&mod_, &tables_, tmpfile, false))
if (clang_loader_->parse(&mod, &tables_, tmpfile, false))
return -1; return -1;
mod_ = &*mod; return 0;
}
mod_->setDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128");
mod_->setTargetTriple("bpf-pc-linux");
int BPFModule::annotate() {
for (auto fn = mod_->getFunctionList().begin(); fn != mod_->getFunctionList().end(); ++fn) for (auto fn = mod_->getFunctionList().begin(); fn != mod_->getFunctionList().end(); ++fn)
fn->addFnAttr(Attribute::AlwaysInline); fn->addFnAttr(Attribute::AlwaysInline);
string err; //for (auto s : mod_->getIdentifiedStructTypes()) {
engine_ = unique_ptr<ExecutionEngine>(EngineBuilder(move(mod)) // llvm::errs() << "struct " << s->getName() << "\n";
.setErrorStr(&err) // for (auto e : s->elements()) {
.setMCJITMemoryManager(make_unique<MyMemoryManager>(&sections_)) // llvm::errs() << " ";
.setMArch("bpf") // e->print(llvm::errs());
.create()); // llvm::errs() << "\n";
if (!engine_) { // }
fprintf(stderr, "Could not create ExecutionEngine: %s\n", err.c_str()); //}
return -1;
if (1) {
auto engine = make_reader(*ctx_);
if (engine)
engine->finalizeObject();
} }
return 0; return 0;
} }
void BPFModule::dump_ir() { void BPFModule::dump_ir(Module &mod) {
legacy::PassManager PM; legacy::PassManager PM;
PM.add(createPrintModulePass(outs())); PM.add(createPrintModulePass(outs()));
PM.run(*mod_); PM.run(mod);
} }
int BPFModule::finalize() { int BPFModule::run_pass_manager(Module &mod) {
if (verifyModule(*mod_, &errs())) { if (verifyModule(mod, &errs())) {
if (flags_ & 1) if (flags_ & 1)
dump_ir(); dump_ir(mod);
return -1; return -1;
} }
...@@ -188,7 +197,30 @@ int BPFModule::finalize() { ...@@ -188,7 +197,30 @@ int BPFModule::finalize() {
PMB.populateModulePassManager(PM); PMB.populateModulePassManager(PM);
if (flags_ & 1) if (flags_ & 1)
PM.add(createPrintModulePass(outs())); PM.add(createPrintModulePass(outs()));
PM.run(*mod_); PM.run(mod);
return 0;
}
int BPFModule::finalize() {
Module *mod = &*mod_;
mod->setDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128");
mod->setTargetTriple("bpf-pc-linux");
string err;
EngineBuilder builder(move(mod_));
builder.setErrorStr(&err);
builder.setMCJITMemoryManager(make_unique<MyMemoryManager>(&sections_));
builder.setMArch("bpf");
builder.setUseOrcMCJITReplacement(true);
engine_ = unique_ptr<ExecutionEngine>(builder.create());
if (!engine_) {
fprintf(stderr, "Could not create ExecutionEngine: %s\n", err.c_str());
return -1;
}
if (int rc = run_pass_manager(*mod))
return rc;
engine_->finalizeObject(); engine_->finalizeObject();
...@@ -308,6 +340,27 @@ const char * BPFModule::table_leaf_desc(const string &name) const { ...@@ -308,6 +340,27 @@ const char * BPFModule::table_leaf_desc(const string &name) const {
if (table_it == tables_->end()) return nullptr; if (table_it == tables_->end()) return nullptr;
return table_it->second.leaf_desc.c_str(); return table_it->second.leaf_desc.c_str();
} }
size_t BPFModule::table_key_size(size_t id) const {
if (id >= table_names_.size()) return 0;
return table_key_size(table_names_[id]);
}
size_t BPFModule::table_key_size(const string &name) const {
if (b_loader_) return 0;
auto table_it = tables_->find(name);
if (table_it == tables_->end()) return 0;
return table_it->second.key_size;
}
size_t BPFModule::table_leaf_size(size_t id) const {
if (id >= table_names_.size()) return 0;
return table_leaf_size(table_names_[id]);
}
size_t BPFModule::table_leaf_size(const string &name) const {
if (b_loader_) return 0;
auto table_it = tables_->find(name);
if (table_it == tables_->end()) return 0;
return table_it->second.leaf_size;
}
// load a B file, which comes in two parts // load a B file, which comes in two parts
int BPFModule::load_b(const string &filename, const string &proto_filename) { int BPFModule::load_b(const string &filename, const string &proto_filename) {
...@@ -324,9 +377,11 @@ int BPFModule::load_b(const string &filename, const string &proto_filename) { ...@@ -324,9 +377,11 @@ int BPFModule::load_b(const string &filename, const string &proto_filename) {
// pass the partially compiled module to the B frontend to continue with. // pass the partially compiled module to the B frontend to continue with.
if (int rc = load_includes(BCC_INSTALL_PREFIX "/share/bcc/include/bcc/helpers.h")) if (int rc = load_includes(BCC_INSTALL_PREFIX "/share/bcc/include/bcc/helpers.h"))
return rc; return rc;
if (int rc = annotate())
return rc;
b_loader_.reset(new BLoader); b_loader_.reset(new BLoader);
if (int rc = b_loader_->parse(mod_, filename, proto_filename)) if (int rc = b_loader_->parse(&*mod_, filename, proto_filename))
return rc; return rc;
if (int rc = finalize()) if (int rc = finalize())
return rc; return rc;
...@@ -345,6 +400,8 @@ int BPFModule::load_c(const string &filename) { ...@@ -345,6 +400,8 @@ int BPFModule::load_c(const string &filename) {
} }
if (int rc = load_cfile(filename, false)) if (int rc = load_cfile(filename, false))
return rc; return rc;
if (int rc = annotate())
return rc;
if (int rc = finalize()) if (int rc = finalize())
return rc; return rc;
return 0; return 0;
...@@ -358,6 +415,8 @@ int BPFModule::load_string(const string &text) { ...@@ -358,6 +415,8 @@ int BPFModule::load_string(const string &text) {
} }
if (int rc = load_cfile(text, true)) if (int rc = load_cfile(text, true))
return rc; return rc;
if (int rc = annotate())
return rc;
if (int rc = finalize()) if (int rc = finalize())
return rc; return rc;
......
...@@ -39,11 +39,14 @@ class BPFModule { ...@@ -39,11 +39,14 @@ class BPFModule {
int init_engine(); int init_engine();
int parse(llvm::Module *mod); int parse(llvm::Module *mod);
int finalize(); int finalize();
void dump_ir(); int annotate();
std::unique_ptr<llvm::ExecutionEngine> make_reader(llvm::LLVMContext &ctx);
void dump_ir(llvm::Module &mod);
int load_file_module(std::unique_ptr<llvm::Module> *mod, const std::string &file, bool in_memory); int load_file_module(std::unique_ptr<llvm::Module> *mod, const std::string &file, bool in_memory);
int load_includes(const std::string &tmpfile); int load_includes(const std::string &tmpfile);
int load_cfile(const std::string &file, bool in_memory); int load_cfile(const std::string &file, bool in_memory);
int kbuild_flags(const char *uname_release, std::vector<std::string> *cflags); int kbuild_flags(const char *uname_release, std::vector<std::string> *cflags);
int run_pass_manager(llvm::Module &mod);
public: public:
BPFModule(unsigned flags); BPFModule(unsigned flags);
~BPFModule(); ~BPFModule();
...@@ -62,8 +65,12 @@ class BPFModule { ...@@ -62,8 +65,12 @@ class BPFModule {
const char * table_name(size_t id) const; const char * table_name(size_t id) const;
const char * table_key_desc(size_t id) const; const char * table_key_desc(size_t id) const;
const char * table_key_desc(const std::string &name) const; const char * table_key_desc(const std::string &name) const;
size_t table_key_size(size_t id) const;
size_t table_key_size(const std::string &name) const;
const char * table_leaf_desc(size_t id) const; const char * table_leaf_desc(size_t id) const;
const char * table_leaf_desc(const std::string &name) const; const char * table_leaf_desc(const std::string &name) const;
size_t table_leaf_size(size_t id) const;
size_t table_leaf_size(const std::string &name) const;
char * license() const; char * license() const;
unsigned kern_version() const; unsigned kern_version() const;
private: private:
...@@ -72,7 +79,7 @@ class BPFModule { ...@@ -72,7 +79,7 @@ class BPFModule {
std::string proto_filename_; std::string proto_filename_;
std::unique_ptr<llvm::LLVMContext> ctx_; std::unique_ptr<llvm::LLVMContext> ctx_;
std::unique_ptr<llvm::ExecutionEngine> engine_; std::unique_ptr<llvm::ExecutionEngine> engine_;
llvm::Module *mod_; std::unique_ptr<llvm::Module> mod_;
std::unique_ptr<BLoader> b_loader_; std::unique_ptr<BLoader> b_loader_;
std::unique_ptr<ClangLoader> clang_loader_; std::unique_ptr<ClangLoader> clang_loader_;
std::map<std::string, std::tuple<uint8_t *, uintptr_t>> sections_; std::map<std::string, std::tuple<uint8_t *, uintptr_t>> sections_;
......
...@@ -51,6 +51,13 @@ bool BMapDeclVisitor::VisitFieldDecl(FieldDecl *D) { ...@@ -51,6 +51,13 @@ bool BMapDeclVisitor::VisitFieldDecl(FieldDecl *D) {
result_ += "\","; result_ += "\",";
return true; return true;
} }
bool BMapDeclVisitor::TraverseRecordDecl(RecordDecl *D) {
// skip children, handled in Visit...
if (!WalkUpFromRecordDecl(D))
return false;
return true;
}
bool BMapDeclVisitor::VisitRecordDecl(RecordDecl *D) { bool BMapDeclVisitor::VisitRecordDecl(RecordDecl *D) {
result_ += "[\""; result_ += "[\"";
result_ += D->getName(); result_ += D->getName();
...@@ -65,7 +72,7 @@ bool BMapDeclVisitor::VisitRecordDecl(RecordDecl *D) { ...@@ -65,7 +72,7 @@ bool BMapDeclVisitor::VisitRecordDecl(RecordDecl *D) {
if (!D->getDefinition()->field_empty()) if (!D->getDefinition()->field_empty())
result_.erase(result_.end() - 2); result_.erase(result_.end() - 2);
result_ += "]]"; result_ += "]]";
return false; return true;
} }
bool BMapDeclVisitor::VisitTagType(const TagType *T) { bool BMapDeclVisitor::VisitTagType(const TagType *T) {
return TraverseDecl(T->getDecl()->getDefinition()); return TraverseDecl(T->getDecl()->getDefinition());
...@@ -80,6 +87,64 @@ bool BMapDeclVisitor::VisitBuiltinType(const BuiltinType *T) { ...@@ -80,6 +87,64 @@ bool BMapDeclVisitor::VisitBuiltinType(const BuiltinType *T) {
return true; return true;
} }
BScanfVisitor::BScanfVisitor(ASTContext &C)
: C(C), n_args_(0) {}
bool BScanfVisitor::VisitFieldDecl(FieldDecl *D) {
args_ += "&val->" + D->getName().str();
++n_args_;
return true;
}
bool BScanfVisitor::TraverseRecordDecl(RecordDecl *D) {
// skip children, handled in Visit...
if (!WalkUpFromRecordDecl(D))
return false;
return true;
}
bool BScanfVisitor::VisitRecordDecl(RecordDecl *D) {
if (type_.empty())
type_ = "struct " + D->getDefinition()->getName().str();
fmt_ += "{ ";
for (auto F : D->getDefinition()->fields()) {
TraverseDecl(F);
if (F->isBitField())
fmt_ += ", " + to_string(F->getBitWidthValue(C));
fmt_ += ", ";
args_ += ", ";
}
if (!D->getDefinition()->field_empty()) {
fmt_.erase(fmt_.end() - 2);
args_.erase(args_.end() - 2);
}
fmt_ += "}";
return true;
}
bool BScanfVisitor::VisitTagType(const TagType *T) {
return TraverseDecl(T->getDecl()->getDefinition());
}
bool BScanfVisitor::VisitTypedefType(const TypedefType *T) {
return TraverseDecl(T->getDecl());
}
bool BScanfVisitor::VisitBuiltinType(const BuiltinType *T) {
if (type_.empty()) {
type_ = T->getName(C.getPrintingPolicy());
args_ += "val";
++n_args_;
}
fmt_ += "%i";
return true;
}
void BScanfVisitor::finalize(string &result) {
result = "int read_entry(const char *str, void *buf) {\n";
result += " " + type_ + " *val = buf;\n";
result += " int n = sscanf(str, \"" + fmt_ + "\", " + args_ + ");\n";
result += " if (n < " + std::to_string(n_args_) + ") return -1;\n";
result += " return 0;\n";
result += "}\n";
}
BTypeVisitor::BTypeVisitor(ASTContext &C, Rewriter &rewriter, map<string, BPFTable> &tables) BTypeVisitor::BTypeVisitor(ASTContext &C, Rewriter &rewriter, map<string, BPFTable> &tables)
: C(C), rewriter_(rewriter), out_(llvm::errs()), tables_(tables) { : C(C), rewriter_(rewriter), out_(llvm::errs()), tables_(tables) {
} }
...@@ -361,11 +426,21 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) { ...@@ -361,11 +426,21 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
if (F->getName() == "key") { if (F->getName() == "key") {
table.key_size = sz; table.key_size = sz;
BMapDeclVisitor visitor(C, table.key_desc); BMapDeclVisitor visitor(C, table.key_desc);
visitor.TraverseType(F->getType()); if (!visitor.TraverseType(F->getType()))
return false;
BScanfVisitor scanf_visitor(C);
if (!scanf_visitor.TraverseType(F->getType()))
return false;
scanf_visitor.finalize(table.key_reader);
} else if (F->getName() == "leaf") { } else if (F->getName() == "leaf") {
table.leaf_size = sz; table.leaf_size = sz;
BMapDeclVisitor visitor(C, table.leaf_desc); BMapDeclVisitor visitor(C, table.leaf_desc);
visitor.TraverseType(F->getType()); if (!visitor.TraverseType(F->getType()))
return false;
BScanfVisitor scanf_visitor(C);
if (!scanf_visitor.TraverseType(F->getType()))
return false;
scanf_visitor.finalize(table.leaf_reader);
} else if (F->getName() == "data") { } else if (F->getName() == "data") {
table.max_entries = sz / table.leaf_size; table.max_entries = sz / table.leaf_size;
} }
......
...@@ -43,23 +43,44 @@ struct BPFTable { ...@@ -43,23 +43,44 @@ struct BPFTable {
size_t max_entries; size_t max_entries;
std::string key_desc; std::string key_desc;
std::string leaf_desc; std::string leaf_desc;
std::string key_reader;
std::string leaf_reader;
}; };
// Helper visitor for constructing a string representation of a key/leaf decl // Helper visitor for constructing a string representation of a key/leaf decl
class BMapDeclVisitor : public clang::RecursiveASTVisitor<BMapDeclVisitor> { class BMapDeclVisitor : public clang::RecursiveASTVisitor<BMapDeclVisitor> {
public: public:
explicit BMapDeclVisitor(clang::ASTContext &C, std::string &result); explicit BMapDeclVisitor(clang::ASTContext &C, std::string &result);
bool TraverseRecordDecl(clang::RecordDecl *Decl);
bool VisitRecordDecl(clang::RecordDecl *Decl); bool VisitRecordDecl(clang::RecordDecl *Decl);
bool VisitFieldDecl(clang::FieldDecl *Decl); bool VisitFieldDecl(clang::FieldDecl *Decl);
bool VisitBuiltinType(const clang::BuiltinType *T); bool VisitBuiltinType(const clang::BuiltinType *T);
bool VisitTypedefType(const clang::TypedefType *T); bool VisitTypedefType(const clang::TypedefType *T);
bool VisitTagType(const clang::TagType *T); bool VisitTagType(const clang::TagType *T);
const std::string & str() const { return result_; }
private: private:
clang::ASTContext &C; clang::ASTContext &C;
std::string &result_; std::string &result_;
}; };
// Helper visitor for constructing a fscanf routine for key/leaf decl
class BScanfVisitor : public clang::RecursiveASTVisitor<BScanfVisitor> {
public:
explicit BScanfVisitor(clang::ASTContext &C);
bool TraverseRecordDecl(clang::RecordDecl *Decl);
bool VisitRecordDecl(clang::RecordDecl *Decl);
bool VisitFieldDecl(clang::FieldDecl *Decl);
bool VisitBuiltinType(const clang::BuiltinType *T);
bool VisitTypedefType(const clang::TypedefType *T);
bool VisitTagType(const clang::TagType *T);
void finalize(std::string &result);
private:
clang::ASTContext &C;
size_t n_args_;
std::string fmt_;
std::string args_;
std::string type_;
};
// Type visitor and rewriter for B programs. // Type visitor and rewriter for B programs.
// It will look for B-specific features and rewrite them into a valid // It will look for B-specific features and rewrite them into a valid
// C program. As part of the processing, open the necessary BPF tables // C program. As part of the processing, open the necessary BPF tables
......
...@@ -46,5 +46,16 @@ int count_foo(struct pt_regs *ctx, unsigned long a, unsigned long b) { ...@@ -46,5 +46,16 @@ int count_foo(struct pt_regs *ctx, unsigned long a, unsigned long b) {
b = BPF(text=text, debug=0) b = BPF(text=text, debug=0)
fn = b.load_func("count_foo", BPF.KPROBE) fn = b.load_func("count_foo", BPF.KPROBE)
def test_scanf(self):
text = """
BPF_TABLE("hash", int, struct { int a; int b; }, stats, 10);
int foo(void *ctx) {
return 0;
}
"""
b = BPF(text=text, debug=0)
fn = b.load_func("foo", BPF.KPROBE)
# todo: the actual test
if __name__ == "__main__": if __name__ == "__main__":
main() main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment