blob: 0bf0ce3240e1445841b7b2601634e1072ebede56 [file] [log] [blame]
#include <map>
#include <memory>
#include <string>
#include <vector>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Frontend/FrontendAction.h>
#include <clang/Rewrite/Core/Rewriter.h>
namespace clang {
class ASTConsumer;
class ASTContext;
class CompilerInstance;
}
namespace llvm {
class raw_ostream;
class StringRef;
}
namespace ebpf {
struct BPFTable {
int fd;
size_t key_size;
size_t leaf_size;
size_t max_entries;
};
// Type visitor and rewriter for B programs.
// 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
// and store the open handles in a map of table-to-fd's.
class BTypeVisitor : public clang::RecursiveASTVisitor<BTypeVisitor> {
public:
explicit BTypeVisitor(clang::ASTContext &C, clang::Rewriter &rewriter,
std::map<std::string, BPFTable> &tables);
bool VisitFunctionDecl(clang::FunctionDecl *D);
bool VisitCallExpr(clang::CallExpr *Call);
bool VisitVarDecl(clang::VarDecl *Decl);
bool VisitArraySubscriptExpr(clang::ArraySubscriptExpr *E);
bool VisitDeclRefExpr(clang::DeclRefExpr *E);
private:
clang::ASTContext &C;
clang::Rewriter &rewriter_; /// modifications to the source go into this class
llvm::raw_ostream &out_; /// for debugging
std::map<std::string, BPFTable> &tables_; /// store the open FDs
};
// A helper class to the frontend action, walks the decls
class BTypeConsumer : public clang::ASTConsumer {
public:
explicit BTypeConsumer(clang::ASTContext &C, clang::Rewriter &rewriter,
std::map<std::string, BPFTable> &tables);
bool HandleTopLevelDecl(clang::DeclGroupRef D) override;
private:
BTypeVisitor visitor_;
};
// Create a B program in 2 phases (everything else is normal C frontend):
// 1. Catch the map declarations and open the fd's
// 2. Capture the IR
class BFrontendAction : public clang::ASTFrontendAction {
public:
// Initialize with the output stream where the new source file contents
// should be written.
explicit BFrontendAction(llvm::raw_ostream &os);
// Called by clang when the AST has been completed, here the output stream
// will be flushed.
void EndSourceFileAction() override;
std::unique_ptr<clang::ASTConsumer>
CreateASTConsumer(clang::CompilerInstance &Compiler, llvm::StringRef InFile) override;
// take ownership of the table-to-fd mapping data structure
std::unique_ptr<std::map<std::string, BPFTable>> take_tables() { return move(tables_); }
private:
std::unique_ptr<clang::Rewriter> rewriter_;
llvm::raw_ostream &os_;
std::unique_ptr<std::map<std::string, BPFTable>> tables_;
};
} // namespace visitor