Commit d56fff02 authored by yonghong-song's avatar yonghong-song Committed by GitHub

Merge pull request #1332 from iovisor/ast_dev

annotate program tag
parents 6aec3099 4f47e3b5
......@@ -57,6 +57,10 @@ if(NOT DEFINED BCC_KERNEL_MODULES_DIR)
set(BCC_KERNEL_MODULES_DIR "/lib/modules")
endif()
if(NOT DEFINED BCC_PROG_TAG_DIR)
set(BCC_PROG_TAG_DIR "/var/tmp/bcc")
endif()
# As reported in issue #735, GCC 6 has some behavioral problems when
# dealing with -isystem. Hence, skip the warning optimization
# altogether on that compiler.
......
......@@ -14,7 +14,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/compat)
add_definitions(${LLVM_DEFINITIONS})
configure_file(libbcc.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libbcc.pc @ONLY)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -DBCC_PROG_TAG_DIR='\"${BCC_PROG_TAG_DIR}\"'")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
include(static_libstdc++)
......
......@@ -488,6 +488,10 @@ StatusTuple BPF::load_func(const std::string& func_name,
if (fd < 0)
return StatusTuple(-1, "Failed to load %s: %d", func_name.c_str(), fd);
bpf_module_->annotate_prog_tag(func_name, fd,
reinterpret_cast<struct bpf_insn*>(func_start),
func_size);
funcs_[func_name] = fd;
return StatusTuple(0);
}
......
......@@ -113,6 +113,7 @@ BPFModule::BPFModule(unsigned flags, TableStorage *ts)
local_ts_ = createSharedTableStorage();
ts_ = &*local_ts_;
}
func_src_ = ebpf::make_unique<FuncSource>();
}
static StatusTuple unimplemented_sscanf(const char *, void *) {
......@@ -133,6 +134,7 @@ BPFModule::~BPFModule() {
engine_.reset();
rw_engine_.reset();
ctx_.reset();
func_src_.reset();
ts_->DeletePrefix(Path({id_}));
}
......@@ -456,7 +458,7 @@ unique_ptr<ExecutionEngine> BPFModule::finalize_rw(unique_ptr<Module> m) {
// load an entire c file as a module
int BPFModule::load_cfile(const string &file, bool in_memory, const char *cflags[], int ncflags) {
clang_loader_ = ebpf::make_unique<ClangLoader>(&*ctx_, flags_);
if (clang_loader_->parse(&mod_, *ts_, file, in_memory, cflags, ncflags, id_))
if (clang_loader_->parse(&mod_, *ts_, file, in_memory, cflags, ncflags, id_, *func_src_))
return -1;
return 0;
}
......@@ -468,7 +470,7 @@ int BPFModule::load_cfile(const string &file, bool in_memory, const char *cflags
// build an ExecutionEngine.
int BPFModule::load_includes(const string &text) {
clang_loader_ = ebpf::make_unique<ClangLoader>(&*ctx_, flags_);
if (clang_loader_->parse(&mod_, *ts_, text, true, nullptr, 0, ""))
if (clang_loader_->parse(&mod_, *ts_, text, true, nullptr, 0, "", *func_src_))
return -1;
return 0;
}
......@@ -632,6 +634,68 @@ uint8_t * BPFModule::function_start(const string &name) const {
return get<0>(section->second);
}
const char * BPFModule::function_source(const string &name) const {
return func_src_->src(name);
}
const char * BPFModule::function_source_rewritten(const string &name) const {
return func_src_->src_rewritten(name);
}
int BPFModule::annotate_prog_tag(const string &name, int prog_fd,
struct bpf_insn *insns, int prog_len) {
unsigned long long tag1, tag2;
int err;
err = bpf_prog_compute_tag(insns, prog_len, &tag1);
if (err)
return err;
err = bpf_prog_get_tag(prog_fd, &tag2);
if (err)
return err;
if (tag1 != tag2) {
fprintf(stderr, "prog tag mismatch %llx %llx\n", tag1, tag2);
return -1;
}
err = mkdir(BCC_PROG_TAG_DIR, 0777);
if (err && errno != EEXIST) {
fprintf(stderr, "cannot create " BCC_PROG_TAG_DIR "\n");
return -1;
}
char buf[128];
::snprintf(buf, sizeof(buf), BCC_PROG_TAG_DIR "/bpf_prog_%llx", tag1);
err = mkdir(buf, 0777);
if (err && errno != EEXIST) {
fprintf(stderr, "cannot create %s\n", buf);
return -1;
}
::snprintf(buf, sizeof(buf), BCC_PROG_TAG_DIR "/bpf_prog_%llx/%s.c",
tag1, name.data());
FileDesc fd(open(buf, O_CREAT | O_WRONLY | O_TRUNC, 0644));
if (fd < 0) {
fprintf(stderr, "cannot create %s\n", buf);
return -1;
}
const char *src = function_source(name);
write(fd, src, strlen(src));
::snprintf(buf, sizeof(buf), BCC_PROG_TAG_DIR "/bpf_prog_%llx/%s.rewritten.c",
tag1, name.data());
fd = open(buf, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd < 0) {
fprintf(stderr, "cannot create %s\n", buf);
return -1;
}
src = function_source_rewritten(name);
write(fd, src, strlen(src));
return 0;
}
size_t BPFModule::function_size(size_t id) const {
if (id >= function_names_.size())
return 0;
......
......@@ -37,6 +37,7 @@ class TableDesc;
class TableStorage;
class BLoader;
class ClangLoader;
class FuncSource;
class BPFModule {
private:
......@@ -68,6 +69,10 @@ class BPFModule {
size_t num_functions() const;
uint8_t * function_start(size_t id) const;
uint8_t * function_start(const std::string &name) const;
const char * function_source(const std::string &name) const;
const char * function_source_rewritten(const std::string &name) const;
int annotate_prog_tag(const std::string &name, int fd,
struct bpf_insn *insn, int prog_len);
const char * function_name(size_t id) const;
size_t function_size(size_t id) const;
size_t function_size(const std::string &name) const;
......@@ -108,6 +113,7 @@ class BPFModule {
std::unique_ptr<llvm::Module> mod_;
std::unique_ptr<BLoader> b_loader_;
std::unique_ptr<ClangLoader> clang_loader_;
std::unique_ptr<FuncSource> func_src_;
std::map<std::string, std::tuple<uint8_t *, uintptr_t>> sections_;
std::vector<TableDesc *> tables_;
std::map<std::string, size_t> table_names_;
......
......@@ -26,6 +26,7 @@
#include <clang/Rewrite/Core/Rewriter.h>
#include "b_frontend_action.h"
#include "loader.h"
#include "common.h"
#include "table_storage.h"
......@@ -222,6 +223,9 @@ bool BTypeVisitor::VisitFunctionDecl(FunctionDecl *D) {
auto real_start_loc = rewriter_.getSourceMgr().getFileLoc(D->getLocStart());
if (D->isExternallyVisible() && D->hasBody()) {
current_fn_ = D->getName();
string bd = rewriter_.getRewrittenText(expansionRange(D->getSourceRange()));
fe_.func_src_.set_src(current_fn_, bd);
fe_.func_range_[current_fn_] = expansionRange(D->getSourceRange());
string attr = string("__attribute__((section(\"") + BPF_FN_PREFIX + D->getName().str() + "\")))\n";
rewriter_.InsertText(real_start_loc, attr);
if (D->param_size() > MAX_CALLING_CONV_REGS + 1) {
......@@ -776,12 +780,18 @@ bool ProbeConsumer::HandleTopLevelDecl(DeclGroupRef Group) {
}
BFrontendAction::BFrontendAction(llvm::raw_ostream &os, unsigned flags, TableStorage &ts,
const std::string &id)
: os_(os), flags_(flags), ts_(ts), id_(id), rewriter_(new Rewriter) {}
const std::string &id, FuncSource& func_src)
: os_(os), flags_(flags), ts_(ts), id_(id), rewriter_(new Rewriter), func_src_(func_src) {}
void BFrontendAction::EndSourceFileAction() {
if (flags_ & DEBUG_PREPROCESSOR)
rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).write(llvm::errs());
for (auto func : func_range_) {
auto f = func.first;
string bd = rewriter_->getRewrittenText(func_range_[f]);
func_src_.set_src_rewritten(f, bd);
}
rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).write(os_);
os_.flush();
}
......
......@@ -42,6 +42,7 @@ class StringRef;
namespace ebpf {
class BFrontendAction;
class FuncSource;
// Type visitor and rewriter for B programs.
// It will look for B-specific features and rewrite them into a valid
......@@ -122,7 +123,8 @@ class BFrontendAction : public clang::ASTFrontendAction {
public:
// Initialize with the output stream where the new source file contents
// should be written.
BFrontendAction(llvm::raw_ostream &os, unsigned flags, TableStorage &ts, const std::string &id);
BFrontendAction(llvm::raw_ostream &os, unsigned flags, TableStorage &ts, const std::string &id,
FuncSource& func_src);
// Called by clang when the AST has been completed, here the output stream
// will be flushed.
......@@ -141,6 +143,9 @@ class BFrontendAction : public clang::ASTFrontendAction {
TableStorage &ts_;
std::string id_;
std::unique_ptr<clang::Rewriter> rewriter_;
friend class BTypeVisitor;
std::map<std::string, clang::SourceRange> func_range_;
FuncSource& func_src_;
};
} // namespace visitor
......@@ -105,7 +105,8 @@ std::pair<bool, string> get_kernel_path_info(const string kdir)
}
int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts, const string &file,
bool in_memory, const char *cflags[], int ncflags, const std::string &id) {
bool in_memory, const char *cflags[], int ncflags, const std::string &id,
FuncSource& func_src) {
using namespace clang;
string main_path = "/virtual/main.c";
......@@ -276,7 +277,7 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts, const st
// capture the rewritten c file
string out_str1;
llvm::raw_string_ostream os1(out_str1);
BFrontendAction bact(os1, flags_, ts, id);
BFrontendAction bact(os1, flags_, ts, id, func_src);
if (!compiler1.ExecuteAction(bact))
return -1;
unique_ptr<llvm::MemoryBuffer> out_buf1 = llvm::MemoryBuffer::getMemBuffer(out_str1);
......@@ -312,5 +313,26 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts, const st
return 0;
}
const char * FuncSource::src(const std::string& name) {
auto src = funcs_.find(name);
if (src == funcs_.end())
return "";
return src->second.src_.data();
}
const char * FuncSource::src_rewritten(const std::string& name) {
auto src = funcs_.find(name);
if (src == funcs_.end())
return "";
return src->second.src_rewritten_.data();
}
void FuncSource::set_src(const std::string& name, const std::string& src) {
funcs_[name].src_ = src;
}
void FuncSource::set_src_rewritten(const std::string& name, const std::string& src) {
funcs_[name].src_rewritten_ = src;
}
} // namespace ebpf
......@@ -30,12 +30,29 @@ class MemoryBuffer;
namespace ebpf {
class FuncSource {
class SourceCode {
public:
SourceCode(const std::string& s1 = "", const std::string& s2 = ""): src_(s1), src_rewritten_(s2) {}
std::string src_;
std::string src_rewritten_;
};
std::map<std::string, SourceCode> funcs_;
public:
FuncSource() {}
const char * src(const std::string& name);
const char * src_rewritten(const std::string& name);
void set_src(const std::string& name, const std::string& src);
void set_src_rewritten(const std::string& name, const std::string& src);
};
class ClangLoader {
public:
explicit ClangLoader(llvm::LLVMContext *ctx, unsigned flags);
~ClangLoader();
int parse(std::unique_ptr<llvm::Module> *mod, TableStorage &ts, const std::string &file,
bool in_memory, const char *cflags[], int ncflags, const std::string &id);
bool in_memory, const char *cflags[], int ncflags, const std::string &id,
FuncSource& func_src);
private:
static std::map<std::string, std::unique_ptr<llvm::MemoryBuffer>> remapped_files_;
......
......@@ -42,6 +42,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/if_alg.h>
#include "libbpf.h"
#include "perf_reader.h"
......@@ -219,6 +220,115 @@ static void bpf_print_hints(char *log)
}
#define ROUND_UP(x, n) (((x) + (n) - 1u) & ~((n) - 1u))
int bpf_obj_get_info(int prog_map_fd, void *info, int *info_len)
{
union bpf_attr attr;
int err;
memset(&attr, 0, sizeof(attr));
attr.info.bpf_fd = prog_map_fd;
attr.info.info_len = *info_len;
attr.info.info = ptr_to_u64(info);
err = syscall(__NR_bpf, BPF_OBJ_GET_INFO_BY_FD, &attr, sizeof(attr));
if (!err)
*info_len = attr.info.info_len;
return err;
}
int bpf_prog_compute_tag(const struct bpf_insn *insns, int prog_len,
unsigned long long *ptag)
{
struct sockaddr_alg alg = {
.salg_family = AF_ALG,
.salg_type = "hash",
.salg_name = "sha1",
};
int shafd = socket(AF_ALG, SOCK_SEQPACKET, 0);
if (shafd < 0) {
fprintf(stderr, "sha1 socket not available %s\n", strerror(errno));
return -1;
}
int ret = bind(shafd, (struct sockaddr *)&alg, sizeof(alg));
if (ret < 0) {
fprintf(stderr, "sha1 bind fail %s\n", strerror(errno));
close(shafd);
return ret;
}
int shafd2 = accept(shafd, NULL, 0);
if (shafd2 < 0) {
fprintf(stderr, "sha1 accept fail %s\n", strerror(errno));
close(shafd);
return -1;
}
struct bpf_insn prog[prog_len / 8];
bool map_ld_seen = false;
int i;
for (i = 0; i < prog_len / 8; i++) {
prog[i] = insns[i];
if (insns[i].code == (BPF_LD | BPF_DW | BPF_IMM) &&
insns[i].src_reg == BPF_PSEUDO_MAP_FD &&
!map_ld_seen) {
prog[i].imm = 0;
map_ld_seen = true;
} else if (insns[i].code == 0 && map_ld_seen) {
prog[i].imm = 0;
map_ld_seen = false;
} else {
map_ld_seen = false;
}
}
ret = write(shafd2, prog, prog_len);
if (ret != prog_len) {
fprintf(stderr, "sha1 write fail %s\n", strerror(errno));
close(shafd2);
close(shafd);
return -1;
}
union {
unsigned char sha[20];
unsigned long long tag;
} u = {};
ret = read(shafd2, u.sha, 20);
if (ret != 20) {
fprintf(stderr, "sha1 read fail %s\n", strerror(errno));
close(shafd2);
close(shafd);
return -1;
}
*ptag = __builtin_bswap64(u.tag);
return 0;
}
int bpf_prog_get_tag(int fd, unsigned long long *ptag)
{
char fmt[64];
snprintf(fmt, sizeof(fmt), "/proc/self/fdinfo/%d", fd);
FILE * f = fopen(fmt, "r");
if (!f) {
/* fprintf(stderr, "failed to open fdinfo %s\n", strerror(errno));*/
return -1;
}
fgets(fmt, sizeof(fmt), f); // pos
fgets(fmt, sizeof(fmt), f); // flags
fgets(fmt, sizeof(fmt), f); // mnt_id
fgets(fmt, sizeof(fmt), f); // prog_type
fgets(fmt, sizeof(fmt), f); // prog_jited
fgets(fmt, sizeof(fmt), f); // prog_tag
fclose(f);
char *p = strchr(fmt, ':');
if (!p) {
/* fprintf(stderr, "broken fdinfo %s\n", fmt);*/
return -2;
}
unsigned long long tag = 0;
sscanf(p + 1, "%llx", &tag);
*ptag = tag;
return 0;
}
int bpf_prog_load(enum bpf_prog_type prog_type,
const struct bpf_insn *insns, int prog_len,
const char *license, unsigned kern_version,
......
......@@ -89,6 +89,10 @@ int bpf_close_perf_event_fd(int fd);
int bpf_obj_pin(int fd, const char *pathname);
int bpf_obj_get(const char *pathname);
int bpf_obj_get_info(int prog_map_fd, void *info, int *info_len);
int bpf_prog_compute_tag(const struct bpf_insn *insns, int prog_len,
unsigned long long *tag);
int bpf_prog_get_tag(int fd, unsigned long long *tag);
#define LOG_BUF_SIZE 65536
......
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