xref: /aosp_15_r20/external/bcc/src/cc/bpf_module.cc (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1 /*
2  * Copyright (c) 2015 PLUMgrid, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "bpf_module.h"
17 
18 #include <fcntl.h>
19 #include <linux/bpf.h>
20 #if LLVM_VERSION_MAJOR <= 16
21 #include <llvm-c/Transforms/IPO.h>
22 #endif
23 #include <llvm/ExecutionEngine/MCJIT.h>
24 #include <llvm/ExecutionEngine/SectionMemoryManager.h>
25 #if LLVM_VERSION_MAJOR >= 16
26 #include <llvm/IRPrinter/IRPrintingPasses.h>
27 #else
28 #include <llvm/IR/IRPrintingPasses.h>
29 #endif
30 #include <llvm/IR/LLVMContext.h>
31 #include <llvm/IR/Module.h>
32 
33 #if LLVM_VERSION_MAJOR >= 15
34 #include <llvm/Pass.h>
35 #include <llvm/IR/PassManager.h>
36 #include <llvm/Passes/PassBuilder.h>
37 #include <llvm/Transforms/IPO/AlwaysInliner.h>
38 #else
39 #include <llvm/IR/LegacyPassManager.h>
40 #endif
41 
42 #include <llvm/IR/Verifier.h>
43 #include <llvm/Object/ObjectFile.h>
44 #include <llvm/Object/ELFObjectFile.h>
45 #include <llvm/Object/SymbolSize.h>
46 #include <llvm/Support/TargetSelect.h>
47 #include <llvm/Transforms/IPO.h>
48 #if LLVM_VERSION_MAJOR <= 16
49 #include <llvm/Transforms/IPO/PassManagerBuilder.h>
50 #endif
51 #include <net/if.h>
52 #include <sys/stat.h>
53 #include <unistd.h>
54 
55 #include <map>
56 #include <set>
57 #include <string>
58 #include <iostream>
59 #include <vector>
60 
61 #include "bcc_btf.h"
62 #include "bcc_debug.h"
63 #include "bcc_elf.h"
64 #include "bcc_libbpf_inc.h"
65 #include "common.h"
66 #include "exported_files.h"
67 #include "frontends/clang/b_frontend_action.h"
68 #include "frontends/clang/loader.h"
69 #include "libbpf.h"
70 
71 namespace ebpf {
72 
73 using std::get;
74 using std::make_tuple;
75 using std::map;
76 using std::move;
77 using std::string;
78 using std::tuple;
79 using std::unique_ptr;
80 using std::vector;
81 using namespace llvm;
82 
83 // Snooping class to remember the sections as the JIT creates them
84 class MyMemoryManager : public SectionMemoryManager {
85  public:
MyMemoryManager(sec_map_def * sections,ProgFuncInfo * prog_func_info)86   explicit MyMemoryManager(sec_map_def *sections, ProgFuncInfo *prog_func_info)
87       : sections_(sections), prog_func_info_(prog_func_info) {}
88 
~MyMemoryManager()89   virtual ~MyMemoryManager() {}
allocateCodeSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName)90   uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
91                                unsigned SectionID,
92                                StringRef SectionName) override {
93     // The programs need to change from fake fd to real map fd, so not allocate ReadOnly regions.
94     uint8_t *Addr = SectionMemoryManager::allocateDataSection(Size, Alignment, SectionID, SectionName, false);
95     (*sections_)[SectionName.str()] = make_tuple(Addr, Size, SectionID);
96     return Addr;
97   }
allocateDataSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName,bool isReadOnly)98   uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
99                                unsigned SectionID, StringRef SectionName,
100                                bool isReadOnly) override {
101     // The lines in .BTF.ext line_info, if corresponding to remapped files, will have empty source line.
102     // The line_info will be fixed in place, so not allocate ReadOnly regions.
103     uint8_t *Addr = SectionMemoryManager::allocateDataSection(Size, Alignment, SectionID, SectionName, false);
104     (*sections_)[SectionName.str()] = make_tuple(Addr, Size, SectionID);
105     return Addr;
106   }
107 
notifyObjectLoaded(ExecutionEngine * EE,const object::ObjectFile & o)108   void notifyObjectLoaded(ExecutionEngine *EE,
109                           const object::ObjectFile &o) override {
110     auto sizes = llvm::object::computeSymbolSizes(o);
111     for (auto ss : sizes) {
112       auto maybe_name = ss.first.getName();
113       if (!maybe_name)
114         continue;
115 
116       std::string name = maybe_name->str();
117       auto info = prog_func_info_->get_func(name);
118       if (!info)
119         continue;
120 
121       auto section = ss.first.getSection();
122       if (!section)
123         continue;
124 
125 #if LLVM_VERSION_MAJOR >= 10
126       auto sec_name = section.get()->getName();
127       if (!sec_name)
128         continue;
129 #else
130       llvm::StringRef sec_name_obj;
131       if (!section.get()->getName(sec_name_obj))
132         continue;
133 
134       auto sec_name = &sec_name_obj;
135 #endif
136       info->section_ = sec_name->str();
137       info->size_ = ss.second;
138     }
139   }
140 
141   sec_map_def *sections_;
142   ProgFuncInfo *prog_func_info_;
143 };
144 
BPFModule(unsigned flags,TableStorage * ts,bool rw_engine_enabled,const std::string & maps_ns,bool allow_rlimit,const char * dev_name)145 BPFModule::BPFModule(unsigned flags, TableStorage *ts, bool rw_engine_enabled,
146                      const std::string &maps_ns, bool allow_rlimit,
147                      const char *dev_name)
148     : flags_(flags),
149       rw_engine_enabled_(rw_engine_enabled && bpf_module_rw_engine_enabled()),
150       used_b_loader_(false),
151       allow_rlimit_(allow_rlimit),
152       ctx_(new LLVMContext),
153       id_(std::to_string((uintptr_t)this)),
154       maps_ns_(maps_ns),
155       ts_(ts), btf_(nullptr) {
156   ifindex_ = dev_name ? if_nametoindex(dev_name) : 0;
157   initialize_rw_engine();
158   LLVMInitializeBPFTarget();
159   LLVMInitializeBPFTargetMC();
160   LLVMInitializeBPFTargetInfo();
161   LLVMInitializeBPFAsmPrinter();
162 #if LLVM_VERSION_MAJOR >= 6
163   LLVMInitializeBPFAsmParser();
164   if (flags & DEBUG_SOURCE)
165     LLVMInitializeBPFDisassembler();
166 #endif
167   LLVMLinkInMCJIT(); /* call empty function to force linking of MCJIT */
168   if (!ts_) {
169     local_ts_ = createSharedTableStorage();
170     ts_ = &*local_ts_;
171   }
172   prog_func_info_ = ebpf::make_unique<ProgFuncInfo>();
173 }
174 
unimplemented_sscanf(const char *,void *)175 static StatusTuple unimplemented_sscanf(const char *, void *) {
176   return StatusTuple(-1, "sscanf unimplemented");
177 }
unimplemented_snprintf(char *,size_t,const void *)178 static StatusTuple unimplemented_snprintf(char *, size_t, const void *) {
179   return StatusTuple(-1, "snprintf unimplemented");
180 }
181 
~BPFModule()182 BPFModule::~BPFModule() {
183   for (auto &v : tables_) {
184     v->key_sscanf = unimplemented_sscanf;
185     v->leaf_sscanf = unimplemented_sscanf;
186     v->key_snprintf = unimplemented_snprintf;
187     v->leaf_snprintf = unimplemented_snprintf;
188   }
189 
190   if (!rw_engine_enabled_) {
191     prog_func_info_->for_each_func(
192         [&](std::string name, FuncInfo &info) {
193       if (!info.start_)
194         return;
195       delete[] info.start_;
196     });
197     for (auto &section : sections_) {
198       delete[] std::get<0>(section.second);
199     }
200   }
201 
202   engine_.reset();
203   cleanup_rw_engine();
204   ctx_.reset();
205   prog_func_info_.reset();
206 
207   if (btf_)
208     delete btf_;
209 
210   ts_->DeletePrefix(Path({id_}));
211 }
212 
free_bcc_memory()213 int BPFModule::free_bcc_memory() {
214   return bcc_free_memory();
215 }
216 
217 // load an entire c file as a module
load_cfile(const string & file,bool in_memory,const char * cflags[],int ncflags)218 int BPFModule::load_cfile(const string &file, bool in_memory, const char *cflags[], int ncflags) {
219   ClangLoader clang_loader(&*ctx_, flags_);
220   if (clang_loader.parse(&mod_, *ts_, file, in_memory, cflags, ncflags, id_,
221                          *prog_func_info_, mod_src_, maps_ns_, fake_fd_map_,
222                          perf_events_))
223     return -1;
224   return 0;
225 }
226 
227 // NOTE: this is a duplicate of the above, but planning to deprecate if we
228 // settle on clang as the frontend
229 
230 // Load in a pre-built list of functions into the initial Module object, then
231 // build an ExecutionEngine.
load_includes(const string & text)232 int BPFModule::load_includes(const string &text) {
233   ClangLoader clang_loader(&*ctx_, flags_);
234   const char *cflags[] = {"-DB_WORKAROUND"};
235   if (clang_loader.parse(&mod_, *ts_, text, true, cflags, 1, "",
236                          *prog_func_info_, mod_src_, "", fake_fd_map_,
237                          perf_events_))
238     return -1;
239   return 0;
240 }
241 
annotate_light()242 void BPFModule::annotate_light() {
243   for (auto fn = mod_->getFunctionList().begin(); fn != mod_->getFunctionList().end(); ++fn)
244     if (!fn->hasFnAttribute(Attribute::NoInline))
245       fn->addFnAttr(Attribute::AlwaysInline);
246 
247   size_t id = 0;
248   Path path({id_});
249   for (auto it = ts_->lower_bound(path), up = ts_->upper_bound(path); it != up; ++it) {
250     TableDesc &table = it->second;
251     tables_.push_back(&it->second);
252     table_names_[table.name] = id++;
253   }
254 }
255 
dump_ir(Module & mod)256 void BPFModule::dump_ir(Module &mod) {
257 #if LLVM_VERSION_MAJOR >= 15
258   // Create the analysis managers
259   LoopAnalysisManager LAM;
260   FunctionAnalysisManager FAM;
261   CGSCCAnalysisManager CGAM;
262   ModuleAnalysisManager MAM;
263 
264   // Create the pass manager
265   PassBuilder PB;
266   PB.registerModuleAnalyses(MAM);
267   PB.registerCGSCCAnalyses(CGAM);
268   PB.registerFunctionAnalyses(FAM);
269   PB.registerLoopAnalyses(LAM);
270   PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
271   auto MPM = PB.buildPerModuleDefaultPipeline(OptimizationLevel::O2);
272 
273   // Add passes and run
274   MPM.addPass(PrintModulePass(errs()));
275   MPM.run(mod, MAM);
276 #else
277   legacy::PassManager PM;
278   PM.add(createPrintModulePass(errs()));
279   PM.run(mod);
280 #endif
281 }
282 
run_pass_manager(Module & mod)283 int BPFModule::run_pass_manager(Module &mod) {
284   if (verifyModule(mod, &errs())) {
285     if (flags_ & DEBUG_LLVM_IR)
286       dump_ir(mod);
287     return -1;
288   }
289 
290 #if LLVM_VERSION_MAJOR >= 15
291   // Create the analysis managers
292   LoopAnalysisManager LAM;
293   FunctionAnalysisManager FAM;
294   CGSCCAnalysisManager CGAM;
295   ModuleAnalysisManager MAM;
296 
297   // Create the pass manager
298   PassBuilder PB;
299   PB.registerModuleAnalyses(MAM);
300   PB.registerCGSCCAnalyses(CGAM);
301   PB.registerFunctionAnalyses(FAM);
302   PB.registerLoopAnalyses(LAM);
303   PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
304   auto MPM = PB.buildPerModuleDefaultPipeline(OptimizationLevel::O3);
305 
306   // Add passes and run
307   MPM.addPass(AlwaysInlinerPass());
308   if (flags_ & DEBUG_LLVM_IR)
309     MPM.addPass(PrintModulePass(outs()));
310   MPM.run(mod, MAM);
311 #else
312   legacy::PassManager PM;
313   PassManagerBuilder PMB;
314   PMB.OptLevel = 3;
315   PM.add(createFunctionInliningPass());
316   /*
317    * llvm < 4.0 needs
318    * PM.add(createAlwaysInlinerPass());
319    * llvm >= 4.0 needs
320    * PM.add(createAlwaysInlinerLegacyPass());
321    * use below 'stable' workaround
322    */
323   LLVMAddAlwaysInlinerPass(reinterpret_cast<LLVMPassManagerRef>(&PM));
324   PMB.populateModulePassManager(PM);
325   if (flags_ & DEBUG_LLVM_IR)
326     PM.add(createPrintModulePass(outs()));
327   PM.run(mod);
328 #endif
329 
330   return 0;
331 }
332 
load_btf(sec_map_def & sections)333 void BPFModule::load_btf(sec_map_def &sections) {
334   uint8_t *btf_sec = nullptr, *btf_ext_sec = nullptr;
335   uintptr_t btf_sec_size = 0, btf_ext_sec_size = 0;
336 
337   for (auto section: sections) {
338     auto sname = section.first;
339     uint8_t *addr = get<0>(section.second);
340     uintptr_t size = get<1>(section.second);
341 
342     if (strcmp(".BTF", sname.c_str()) == 0) {
343       btf_sec = addr;
344       btf_sec_size = size;
345     }
346 
347     if (strcmp(".BTF.ext", sname.c_str()) == 0) {
348       btf_ext_sec = addr;
349       btf_ext_sec_size = size;
350     }
351   }
352 
353   if (btf_sec == nullptr || btf_ext_sec == nullptr)
354     return;
355 
356   // Both .BTF and .BTF.ext ELF sections are present.
357   // The remapped files (the main file and /virtual/include/bcc/helpers.h)
358   // will provide missing source codes in the .BTF.ext line_info table.
359   auto helpers_h = ExportedFiles::headers().find("/virtual/include/bcc/helpers.h");
360   if (helpers_h == ExportedFiles::headers().end()) {
361     fprintf(stderr, "Internal error: missing bcc/helpers.h");
362     return;
363   }
364   std::map<std::string, std::string> remapped_sources;
365   remapped_sources["/virtual/main.c"] = mod_src_;
366   remapped_sources["/virtual/include/bcc/helpers.h"] = helpers_h->second;
367 
368   BTF *btf = new BTF(flags_ & DEBUG_BTF, sections);
369   int ret = btf->load(btf_sec, btf_sec_size, btf_ext_sec, btf_ext_sec_size,
370                        remapped_sources);
371   if (ret) {
372     delete btf;
373     return;
374   }
375   btf_ = btf;
376 }
377 
create_maps(std::map<std::string,std::pair<int,int>> & map_tids,std::map<int,int> & map_fds,std::map<std::string,int> & inner_map_fds,bool for_inner_map)378 int BPFModule::create_maps(std::map<std::string, std::pair<int, int>> &map_tids,
379                            std::map<int, int> &map_fds,
380                            std::map<std::string, int> &inner_map_fds,
381                            bool for_inner_map) {
382   std::set<std::string> inner_maps;
383   if (for_inner_map) {
384     for (auto map : fake_fd_map_) {
385       std::string inner_map_name = get<7>(map.second);
386       if (inner_map_name.size())
387         inner_maps.insert(inner_map_name);
388     }
389   }
390 
391   for (auto map : fake_fd_map_) {
392     int fd, fake_fd, map_type, key_size, value_size, max_entries, map_flags;
393     int pinned_id;
394     const char *map_name;
395     const char *pinned;
396     std::string inner_map_name;
397     int inner_map_fd = 0;
398 
399     fake_fd     = map.first;
400     map_type    = get<0>(map.second);
401     map_name    = get<1>(map.second).c_str();
402     key_size    = get<2>(map.second);
403     value_size  = get<3>(map.second);
404     max_entries = get<4>(map.second);
405     map_flags   = get<5>(map.second);
406     pinned_id   = get<6>(map.second);
407     inner_map_name = get<7>(map.second);
408 
409     if (for_inner_map) {
410       if (inner_maps.find(map_name) == inner_maps.end())
411         continue;
412       if (inner_map_name.size()) {
413         fprintf(stderr, "inner map %s has inner map %s\n",
414                 map_name, inner_map_name.c_str());
415         return -1;
416       }
417     } else {
418       if (inner_map_fds.find(map_name) != inner_map_fds.end())
419         continue;
420       if (inner_map_name.size())
421         inner_map_fd = inner_map_fds[inner_map_name];
422     }
423 
424     if (pinned_id <= 0) {
425       struct bcc_create_map_attr attr = {};
426       attr.map_type = (enum bpf_map_type)map_type;
427       attr.name = map_name;
428       attr.key_size = key_size;
429       attr.value_size = value_size;
430       attr.max_entries = max_entries;
431       attr.map_flags = map_flags;
432       attr.map_ifindex = ifindex_;
433       attr.inner_map_fd = inner_map_fd;
434 
435       if (map_tids.find(map_name) != map_tids.end()) {
436         attr.btf_fd = btf_->get_fd();
437         attr.btf_key_type_id = map_tids[map_name].first;
438         attr.btf_value_type_id = map_tids[map_name].second;
439       }
440 
441       fd = bcc_create_map_xattr(&attr, allow_rlimit_);
442     } else {
443       fd = bpf_map_get_fd_by_id(pinned_id);
444     }
445 
446     if (fd < 0) {
447       fprintf(stderr, "could not open bpf map: %s, error: %s\n",
448               map_name, strerror(errno));
449       return -1;
450     }
451 
452     if (pinned_id == -1) {
453       pinned = get<8>(map.second).c_str();
454       if (bpf_obj_pin(fd, pinned)) {
455         fprintf(stderr, "failed to pin map: %s, error: %s\n",
456                 pinned, strerror(errno));
457         return -1;
458       }
459     }
460 
461     if (for_inner_map)
462       inner_map_fds[map_name] = fd;
463 
464     map_fds[fake_fd] = fd;
465   }
466 
467   return 0;
468 }
469 
load_maps(sec_map_def & sections)470 int BPFModule::load_maps(sec_map_def &sections) {
471   // find .maps.<table_name> sections and retrieve all map key/value type id's
472   std::map<std::string, std::pair<int, int>> map_tids;
473   if (btf_) {
474     for (auto section : sections) {
475       auto sec_name = section.first;
476       if (strncmp(".maps.", sec_name.c_str(), 6) == 0) {
477         std::string map_name = sec_name.substr(6);
478         unsigned key_tid = 0, value_tid = 0;
479         unsigned expected_ksize = 0, expected_vsize = 0;
480 
481         // skip extern maps, which won't be in fake_fd_map_ as they do not
482         // require explicit bpf_create_map.
483         bool is_extern = false;
484         for (auto &t : tables_) {
485           if (t->name == map_name) {
486             is_extern = t->is_extern;
487             break;
488           }
489         }
490         if (is_extern)
491           continue;
492 
493         for (auto map : fake_fd_map_) {
494           std::string name;
495 
496           name = get<1>(map.second);
497           if (map_name == name) {
498             expected_ksize = get<2>(map.second);
499             expected_vsize = get<3>(map.second);
500             break;
501           }
502         }
503 
504         int ret = btf_->get_map_tids(map_name, expected_ksize,
505                                      expected_vsize, &key_tid, &value_tid);
506         if (ret)
507           continue;
508 
509         map_tids[map_name] = std::make_pair(key_tid, value_tid);
510       }
511     }
512   }
513 
514   // create maps
515   std::map<std::string, int> inner_map_fds;
516   std::map<int, int> map_fds;
517   if (create_maps(map_tids, map_fds, inner_map_fds, true) < 0)
518     return -1;
519   if (create_maps(map_tids, map_fds, inner_map_fds, false) < 0)
520     return -1;
521 
522   // update map table fd's
523   for (auto it = ts_->begin(), up = ts_->end(); it != up; ++it) {
524     TableDesc &table = it->second;
525     if (map_fds.find(table.fake_fd) != map_fds.end()) {
526       table.fd = map_fds[table.fake_fd];
527       table.fake_fd = 0;
528     }
529   }
530 
531   // update instructions
532   prog_func_info_->for_each_func([&](std::string name, FuncInfo &info) {
533     struct bpf_insn *insns = (struct bpf_insn *)info.start_;
534     uint32_t i, num_insns = info.size_ / sizeof(struct bpf_insn);
535     for (i = 0; i < num_insns; i++) {
536       if (insns[i].code == (BPF_LD | BPF_DW | BPF_IMM)) {
537         // change map_fd is it is a ld_pseudo
538         if (insns[i].src_reg == BPF_PSEUDO_MAP_FD &&
539             map_fds.find(insns[i].imm) != map_fds.end())
540           insns[i].imm = map_fds[insns[i].imm];
541         i++;
542       }
543     }
544   });
545 
546   return 0;
547 }
548 
finalize()549 int BPFModule::finalize() {
550   Module *mod = &*mod_;
551   sec_map_def tmp_sections,
552       *sections_p;
553 
554   mod->setTargetTriple("bpf-pc-linux");
555 #if LLVM_VERSION_MAJOR >= 11
556 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
557   mod->setDataLayout("e-m:e-p:64:64-i64:64-i128:128-n32:64-S128");
558 #else
559   mod->setDataLayout("E-m:e-p:64:64-i64:64-i128:128-n32:64-S128");
560 #endif
561 #else
562 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
563   mod->setDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128");
564 #else
565   mod->setDataLayout("E-m:e-p:64:64-i64:64-n32:64-S128");
566 #endif
567 #endif
568   sections_p = rw_engine_enabled_ ? &sections_ : &tmp_sections;
569 
570   string err;
571   EngineBuilder builder(move(mod_));
572   builder.setErrorStr(&err);
573   builder.setMCJITMemoryManager(
574       ebpf::make_unique<MyMemoryManager>(sections_p, &*prog_func_info_));
575   builder.setMArch("bpf");
576 #if LLVM_VERSION_MAJOR <= 11
577   builder.setUseOrcMCJITReplacement(false);
578 #endif
579   engine_ = unique_ptr<ExecutionEngine>(builder.create());
580   if (!engine_) {
581     fprintf(stderr, "Could not create ExecutionEngine: %s\n", err.c_str());
582     return -1;
583   }
584 
585   engine_->setProcessAllSections(true);
586 
587   if (int rc = run_pass_manager(*mod))
588     return rc;
589 
590   engine_->finalizeObject();
591   prog_func_info_->for_each_func([&](std::string name, FuncInfo &info) {
592     info.start_ = (uint8_t *)engine_->getFunctionAddress(name);
593   });
594   finalize_prog_func_info();
595 
596   if (flags_ & DEBUG_SOURCE) {
597     SourceDebugger src_debugger(mod, *sections_p, *prog_func_info_, mod_src_,
598                                 src_dbg_fmap_);
599     src_debugger.dump();
600   }
601 
602   load_btf(*sections_p);
603   if (load_maps(*sections_p))
604     return -1;
605 
606   if (!rw_engine_enabled_) {
607     // Setup sections_ correctly and then free llvm internal memory
608     for (auto section : tmp_sections) {
609       auto fname = section.first;
610       uintptr_t size = get<1>(section.second);
611       uint8_t *tmp_p = NULL;
612       // Only copy data for non-map sections
613       if (strncmp("maps/", section.first.c_str(), 5)) {
614         uint8_t *addr = get<0>(section.second);
615         tmp_p = new uint8_t[size];
616         memcpy(tmp_p, addr, size);
617       }
618       sections_[fname] = make_tuple(tmp_p, size, get<2>(section.second));
619     }
620 
621     prog_func_info_->for_each_func([](std::string name, FuncInfo &info) {
622       uint8_t *tmp_p = new uint8_t[info.size_];
623       memcpy(tmp_p, info.start_, info.size_);
624       info.start_ = tmp_p;
625     });
626     engine_.reset();
627     ctx_.reset();
628   }
629 
630   return 0;
631 }
632 
finalize_prog_func_info()633 void BPFModule::finalize_prog_func_info() {
634   // prog_func_info_'s FuncInfo data is gradually populated (first in frontend
635   // action, then bpf_module). It's possible for a FuncInfo to have been
636   // created by FrontendAction but no corresponding start location found in
637   // bpf_module - filter out these functions
638   //
639   // The numeric function ids in the new prog_func_info_ are considered
640   // canonical
641   std::unique_ptr<ProgFuncInfo> finalized = ebpf::make_unique<ProgFuncInfo>();
642   prog_func_info_->for_each_func([&](std::string name, FuncInfo &info) {
643     if(info.start_) {
644       auto i = finalized->add_func(name);
645       if (i) { // should always be true
646         *i = info;
647       }
648     }
649   });
650   prog_func_info_.swap(finalized);
651 }
652 
num_functions() const653 size_t BPFModule::num_functions() const { return prog_func_info_->num_funcs(); }
654 
function_name(size_t id) const655 const char * BPFModule::function_name(size_t id) const {
656   auto name = prog_func_info_->func_name(id);
657   if (name)
658     return name->c_str();
659   return nullptr;
660 }
661 
function_start(size_t id) const662 uint8_t * BPFModule::function_start(size_t id) const {
663   auto fn = prog_func_info_->get_func(id);
664   if (fn)
665     return fn->start_;
666   return nullptr;
667 }
668 
function_start(const string & name) const669 uint8_t * BPFModule::function_start(const string &name) const {
670   auto fn = prog_func_info_->get_func(name);
671   if (fn)
672     return fn->start_;
673   return nullptr;
674 }
675 
function_source(const string & name) const676 const char * BPFModule::function_source(const string &name) const {
677   auto fn = prog_func_info_->get_func(name);
678   if (fn)
679     return fn->src_.c_str();
680   return "";
681 }
682 
function_source_rewritten(const string & name) const683 const char * BPFModule::function_source_rewritten(const string &name) const {
684   auto fn = prog_func_info_->get_func(name);
685   if (fn)
686     return fn->src_rewritten_.c_str();
687   return "";
688 }
689 
annotate_prog_tag(const string & name,int prog_fd,struct bpf_insn * insns,int prog_len)690 int BPFModule::annotate_prog_tag(const string &name, int prog_fd,
691                                  struct bpf_insn *insns, int prog_len) {
692   unsigned long long tag1, tag2;
693   int err;
694 
695   err = bpf_prog_compute_tag(insns, prog_len, &tag1);
696   if (err)
697     return err;
698   err = bpf_prog_get_tag(prog_fd, &tag2);
699   if (err)
700     return err;
701   if (tag1 != tag2) {
702     fprintf(stderr, "prog tag mismatch %llx %llx\n", tag1, tag2);
703     return -1;
704   }
705 
706   err = mkdir(BCC_PROG_TAG_DIR, 0777);
707   if (err && errno != EEXIST) {
708     fprintf(stderr, "cannot create " BCC_PROG_TAG_DIR "\n");
709     return -1;
710   }
711 
712   char buf[128];
713   ::snprintf(buf, sizeof(buf), BCC_PROG_TAG_DIR "/bpf_prog_%llx", tag1);
714   err = mkdir(buf, 0777);
715   if (err && errno != EEXIST) {
716     fprintf(stderr, "cannot create %s\n", buf);
717     return -1;
718   }
719 
720   ::snprintf(buf, sizeof(buf), BCC_PROG_TAG_DIR "/bpf_prog_%llx/%s.c",
721              tag1, name.data());
722   FileDesc fd(open(buf, O_CREAT | O_WRONLY | O_TRUNC, 0644));
723   if (fd < 0) {
724     fprintf(stderr, "cannot create %s\n", buf);
725     return -1;
726   }
727 
728   const char *src = function_source(name);
729   write(fd, src, strlen(src));
730 
731   ::snprintf(buf, sizeof(buf), BCC_PROG_TAG_DIR "/bpf_prog_%llx/%s.rewritten.c",
732              tag1, name.data());
733   fd = open(buf, O_CREAT | O_WRONLY | O_TRUNC, 0644);
734   if (fd < 0) {
735     fprintf(stderr, "cannot create %s\n", buf);
736     return -1;
737   }
738 
739   src = function_source_rewritten(name);
740   write(fd, src, strlen(src));
741 
742   if (!src_dbg_fmap_[name].empty()) {
743     ::snprintf(buf, sizeof(buf), BCC_PROG_TAG_DIR "/bpf_prog_%llx/%s.dis.txt",
744                tag1, name.data());
745     fd = open(buf, O_CREAT | O_WRONLY | O_TRUNC, 0644);
746     if (fd < 0) {
747       fprintf(stderr, "cannot create %s\n", buf);
748       return -1;
749     }
750 
751     const char *src = src_dbg_fmap_[name].c_str();
752     write(fd, src, strlen(src));
753   }
754 
755   return 0;
756 }
757 
function_size(size_t id) const758 size_t BPFModule::function_size(size_t id) const {
759   auto fn = prog_func_info_->get_func(id);
760   if (fn)
761     return fn->size_;
762   return 0;
763 }
764 
function_size(const string & name) const765 size_t BPFModule::function_size(const string &name) const {
766   auto fn = prog_func_info_->get_func(name);
767   if (fn)
768     return fn->size_;
769   return 0;
770 }
771 
license() const772 char * BPFModule::license() const {
773   auto section = sections_.find("license");
774   if (section == sections_.end())
775     return nullptr;
776 
777   return (char *)get<0>(section->second);
778 }
779 
kern_version() const780 unsigned BPFModule::kern_version() const {
781   auto section = sections_.find("version");
782   if (section == sections_.end())
783     return 0;
784 
785   return *(unsigned *)get<0>(section->second);
786 }
787 
num_tables() const788 size_t BPFModule::num_tables() const { return tables_.size(); }
789 
perf_event_fields(const char * event) const790 size_t BPFModule::perf_event_fields(const char *event) const {
791   auto it = perf_events_.find(event);
792   if (it == perf_events_.end())
793     return 0;
794   return it->second.size();
795 }
796 
perf_event_field(const char * event,size_t i) const797 const char * BPFModule::perf_event_field(const char *event, size_t i) const {
798   auto it = perf_events_.find(event);
799   if (it == perf_events_.end() || i >= it->second.size())
800     return nullptr;
801   return it->second[i].c_str();
802 }
803 
table_id(const string & name) const804 size_t BPFModule::table_id(const string &name) const {
805   auto it = table_names_.find(name);
806   if (it == table_names_.end()) return ~0ull;
807   return it->second;
808 }
809 
table_fd(const string & name) const810 int BPFModule::table_fd(const string &name) const {
811   return table_fd(table_id(name));
812 }
813 
table_fd(size_t id) const814 int BPFModule::table_fd(size_t id) const {
815   if (id >= tables_.size())
816     return -1;
817   return tables_[id]->fd;
818 }
819 
table_type(const string & name) const820 int BPFModule::table_type(const string &name) const {
821   return table_type(table_id(name));
822 }
823 
table_type(size_t id) const824 int BPFModule::table_type(size_t id) const {
825   if (id >= tables_.size())
826     return -1;
827   return tables_[id]->type;
828 }
829 
table_max_entries(const string & name) const830 size_t BPFModule::table_max_entries(const string &name) const {
831   return table_max_entries(table_id(name));
832 }
833 
table_max_entries(size_t id) const834 size_t BPFModule::table_max_entries(size_t id) const {
835   if (id >= tables_.size())
836     return 0;
837   return tables_[id]->max_entries;
838 }
839 
table_flags(const string & name) const840 int BPFModule::table_flags(const string &name) const {
841   return table_flags(table_id(name));
842 }
843 
table_flags(size_t id) const844 int BPFModule::table_flags(size_t id) const {
845   if (id >= tables_.size())
846     return -1;
847   return tables_[id]->flags;
848 }
849 
table_name(size_t id) const850 const char * BPFModule::table_name(size_t id) const {
851   if (id >= tables_.size())
852     return nullptr;
853   return tables_[id]->name.c_str();
854 }
855 
table_key_desc(size_t id) const856 const char * BPFModule::table_key_desc(size_t id) const {
857   if (used_b_loader_) return nullptr;
858   if (id >= tables_.size())
859     return nullptr;
860   return tables_[id]->key_desc.c_str();
861 }
862 
table_key_desc(const string & name) const863 const char * BPFModule::table_key_desc(const string &name) const {
864   return table_key_desc(table_id(name));
865 }
866 
table_leaf_desc(size_t id) const867 const char * BPFModule::table_leaf_desc(size_t id) const {
868   if (used_b_loader_) return nullptr;
869   if (id >= tables_.size())
870     return nullptr;
871   return tables_[id]->leaf_desc.c_str();
872 }
873 
table_leaf_desc(const string & name) const874 const char * BPFModule::table_leaf_desc(const string &name) const {
875   return table_leaf_desc(table_id(name));
876 }
table_key_size(size_t id) const877 size_t BPFModule::table_key_size(size_t id) const {
878   if (id >= tables_.size())
879     return 0;
880   return tables_[id]->key_size;
881 }
table_key_size(const string & name) const882 size_t BPFModule::table_key_size(const string &name) const {
883   return table_key_size(table_id(name));
884 }
885 
table_leaf_size(size_t id) const886 size_t BPFModule::table_leaf_size(size_t id) const {
887   if (id >= tables_.size())
888     return 0;
889   return tables_[id]->leaf_size;
890 }
table_leaf_size(const string & name) const891 size_t BPFModule::table_leaf_size(const string &name) const {
892   return table_leaf_size(table_id(name));
893 }
894 
895 struct TableIterator {
TableIteratorebpf::TableIterator896   TableIterator(size_t key_size, size_t leaf_size)
897       : key(new uint8_t[key_size]), leaf(new uint8_t[leaf_size]) {
898   }
899   unique_ptr<uint8_t[]> key;
900   unique_ptr<uint8_t[]> leaf;
901   uint8_t keyb[512];
902 };
903 
table_key_printf(size_t id,char * buf,size_t buflen,const void * key)904 int BPFModule::table_key_printf(size_t id, char *buf, size_t buflen, const void *key) {
905   if (id >= tables_.size())
906     return -1;
907   const TableDesc &desc = *tables_[id];
908   StatusTuple rc = desc.key_snprintf(buf, buflen, key);
909   if (rc.code() < 0) {
910     fprintf(stderr, "%s\n", rc.msg().c_str());
911     return -1;
912   }
913   return 0;
914 }
915 
table_leaf_printf(size_t id,char * buf,size_t buflen,const void * leaf)916 int BPFModule::table_leaf_printf(size_t id, char *buf, size_t buflen, const void *leaf) {
917   if (id >= tables_.size())
918     return -1;
919   const TableDesc &desc = *tables_[id];
920   StatusTuple rc = desc.leaf_snprintf(buf, buflen, leaf);
921   if (rc.code() < 0) {
922     fprintf(stderr, "%s\n", rc.msg().c_str());
923     return -1;
924   }
925   return 0;
926 }
927 
table_key_scanf(size_t id,const char * key_str,void * key)928 int BPFModule::table_key_scanf(size_t id, const char *key_str, void *key) {
929   if (id >= tables_.size())
930     return -1;
931   const TableDesc &desc = *tables_[id];
932   StatusTuple rc = desc.key_sscanf(key_str, key);
933   if (rc.code() < 0) {
934     fprintf(stderr, "%s\n", rc.msg().c_str());
935     return -1;
936   }
937   return 0;
938 }
939 
table_leaf_scanf(size_t id,const char * leaf_str,void * leaf)940 int BPFModule::table_leaf_scanf(size_t id, const char *leaf_str, void *leaf) {
941   if (id >= tables_.size())
942     return -1;
943   const TableDesc &desc = *tables_[id];
944   StatusTuple rc = desc.leaf_sscanf(leaf_str, leaf);
945   if (rc.code() < 0) {
946     fprintf(stderr, "%s\n", rc.msg().c_str());
947     return -1;
948   }
949   return 0;
950 }
951 
952 // load a C file
load_c(const string & filename,const char * cflags[],int ncflags)953 int BPFModule::load_c(const string &filename, const char *cflags[], int ncflags) {
954   if (!sections_.empty()) {
955     fprintf(stderr, "Program already initialized\n");
956     return -1;
957   }
958   if (filename.empty()) {
959     fprintf(stderr, "Invalid filename\n");
960     return -1;
961   }
962   if (int rc = load_cfile(filename, false, cflags, ncflags))
963     return rc;
964   if (rw_engine_enabled_) {
965     if (int rc = annotate())
966       return rc;
967   } else {
968     annotate_light();
969   }
970   if (int rc = finalize())
971     return rc;
972   return 0;
973 }
974 
975 // load a C text string
load_string(const string & text,const char * cflags[],int ncflags)976 int BPFModule::load_string(const string &text, const char *cflags[], int ncflags) {
977   if (!sections_.empty()) {
978     fprintf(stderr, "Program already initialized\n");
979     return -1;
980   }
981   if (int rc = load_cfile(text, true, cflags, ncflags))
982     return rc;
983   if (rw_engine_enabled_) {
984     if (int rc = annotate())
985       return rc;
986   } else {
987     annotate_light();
988   }
989 
990   if (int rc = finalize())
991     return rc;
992   return 0;
993 }
994 
bcc_func_load(int prog_type,const char * name,const struct bpf_insn * insns,int prog_len,const char * license,unsigned kern_version,int log_level,char * log_buf,unsigned log_buf_size,const char * dev_name,unsigned flags,int expected_attach_type)995 int BPFModule::bcc_func_load(int prog_type, const char *name,
996                 const struct bpf_insn *insns, int prog_len,
997                 const char *license, unsigned kern_version,
998                 int log_level, char *log_buf, unsigned log_buf_size,
999                 const char *dev_name, unsigned flags, int expected_attach_type) {
1000   struct bpf_prog_load_opts opts = {};
1001   unsigned func_info_cnt, line_info_cnt, finfo_rec_size, linfo_rec_size;
1002   void *func_info = NULL, *line_info = NULL;
1003   int ret;
1004 
1005   if (expected_attach_type != -1) {
1006     opts.expected_attach_type = (enum bpf_attach_type)expected_attach_type;
1007   }
1008   if (prog_type != BPF_PROG_TYPE_TRACING &&
1009       prog_type != BPF_PROG_TYPE_EXT) {
1010     opts.kern_version = kern_version;
1011   }
1012   opts.prog_flags = flags;
1013   opts.log_level = log_level;
1014   if (dev_name)
1015     opts.prog_ifindex = if_nametoindex(dev_name);
1016 
1017   if (btf_) {
1018     int btf_fd = btf_->get_fd();
1019     char secname[256];
1020 
1021     ::snprintf(secname, sizeof(secname), "%s%s", BPF_FN_PREFIX, name);
1022     ret = btf_->get_btf_info(secname, &func_info, &func_info_cnt,
1023                              &finfo_rec_size, &line_info,
1024                              &line_info_cnt, &linfo_rec_size);
1025     if (!ret) {
1026       opts.prog_btf_fd = btf_fd;
1027       opts.func_info = func_info;
1028       opts.func_info_cnt = func_info_cnt;
1029       opts.func_info_rec_size = finfo_rec_size;
1030       opts.line_info = line_info;
1031       opts.line_info_cnt = line_info_cnt;
1032       opts.line_info_rec_size = linfo_rec_size;
1033     }
1034   }
1035 
1036   ret = bcc_prog_load_xattr((enum bpf_prog_type)prog_type, name, license, insns, &opts, prog_len, log_buf, log_buf_size, allow_rlimit_);
1037   if (btf_) {
1038     free(func_info);
1039     free(line_info);
1040   }
1041 
1042   return ret;
1043 }
1044 
bcc_func_attach(int prog_fd,int attachable_fd,int attach_type,unsigned int flags)1045 int BPFModule::bcc_func_attach(int prog_fd, int attachable_fd,
1046                                int attach_type, unsigned int flags) {
1047   return bpf_prog_attach(prog_fd, attachable_fd,
1048                          (enum bpf_attach_type)attach_type, flags);
1049 }
1050 
bcc_func_detach(int prog_fd,int attachable_fd,int attach_type)1051 int BPFModule::bcc_func_detach(int prog_fd, int attachable_fd,
1052                                int attach_type) {
1053   return bpf_prog_detach2(prog_fd, attachable_fd,
1054                           (enum bpf_attach_type)attach_type);
1055 }
1056 
1057 } // namespace ebpf
1058