From 76115d2f001505b7c3ac9de879cb2a09f1941e5d Mon Sep 17 00:00:00 2001 From: Dave Marchevsky Date: Tue, 12 Oct 2021 16:21:36 -0700 Subject: [PATCH 1/2] bpf_module: clean up some ".bpf.fn." usage Replace usage of the raw string with macro. Signed-off-by: Dave Marchevsky --- src/cc/bpf_module.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/bpf_module.cc b/src/cc/bpf_module.cc index 36f9582a562e..7fb078b7d804 100644 --- a/src/cc/bpf_module.cc +++ b/src/cc/bpf_module.cc @@ -428,7 +428,7 @@ int BPFModule::load_maps(sec_map_def §ions) { // update instructions for (auto section : sections) { auto sec_name = section.first; - if (strncmp(".bpf.fn.", sec_name.c_str(), 8) == 0) { + if (strncmp(BPF_FN_PREFIX, sec_name.c_str(), 8) == 0) { uint8_t *addr = get<0>(section.second); uintptr_t size = get<1>(section.second); struct bpf_insn *insns = (struct bpf_insn *)addr; @@ -903,7 +903,7 @@ int BPFModule::bcc_func_load(int prog_type, const char *name, int btf_fd = btf_->get_fd(); char secname[256]; - ::snprintf(secname, sizeof(secname), ".bpf.fn.%s", name); + ::snprintf(secname, sizeof(secname), "%s%s", BPF_FN_PREFIX, name); ret = btf_->get_btf_info(secname, &func_info, &func_info_cnt, &finfo_rec_size, &line_info, &line_info_cnt, &linfo_rec_size); From 8323d7483b7fee60c28f7779788d1327240d8319 Mon Sep 17 00:00:00 2001 From: Dave Marchevsky Date: Tue, 12 Oct 2021 16:48:07 -0700 Subject: [PATCH 2/2] bpf_module: Keep track of BPF progs using function instead of section bcc currently identifies each individual BPF prog in an object file by putting the prog in a special ".bpf.fn.$FUNC_NAME" section when preprocessing the AST. After JITting an object file, the location and size of the section are considered to be "the function's insns". In order to support libbpf-style loading, we need to support its sec_def-style SEC() attributes e.g. SEC("tp_btf/softirq_entry"), which allow libbpf to determine the type of BPF prog - and often other information like where to attach - based on the section name. These are not guaranteed to be unique per function, so we can no longer assume that a section contains only one function. This commit gets rid of that assumption. bcc now finds the symbol in the JITed image matching each BPF prog function and uses it to determine size/location. Also, this commit only adds the ".bpf.fn.$FUNC_NAME" section attribute iff there isn't already a custom section attribute set. Signed-off-by: Dave Marchevsky --- src/cc/bcc_debug.cc | 89 ++++---- src/cc/bcc_debug.h | 13 +- src/cc/bpf_module.cc | 228 ++++++++++++-------- src/cc/bpf_module.h | 7 +- src/cc/frontends/clang/b_frontend_action.cc | 38 ++-- src/cc/frontends/clang/b_frontend_action.h | 9 +- src/cc/frontends/clang/loader.cc | 103 +++++---- src/cc/frontends/clang/loader.h | 56 +++-- 8 files changed, 313 insertions(+), 230 deletions(-) diff --git a/src/cc/bcc_debug.cc b/src/cc/bcc_debug.cc index 52b6571ed6c3..10210fc053b3 100644 --- a/src/cc/bcc_debug.cc +++ b/src/cc/bcc_debug.cc @@ -190,68 +190,67 @@ void SourceDebugger::dump() { vector LineCache = buildLineCache(); // Start to disassemble with source code annotation section by section - for (auto section : sections_) - if (!strncmp(fn_prefix_.c_str(), section.first.c_str(), - fn_prefix_.size())) { - MCDisassembler::DecodeStatus S; - MCInst Inst; - uint64_t Size; - uint8_t *FuncStart = get<0>(section.second); - uint64_t FuncSize = get<1>(section.second); + prog_func_info_.for_each_func([&](std::string func_name, FuncInfo &info) { + MCDisassembler::DecodeStatus S; + MCInst Inst; + uint64_t Size; + uint8_t *FuncStart = info.start_; + uint64_t FuncSize = info.size_; #if LLVM_MAJOR_VERSION >= 9 - unsigned SectionID = get<2>(section.second); + auto section = sections_.find(info.section_); + if (section == sections_.end()) { + errs() << "Debug Error: no section entry for section " << info.section_ + << '\n'; + return; + } + unsigned SectionID = get<2>(section->second); #endif - ArrayRef Data(FuncStart, FuncSize); - uint32_t CurrentSrcLine = 0; - string func_name = section.first.substr(fn_prefix_.size()); + ArrayRef Data(FuncStart, FuncSize); + uint32_t CurrentSrcLine = 0; - errs() << "Disassembly of section " << section.first << ":\n" - << func_name << ":\n"; + errs() << "Disassembly of function " << func_name << "\n"; - string src_dbg_str; - llvm::raw_string_ostream os(src_dbg_str); - for (uint64_t Index = 0; Index < FuncSize; Index += Size) { + string src_dbg_str; + llvm::raw_string_ostream os(src_dbg_str); + for (uint64_t Index = 0; Index < FuncSize; Index += Size) { #if LLVM_MAJOR_VERSION >= 10 - S = DisAsm->getInstruction(Inst, Size, Data.slice(Index), Index, - nulls()); + S = DisAsm->getInstruction(Inst, Size, Data.slice(Index), Index, nulls()); #else - S = DisAsm->getInstruction(Inst, Size, Data.slice(Index), Index, - nulls(), nulls()); + S = DisAsm->getInstruction(Inst, Size, Data.slice(Index), Index, nulls(), + nulls()); #endif - if (S != MCDisassembler::Success) { - os << "Debug Error: disassembler failed: " << std::to_string(S) - << '\n'; - break; - } else { - DILineInfo LineInfo; + if (S != MCDisassembler::Success) { + os << "Debug Error: disassembler failed: " << std::to_string(S) << '\n'; + break; + } else { + DILineInfo LineInfo; - LineTable->getFileLineInfoForAddress( + LineTable->getFileLineInfoForAddress( #if LLVM_MAJOR_VERSION >= 9 - {(uint64_t)FuncStart + Index, SectionID}, + {(uint64_t)FuncStart + Index, SectionID}, #else - (uint64_t)FuncStart + Index, + (uint64_t)FuncStart + Index, #endif - CU->getCompilationDir(), - DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, - LineInfo); + CU->getCompilationDir(), + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, LineInfo); - adjustInstSize(Size, Data[Index], Data[Index + 1]); - dumpSrcLine(LineCache, LineInfo.FileName, LineInfo.Line, - CurrentSrcLine, os); - os << format("%4" PRIu64 ":", Index >> 3) << '\t'; - dumpBytes(Data.slice(Index, Size), os); + adjustInstSize(Size, Data[Index], Data[Index + 1]); + dumpSrcLine(LineCache, LineInfo.FileName, LineInfo.Line, CurrentSrcLine, + os); + os << format("%4" PRIu64 ":", Index >> 3) << '\t'; + dumpBytes(Data.slice(Index, Size), os); #if LLVM_MAJOR_VERSION >= 10 - IP->printInst(&Inst, 0, "", *STI, os); + IP->printInst(&Inst, 0, "", *STI, os); #else - IP->printInst(&Inst, os, "", *STI); + IP->printInst(&Inst, os, "", *STI); #endif - os << '\n'; - } + os << '\n'; } - os.flush(); - errs() << src_dbg_str << '\n'; - src_dbg_fmap_[func_name] = src_dbg_str; } + os.flush(); + errs() << src_dbg_str << '\n'; + src_dbg_fmap_[func_name] = src_dbg_str; + }); } } // namespace ebpf diff --git a/src/cc/bcc_debug.h b/src/cc/bcc_debug.h index 1467ca80012f..f9bda11834b7 100644 --- a/src/cc/bcc_debug.h +++ b/src/cc/bcc_debug.h @@ -15,19 +15,18 @@ */ #include "bpf_module.h" +#include "frontends/clang/loader.h" namespace ebpf { class SourceDebugger { public: - SourceDebugger( - llvm::Module *mod, - sec_map_def §ions, - const std::string &fn_prefix, const std::string &mod_src, - std::map &src_dbg_fmap) + SourceDebugger(llvm::Module *mod, sec_map_def §ions, + ProgFuncInfo &prog_func_info, const std::string &mod_src, + std::map &src_dbg_fmap) : mod_(mod), sections_(sections), - fn_prefix_(fn_prefix), + prog_func_info_(prog_func_info), mod_src_(mod_src), src_dbg_fmap_(src_dbg_fmap) {} // Only support dump for llvm 6.x and later. @@ -56,7 +55,7 @@ class SourceDebugger { private: llvm::Module *mod_; const sec_map_def §ions_; - const std::string &fn_prefix_; + ProgFuncInfo &prog_func_info_; const std::string &mod_src_; std::map &src_dbg_fmap_; }; diff --git a/src/cc/bpf_module.cc b/src/cc/bpf_module.cc index 7fb078b7d804..3290ebe25809 100644 --- a/src/cc/bpf_module.cc +++ b/src/cc/bpf_module.cc @@ -13,38 +13,43 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "bpf_module.h" + #include -#include -#include -#include -#include -#include -#include #include -#include - +#include #include #include #include -#include #include +#include #include #include +#include +#include +#include #include #include #include -#include +#include +#include +#include -#include "common.h" +#include +#include +#include +#include +#include + +#include "bcc_btf.h" #include "bcc_debug.h" #include "bcc_elf.h" -#include "frontends/clang/loader.h" -#include "frontends/clang/b_frontend_action.h" -#include "bpf_module.h" +#include "bcc_libbpf_inc.h" +#include "common.h" #include "exported_files.h" +#include "frontends/clang/b_frontend_action.h" +#include "frontends/clang/loader.h" #include "libbpf.h" -#include "bcc_btf.h" -#include "bcc_libbpf_inc.h" namespace ebpf { @@ -58,15 +63,11 @@ using std::unique_ptr; using std::vector; using namespace llvm; -const string BPFModule::FN_PREFIX = BPF_FN_PREFIX; - // Snooping class to remember the sections as the JIT creates them class MyMemoryManager : public SectionMemoryManager { public: - - explicit MyMemoryManager(sec_map_def *sections) - : sections_(sections) { - } + explicit MyMemoryManager(sec_map_def *sections, ProgFuncInfo *prog_func_info) + : sections_(sections), prog_func_info_(prog_func_info) {} virtual ~MyMemoryManager() {} uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, @@ -74,8 +75,6 @@ class MyMemoryManager : public SectionMemoryManager { StringRef SectionName) override { // The programs need to change from fake fd to real map fd, so not allocate ReadOnly regions. uint8_t *Addr = SectionMemoryManager::allocateDataSection(Size, Alignment, SectionID, SectionName, false); - //printf("allocateDataSection: %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, SectionID); return Addr; } @@ -85,12 +84,38 @@ class MyMemoryManager : public SectionMemoryManager { // The lines in .BTF.ext line_info, if corresponding to remapped files, will have empty source line. // The line_info will be fixed in place, so not allocate ReadOnly regions. uint8_t *Addr = SectionMemoryManager::allocateDataSection(Size, Alignment, SectionID, SectionName, false); - //printf("allocateDataSection: %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, SectionID); return Addr; } + + void notifyObjectLoaded(ExecutionEngine *EE, + const object::ObjectFile &o) override { + auto sizes = llvm::object::computeSymbolSizes(o); + for (auto ss : sizes) { + auto maybe_name = ss.first.getName(); + if (!maybe_name) + continue; + + std::string name = maybe_name->str(); + auto info = prog_func_info_->get_func(name); + if (!info) + continue; + + auto section = ss.first.getSection(); + if (!section) + continue; + + auto sec_name = section.get()->getName(); + if (!sec_name) + continue; + + info->section_ = sec_name->str(); + info->size_ = ss.second; + } + } + sec_map_def *sections_; + ProgFuncInfo *prog_func_info_; }; BPFModule::BPFModule(unsigned flags, TableStorage *ts, bool rw_engine_enabled, @@ -120,7 +145,7 @@ BPFModule::BPFModule(unsigned flags, TableStorage *ts, bool rw_engine_enabled, local_ts_ = createSharedTableStorage(); ts_ = &*local_ts_; } - func_src_ = ebpf::make_unique(); + prog_func_info_ = ebpf::make_unique(); } static StatusTuple unimplemented_sscanf(const char *, void *) { @@ -139,14 +164,18 @@ BPFModule::~BPFModule() { } if (!rw_engine_enabled_) { - for (auto section : sections_) - delete[] get<0>(section.second); + prog_func_info_->for_each_func( + [&](std::string name, FuncInfo &info) { + if (!info.start_) + return; + delete[] info.start_; + }); } engine_.reset(); cleanup_rw_engine(); ctx_.reset(); - func_src_.reset(); + prog_func_info_.reset(); if (btf_) delete btf_; @@ -162,7 +191,8 @@ int BPFModule::free_bcc_memory() { int BPFModule::load_cfile(const string &file, bool in_memory, const char *cflags[], int ncflags) { ClangLoader clang_loader(&*ctx_, flags_); if (clang_loader.parse(&mod_, *ts_, file, in_memory, cflags, ncflags, id_, - *func_src_, mod_src_, maps_ns_, fake_fd_map_, perf_events_)) + *prog_func_info_, mod_src_, maps_ns_, fake_fd_map_, + perf_events_)) return -1; return 0; } @@ -175,8 +205,9 @@ int BPFModule::load_cfile(const string &file, bool in_memory, const char *cflags int BPFModule::load_includes(const string &text) { ClangLoader clang_loader(&*ctx_, flags_); const char *cflags[] = {"-DB_WORKAROUND"}; - if (clang_loader.parse(&mod_, *ts_, text, true, cflags, 1, "", *func_src_, - mod_src_, "", fake_fd_map_, perf_events_)) + if (clang_loader.parse(&mod_, *ts_, text, true, cflags, 1, "", + *prog_func_info_, mod_src_, "", fake_fd_map_, + perf_events_)) return -1; return 0; } @@ -426,26 +457,19 @@ int BPFModule::load_maps(sec_map_def §ions) { } // update instructions - for (auto section : sections) { - auto sec_name = section.first; - if (strncmp(BPF_FN_PREFIX, sec_name.c_str(), 8) == 0) { - uint8_t *addr = get<0>(section.second); - uintptr_t size = get<1>(section.second); - struct bpf_insn *insns = (struct bpf_insn *)addr; - int i, num_insns; - - num_insns = size/sizeof(struct bpf_insn); - for (i = 0; i < num_insns; i++) { - if (insns[i].code == (BPF_LD | BPF_DW | BPF_IMM)) { - // change map_fd is it is a ld_pseudo */ - if (insns[i].src_reg == BPF_PSEUDO_MAP_FD && - map_fds.find(insns[i].imm) != map_fds.end()) - insns[i].imm = map_fds[insns[i].imm]; - i++; - } + prog_func_info_->for_each_func([&](std::string name, FuncInfo &info) { + struct bpf_insn *insns = (struct bpf_insn *)info.start_; + uint32_t i, num_insns = info.size_ / sizeof(struct bpf_insn); + for (i = 0; i < num_insns; i++) { + if (insns[i].code == (BPF_LD | BPF_DW | BPF_IMM)) { + // change map_fd is it is a ld_pseudo + if (insns[i].src_reg == BPF_PSEUDO_MAP_FD && + map_fds.find(insns[i].imm) != map_fds.end()) + insns[i].imm = map_fds[insns[i].imm]; + i++; } } - } + }); return 0; } @@ -474,7 +498,8 @@ int BPFModule::finalize() { string err; EngineBuilder builder(move(mod_)); builder.setErrorStr(&err); - builder.setMCJITMemoryManager(ebpf::make_unique(sections_p)); + builder.setMCJITMemoryManager( + ebpf::make_unique(sections_p, &*prog_func_info_)); builder.setMArch("bpf"); #if LLVM_MAJOR_VERSION <= 11 builder.setUseOrcMCJITReplacement(false); @@ -485,20 +510,19 @@ int BPFModule::finalize() { return -1; } -#if LLVM_MAJOR_VERSION >= 9 engine_->setProcessAllSections(true); -#else - if (flags_ & DEBUG_SOURCE) - engine_->setProcessAllSections(true); -#endif if (int rc = run_pass_manager(*mod)) return rc; engine_->finalizeObject(); + prog_func_info_->for_each_func([&](std::string name, FuncInfo &info) { + info.start_ = (uint8_t *)engine_->getFunctionAddress(name); + }); + finalize_prog_func_info(); if (flags_ & DEBUG_SOURCE) { - SourceDebugger src_debugger(mod, *sections_p, FN_PREFIX, mod_src_, + SourceDebugger src_debugger(mod, *sections_p, *prog_func_info_, mod_src_, src_dbg_fmap_); src_debugger.dump(); } @@ -521,51 +545,74 @@ int BPFModule::finalize() { } sections_[fname] = make_tuple(tmp_p, size, get<2>(section.second)); } + + prog_func_info_->for_each_func([](std::string name, FuncInfo &info) { + uint8_t *tmp_p = new uint8_t[info.size_]; + memcpy(tmp_p, info.start_, info.size_); + info.start_ = tmp_p; + }); engine_.reset(); ctx_.reset(); } - // give functions an id - for (auto section : sections_) - if (!strncmp(FN_PREFIX.c_str(), section.first.c_str(), FN_PREFIX.size())) - function_names_.push_back(section.first); - return 0; } -size_t BPFModule::num_functions() const { - return function_names_.size(); +void BPFModule::finalize_prog_func_info() { + // prog_func_info_'s FuncInfo data is gradually populated (first in frontend + // action, then bpf_module). It's possible for a FuncInfo to have been + // created by FrontendAction but no corresponding start location found in + // bpf_module - filter out these functions + // + // The numeric function ids in the new prog_func_info_ are considered + // canonical + std::unique_ptr finalized = ebpf::make_unique(); + prog_func_info_->for_each_func([&](std::string name, FuncInfo &info) { + if(info.start_) { + auto i = finalized->add_func(name); + if (i) { // should always be true + *i = info; + } + } + }); + prog_func_info_.swap(finalized); } +size_t BPFModule::num_functions() const { return prog_func_info_->num_funcs(); } + const char * BPFModule::function_name(size_t id) const { - if (id >= function_names_.size()) - return nullptr; - return function_names_[id].c_str() + FN_PREFIX.size(); + auto name = prog_func_info_->func_name(id); + if (name) + return name->c_str(); + return nullptr; } uint8_t * BPFModule::function_start(size_t id) const { - if (id >= function_names_.size()) - return nullptr; - auto section = sections_.find(function_names_[id]); - if (section == sections_.end()) - return nullptr; - return get<0>(section->second); + auto fn = prog_func_info_->get_func(id); + if (fn) + return fn->start_; + return nullptr; } uint8_t * BPFModule::function_start(const string &name) const { - auto section = sections_.find(FN_PREFIX + name); - if (section == sections_.end()) - return nullptr; - - return get<0>(section->second); + auto fn = prog_func_info_->get_func(name); + if (fn) + return fn->start_; + return nullptr; } const char * BPFModule::function_source(const string &name) const { - return func_src_->src(name); + auto fn = prog_func_info_->get_func(name); + if (fn) + return fn->src_.c_str(); + return ""; } const char * BPFModule::function_source_rewritten(const string &name) const { - return func_src_->src_rewritten(name); + auto fn = prog_func_info_->get_func(name); + if (fn) + return fn->src_rewritten_.c_str(); + return ""; } int BPFModule::annotate_prog_tag(const string &name, int prog_fd, @@ -637,20 +684,17 @@ int BPFModule::annotate_prog_tag(const string &name, int prog_fd, } size_t BPFModule::function_size(size_t id) const { - if (id >= function_names_.size()) - return 0; - auto section = sections_.find(function_names_[id]); - if (section == sections_.end()) - return 0; - return get<1>(section->second); + auto fn = prog_func_info_->get_func(id); + if (fn) + return fn->size_; + return 0; } size_t BPFModule::function_size(const string &name) const { - auto section = sections_.find(FN_PREFIX + name); - if (section == sections_.end()) - return 0; - - return get<1>(section->second); + auto fn = prog_func_info_->get_func(name); + if (fn) + return fn->size_; + return 0; } char * BPFModule::license() const { diff --git a/src/cc/bpf_module.h b/src/cc/bpf_module.h index 87938c3fa4fd..fb368af2c29f 100644 --- a/src/cc/bpf_module.h +++ b/src/cc/bpf_module.h @@ -59,14 +59,13 @@ class TableDesc; class TableStorage; class BLoader; class ClangLoader; -class FuncSource; +class ProgFuncInfo; class BTF; bool bpf_module_rw_engine_enabled(void); class BPFModule { private: - static const std::string FN_PREFIX; int init_engine(); void initialize_rw_engine(); void cleanup_rw_engine(); @@ -74,6 +73,7 @@ class BPFModule { int finalize(); int annotate(); void annotate_light(); + void finalize_prog_func_info(); std::unique_ptr finalize_rw(std::unique_ptr mod); std::string make_reader(llvm::Module *mod, llvm::Type *type); std::string make_writer(llvm::Module *mod, llvm::Type *type); @@ -162,11 +162,10 @@ class BPFModule { std::unique_ptr engine_; std::unique_ptr rw_engine_; std::unique_ptr mod_; - std::unique_ptr func_src_; + std::unique_ptr prog_func_info_; sec_map_def sections_; std::vector tables_; std::map table_names_; - std::vector function_names_; std::map readers_; std::map writers_; std::string id_; diff --git a/src/cc/frontends/clang/b_frontend_action.cc b/src/cc/frontends/clang/b_frontend_action.cc index 7bfc4ed79917..9b2853a9a0bc 100644 --- a/src/cc/frontends/clang/b_frontend_action.cc +++ b/src/cc/frontends/clang/b_frontend_action.cc @@ -811,10 +811,23 @@ bool BTypeVisitor::VisitFunctionDecl(FunctionDecl *D) { if (fe_.is_rewritable_ext_func(D)) { current_fn_ = string(D->getName()); string bd = rewriter_.getRewrittenText(expansionRange(D->getSourceRange())); - fe_.func_src_.set_src(current_fn_, bd); + auto func_info = fe_.prog_func_info_.add_func(current_fn_); + if (!func_info) { + // We should only reach add_func above once per function seen, but the + // BPF_PROG-helper using macros in export/helpers.h (KFUNC_PROBE .. + // LSM_PROBE) break this logic. TODO: adjust export/helpers.h to not + // do so and bail out here, or find a better place to do add_func + func_info = fe_.prog_func_info_.get_func(current_fn_); + //error(GET_BEGINLOC(D), "redefinition of existing function"); + //return false; + } + func_info->src_ = 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->getAttr()) { + 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) { error(GET_BEGINLOC(D->getParamDecl(MAX_CALLING_CONV_REGS + 1)), "too many arguments, bcc only supports in-register parameters"); @@ -1689,13 +1702,12 @@ void BTypeConsumer::HandleTranslationUnit(ASTContext &Context) { } -BFrontendAction::BFrontendAction(llvm::raw_ostream &os, unsigned flags, - TableStorage &ts, const std::string &id, - const std::string &main_path, - FuncSource &func_src, std::string &mod_src, - const std::string &maps_ns, - fake_fd_map_def &fake_fd_map, - std::map> &perf_events) +BFrontendAction::BFrontendAction( + llvm::raw_ostream &os, unsigned flags, TableStorage &ts, + const std::string &id, const std::string &main_path, + ProgFuncInfo &prog_func_info, std::string &mod_src, + const std::string &maps_ns, fake_fd_map_def &fake_fd_map, + std::map> &perf_events) : os_(os), flags_(flags), ts_(ts), @@ -1703,7 +1715,7 @@ BFrontendAction::BFrontendAction(llvm::raw_ostream &os, unsigned flags, maps_ns_(maps_ns), rewriter_(new Rewriter), main_path_(main_path), - func_src_(func_src), + prog_func_info_(prog_func_info), mod_src_(mod_src), next_fake_fd_(-1), fake_fd_map_(fake_fd_map), @@ -1781,7 +1793,9 @@ void BFrontendAction::EndSourceFileAction() { for (auto func : func_range_) { auto f = func.first; string bd = rewriter_->getRewrittenText(func_range_[f]); - func_src_.set_src_rewritten(f, bd); + auto fn = prog_func_info_.get_func(f); + if (fn) + fn->src_rewritten_ = bd; } rewriter_->getEditBuffer(rewriter_->getSourceMgr().getMainFileID()).write(os_); os_.flush(); diff --git a/src/cc/frontends/clang/b_frontend_action.h b/src/cc/frontends/clang/b_frontend_action.h index 530d322a6e56..225645916f40 100644 --- a/src/cc/frontends/clang/b_frontend_action.h +++ b/src/cc/frontends/clang/b_frontend_action.h @@ -40,7 +40,7 @@ class StringRef; namespace ebpf { class BFrontendAction; -class FuncSource; +class ProgFuncInfo; // Traces maps with external pointers as values. class MapVisitor : public clang::RecursiveASTVisitor { @@ -156,9 +156,8 @@ class BFrontendAction : public clang::ASTFrontendAction { // should be written. BFrontendAction(llvm::raw_ostream &os, unsigned flags, TableStorage &ts, const std::string &id, const std::string &main_path, - FuncSource &func_src, std::string &mod_src, - const std::string &maps_ns, - fake_fd_map_def &fake_fd_map, + ProgFuncInfo &prog_func_info, std::string &mod_src, + const std::string &maps_ns, fake_fd_map_def &fake_fd_map, std::map> &perf_events); // Called by clang when the AST has been completed, here the output stream @@ -192,7 +191,7 @@ class BFrontendAction : public clang::ASTFrontendAction { friend class BTypeVisitor; std::map func_range_; const std::string &main_path_; - FuncSource &func_src_; + ProgFuncInfo &prog_func_info_; std::string &mod_src_; std::set m_; int next_fake_fd_; diff --git a/src/cc/frontends/clang/loader.cc b/src/cc/frontends/clang/loader.cc index 4f9914a2cfa9..f97a02eedeb3 100644 --- a/src/cc/frontends/clang/loader.cc +++ b/src/cc/frontends/clang/loader.cc @@ -66,6 +66,44 @@ using std::vector; namespace ebpf { +optional ProgFuncInfo::get_func(std::string name) { + auto it = funcs_.find(name); + if (it != funcs_.end()) + return it->second; + return nullopt; +} + +optional ProgFuncInfo::get_func(size_t id) { + auto it = func_idx_.find(id); + if (it != func_idx_.end()) + return get_func(it->second); + return nullopt; +} + +optional ProgFuncInfo::func_name(size_t id) { + auto it = func_idx_.find(id); + if (it != func_idx_.end()) + return it->second; + return nullopt; +} + +void ProgFuncInfo::for_each_func( + std::function cb) { + for (auto it = funcs_.begin(); it != funcs_.end(); ++it) { + cb(it->first, it->second); + } +} + +optional ProgFuncInfo::add_func(std::string name) { + auto fn = get_func(name); + if (fn) + return nullopt; + size_t current = funcs_.size(); + funcs_.emplace(name, 0); + func_idx_.emplace(current, name); + return get_func(name); +} + ClangLoader::ClangLoader(llvm::LLVMContext *ctx, unsigned flags) : ctx_(ctx), flags_(flags) { @@ -152,13 +190,12 @@ static int CreateFromArgs(clang::CompilerInvocation &invocation, } -int ClangLoader::parse(unique_ptr *mod, TableStorage &ts, - const string &file, bool in_memory, const char *cflags[], - int ncflags, const std::string &id, FuncSource &func_src, - std::string &mod_src, - const std::string &maps_ns, - fake_fd_map_def &fake_fd_map, - std::map> &perf_events) { +int ClangLoader::parse( + unique_ptr *mod, TableStorage &ts, const string &file, + bool in_memory, const char *cflags[], int ncflags, const std::string &id, + ProgFuncInfo &prog_func_info, std::string &mod_src, + const std::string &maps_ns, fake_fd_map_def &fake_fd_map, + std::map> &perf_events) { string main_path = "/virtual/main.c"; unique_ptr main_buf; struct utsname un; @@ -280,7 +317,8 @@ int ClangLoader::parse(unique_ptr *mod, TableStorage &ts, #endif if (do_compile(mod, ts, in_memory, flags_cstr, flags_cstr_rem, main_path, - main_buf, id, func_src, mod_src, true, maps_ns, fake_fd_map, perf_events)) { + main_buf, id, prog_func_info, mod_src, true, maps_ns, + fake_fd_map, perf_events)) { #if BCC_BACKUP_COMPILE != 1 return -1; #else @@ -288,11 +326,12 @@ int ClangLoader::parse(unique_ptr *mod, TableStorage &ts, llvm::errs() << "WARNING: compilation failure, trying with system bpf.h\n"; ts.DeletePrefix(Path({id})); - func_src.clear(); + prog_func_info.clear(); mod_src.clear(); fake_fd_map.clear(); if (do_compile(mod, ts, in_memory, flags_cstr, flags_cstr_rem, main_path, - main_buf, id, func_src, mod_src, false, maps_ns, fake_fd_map, perf_events)) + main_buf, id, prog_func_info, mod_src, false, maps_ns, + fake_fd_map, perf_events)) return -1; #endif } @@ -334,17 +373,14 @@ string get_clang_target(void) { return string(ret); } -int ClangLoader::do_compile(unique_ptr *mod, TableStorage &ts, - bool in_memory, - const vector &flags_cstr_in, - const vector &flags_cstr_rem, - const std::string &main_path, - const unique_ptr &main_buf, - const std::string &id, FuncSource &func_src, - std::string &mod_src, bool use_internal_bpfh, - const std::string &maps_ns, - fake_fd_map_def &fake_fd_map, - std::map> &perf_events) { +int ClangLoader::do_compile( + unique_ptr *mod, TableStorage &ts, bool in_memory, + const vector &flags_cstr_in, + const vector &flags_cstr_rem, const std::string &main_path, + const unique_ptr &main_buf, const std::string &id, + ProgFuncInfo &prog_func_info, std::string &mod_src, bool use_internal_bpfh, + const std::string &maps_ns, fake_fd_map_def &fake_fd_map, + std::map> &perf_events) { using namespace clang; vector flags_cstr = flags_cstr_in; @@ -444,7 +480,7 @@ int ClangLoader::do_compile(unique_ptr *mod, TableStorage &ts, // capture the rewritten c file string out_str1; llvm::raw_string_ostream os1(out_str1); - BFrontendAction bact(os1, flags_, ts, id, main_path, func_src, mod_src, + BFrontendAction bact(os1, flags_, ts, id, main_path, prog_func_info, mod_src, maps_ns, fake_fd_map, perf_events); if (!compiler1.ExecuteAction(bact)) return -1; @@ -474,27 +510,4 @@ int ClangLoader::do_compile(unique_ptr *mod, TableStorage &ts, 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 diff --git a/src/cc/frontends/clang/loader.h b/src/cc/frontends/clang/loader.h index 05db08cbfc9d..aa6f9eea1ac0 100644 --- a/src/cc/frontends/clang/loader.h +++ b/src/cc/frontends/clang/loader.h @@ -16,13 +16,18 @@ #pragma once +#include + +#include #include #include #include -#include - #include "table_storage.h" +#include "vendor/optional.hpp" + +using std::experimental::nullopt; +using std::experimental::optional; namespace llvm { class Module; @@ -32,21 +37,33 @@ 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 funcs_; +struct FuncInfo { + uint8_t *start_ = nullptr; + size_t size_ = 0; + std::string section_; + std::string src_; + std::string src_rewritten_; + // dummy constructor so emplace() works + FuncInfo(int i) {} +}; + +class ProgFuncInfo { public: - FuncSource() {} - void clear() { funcs_.clear(); } - 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); + ProgFuncInfo() {} + void clear() { + funcs_.clear(); + func_idx_.clear(); + } + optional get_func(std::string name); + optional get_func(size_t id); + optional func_name(size_t id); + optional add_func(std::string name); + size_t num_funcs() { return funcs_.size(); } + void for_each_func(std::function cb); + + private: + std::map funcs_; + std::map func_idx_; }; class ClangLoader { @@ -55,7 +72,7 @@ class ClangLoader { ~ClangLoader(); int parse(std::unique_ptr *mod, TableStorage &ts, const std::string &file, bool in_memory, const char *cflags[], - int ncflags, const std::string &id, FuncSource &func_src, + int ncflags, const std::string &id, ProgFuncInfo &prog_func_info, std::string &mod_src, const std::string &maps_ns, fake_fd_map_def &fake_fd_map, std::map> &perf_events); @@ -66,10 +83,9 @@ class ClangLoader { const std::vector &flags_cstr_rem, const std::string &main_path, const std::unique_ptr &main_buf, - const std::string &id, FuncSource &func_src, + const std::string &id, ProgFuncInfo &prog_func_info, std::string &mod_src, bool use_internal_bpfh, - const std::string &maps_ns, - fake_fd_map_def &fake_fd_map, + const std::string &maps_ns, fake_fd_map_def &fake_fd_map, std::map> &perf_events); void add_remapped_includes(clang::CompilerInvocation& invocation); void add_main_input(clang::CompilerInvocation& invocation,