• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <cerrno>
17 #include <chrono>
18 #include <csignal>
19 #include <cstdio>
20 #include <cstdlib>
21 #include <cstring>
22 #include <ctime>
23 #include <iomanip>
24 #include <iostream>
25 #include <memory>
26 #include <mutex>
27 
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <linux/bpf.h>
31 #include <linux/perf_event.h>
32 #include <sys/resource.h>
33 
34 #include "bpf.h"
35 #include "elf_file.h"
36 #include "libbpf_logger.h"
37 #include "bpf_controller.h"
38 
39 namespace {
40 std::unique_ptr<LIBBPFLogger> libbpfLogger {nullptr};
41 const std::string THIRD_PARTY_MUSL_ADDR = "/system/lib/ld-musl-aarch64.so.1";
42 constexpr int32_t SYM_32_VALUE_OFFSET = 4;
43 constexpr int32_t SYM_64_VALUE_OFFSET = 8;
44 constexpr int32_t WIDE_SIXTEEN = 16;
45 } // namespace
46 
LIBBPFPrintFunc(enum libbpf_print_level level,const char * format,va_list args)47 int BPFController::LIBBPFPrintFunc(enum libbpf_print_level level, const char *format, va_list args)
48 {
49     if (libbpfLogger) {
50         return libbpfLogger->Printf(level, format, args);
51     }
52     return 0;
53 }
54 
~BPFController()55 BPFController::~BPFController()
56 {
57     Stop();
58     if (rb_) {
59         // release bpf ringbuffer
60         ring_buffer__free(rb_);
61         rb_ = nullptr;
62     }
63     if (ips_) {
64         delete[] ips_;
65         ips_ = nullptr;
66     }
67     if (skel_) {
68         hiebpf_bpf__destroy(skel_);
69         skel_ = nullptr;
70     }
71 
72     for (size_t k = 0; k < receivers_.size(); ++k) {
73         receivers_[k]->Stop();
74     }
75     if (bpfLogReader_) {
76         bpfLogReader_->Stop();
77     }
78 }
79 
MakeUnique(const BPFConfig & config)80 std::unique_ptr<BPFController> BPFController::MakeUnique(const BPFConfig& config)
81 {
82     std::unique_ptr<BPFController> bpfctlr {new(std::nothrow) BPFController {config}};
83     CHECK_NOTNULL(bpfctlr, nullptr, "failed to instantiate BPFController");
84     HHLOGI(true, "BPFController instantiated");
85 
86     CHECK_TRUE(bpfctlr->VerifyConfigurations() == 0, nullptr, "failed to verify config");
87     HHLOGI(true, "BPFConfig verified");
88 
89     CHECK_TRUE(bpfctlr->SetUpBPF() == 0, nullptr, "failed to set up BPF");
90     HHLOGI(true, "BPF setup done");
91 
92     return bpfctlr;
93 }
94 
VerifyDumpEvents(const __u32 nr)95 static inline int VerifyDumpEvents(const __u32 nr)
96 {
97     CHECK_TRUE(nr <= BPFController::DUMP_EVENTS_LIMIT, -1, "dump events exceeds limit");
98     return 0;
99 }
100 
VerifyTraceDuration(const __u32 duration)101 static inline int VerifyTraceDuration(const __u32 duration)
102 {
103     CHECK_TRUE(duration <= BPFController::TRACE_DURATION_LIMIT, -1, "trace duration exceeds limit");
104     return 0;
105 }
106 
VerifyMaxStackDepth(const __u32 depth)107 static inline int VerifyMaxStackDepth(const __u32 depth)
108 {
109     CHECK_TRUE(depth <= MAX_STACK_LIMIT, -1, "max stack depth exceeds limit");
110     return 0;
111 }
112 
VerifySelectEventGroups(const std::set<HiebpfEventGroup> & selectEventGroups)113 int BPFController::VerifySelectEventGroups(const std::set<HiebpfEventGroup> &selectEventGroups)
114 {
115     CHECK_TRUE(!selectEventGroups.empty(), -1, "VerifySelectEventGroups() failed: event group list is empty");
116     selectEventGroups_ = selectEventGroups;
117     return 0;
118 }
119 
VerifyConfigurations()120 int BPFController::VerifyConfigurations()
121 {
122     CHECK_TRUE(VerifySelectEventGroups(config_.selectEventGroups_) == 0, -1, "VerifySelectEventGroups fail");
123     HHLOGI(true, "VerifySelectEventGroups() done");
124     CHECK_TRUE(VerifyDumpEvents(config_.dumpEvents_) == 0, -1,
125                "VerifyDumpEvents() failed: dump events = %u", config_.dumpEvents_);
126     HHLOGI(true, "VerifyDumpEents() done");
127     CHECK_TRUE(VerifyTraceDuration(config_.traceDuration_) == 0, -1,
128                "VerifyTraceDuration() failed: duration = %u", config_.traceDuration_);
129     HHLOGI(true, "VerifyTraceDuration() done");
130     CHECK_TRUE(VerifyMaxStackDepth(config_.maxStackDepth_) == 0, -1,
131                "VerifyMaxStackDepth() failed: max stack depth = %u", config_.maxStackDepth_);
132     HHLOGI(true, "VerifyMaxStackDepth() done");
133     return 0;
134 }
135 
SetUpBPF()136 int BPFController::SetUpBPF()
137 {
138     CHECK_TRUE(ConfigLIBBPFLogger() == 0, -1, "failed to configure LIBBPF logger");
139     HHLOGI(true, "ConfigLIBBPFLogger() done");
140 
141     // set up libbpf deubug level
142     libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
143     // set RLIMIT_MEMLOCK
144     struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
145     setrlimit(RLIMIT_MEMLOCK, &r);
146 
147     skel_ = hiebpf_bpf__open();
148     int err = libbpf_get_error(skel_);
149     CHECK_TRUE(!err, err, "failed to open BPF skeleton: %s", strerror(-err));
150     HHLOGI(true, "BPF skeleton opened");
151     if (config_.unwindStack_) {
152         ips_ = new(std::nothrow) __u64[config_.maxStackDepth_];
153         CHECK_NOTNULL(ips_, -1, "failed to allocate memory for ips");
154     }
155     HHLOGI(true, "allocate ips buffer done");
156     dataFile_ = HiebpfDataFile::MakeShared(config_.cmd_, config_.outputFile_);
157     CHECK_NOTNULL(dataFile_, -1, "failed to make hiebpf data file");
158     CHECK_TRUE(FilterProgByEvents() == 0, -1, "failed to load BPF objects");
159     HHLOGI(true, "make HiebpfDataFile done");
160     skel_->rodata->g_stack_limit = config_.maxStackDepth_;
161     err = hiebpf_bpf__load(skel_);
162     CHECK_TRUE(!err, err, "failed to load BPF skeleton: %s", strerror(-err));
163     CHECK_TRUE(ConfigureBPF() == 0, -1, "failed to configure BPF");
164     HHLOGI(true, "BPF configuration done");
165 
166     return 0;
167 }
168 
FilterProgByEvents()169 int BPFController::FilterProgByEvents()
170 {
171     // check each one hiebpf_bpf.progs in hiebpf.skel.h
172     // hiebpf_bpf.progs is autoload by default
173     FilterFsGroup();
174 
175     if (selectEventGroups_.find(MEM_GROUP_ALL) == selectEventGroups_.end()) {
176         bpf_program__set_autoload(skel_->progs.__do_fault_entry, false);
177         bpf_program__set_autoload(skel_->progs.__do_fault_exit, false);
178 
179         bpf_program__set_autoload(skel_->progs.do_swap_page_entry, false);
180         bpf_program__set_autoload(skel_->progs.do_swap_page_exit, false);
181 
182         bpf_program__set_autoload(skel_->progs.do_wp_page_entry, false);
183         bpf_program__set_autoload(skel_->progs.do_wp_page_exit, false);
184     }
185     if (selectEventGroups_.find(BIO_GROUP_ALL) == selectEventGroups_.end()) {
186         bpf_program__set_autoload(skel_->progs.block_issue, false);
187         bpf_program__set_autoload(skel_->progs.blk_update_request, false);
188     } else {
189         dataFile_->WriteKernelSymbol();
190     }
191     return 0;
192 }
193 
FilterFsGroup()194 void BPFController::FilterFsGroup()
195 {
196     if (selectEventGroups_.find(FS_GROUP_ALL) != selectEventGroups_.end()) {
197         return;
198     }
199 
200     if (selectEventGroups_.find(FS_GROUP_OPEN) == selectEventGroups_.end()) {
201         bpf_program__set_autoload(skel_->progs.do_sys_openat2_entry, false);
202         bpf_program__set_autoload(skel_->progs.do_sys_openat2_exit, false);
203     }
204     if (selectEventGroups_.find(FS_GROUP_READ) == selectEventGroups_.end()) {
205         bpf_program__set_autoload(skel_->progs.do_readv_entry, false);
206         bpf_program__set_autoload(skel_->progs.do_readv_exit, false);
207 
208         bpf_program__set_autoload(skel_->progs.do_preadv_entry, false);
209         bpf_program__set_autoload(skel_->progs.do_preadv_exit, false);
210 
211         bpf_program__set_autoload(skel_->progs.ksys_read_entry, false);
212         bpf_program__set_autoload(skel_->progs.ksys_read_exit, false);
213 
214         bpf_program__set_autoload(skel_->progs.ksys_pread64_entry, false);
215         bpf_program__set_autoload(skel_->progs.ksys_pread64_exit, false);
216     }
217     if (selectEventGroups_.find(FS_GROUP_WRITE) == selectEventGroups_.end()) {
218         bpf_program__set_autoload(skel_->progs.do_writev_entry, false);
219         bpf_program__set_autoload(skel_->progs.do_writev_exit, false);
220 
221         bpf_program__set_autoload(skel_->progs.__arm64_sys_pwritev_entry, false);
222         bpf_program__set_autoload(skel_->progs.__arm64_sys_pwritev_exit, false);
223         bpf_program__set_autoload(skel_->progs.__arm64_sys_pwritev2_entry, false);
224         bpf_program__set_autoload(skel_->progs.__arm64_sys_pwritev2_exit, false);
225         bpf_program__set_autoload(skel_->progs.__arm64_compat_sys_pwritev_entry, false);
226         bpf_program__set_autoload(skel_->progs.__arm64_compat_sys_pwritev_exit, false);
227         bpf_program__set_autoload(skel_->progs.__arm64_compat_sys_pwritev2_entry, false);
228         bpf_program__set_autoload(skel_->progs.__arm64_compat_sys_pwritev2_exit, false);
229 
230         bpf_program__set_autoload(skel_->progs.ksys_write_entry, false);
231         bpf_program__set_autoload(skel_->progs.ksys_write_exit, false);
232 
233         bpf_program__set_autoload(skel_->progs.ksys_pwrite64_entry, false);
234         bpf_program__set_autoload(skel_->progs.ksys_pwrite64_exit, false);
235     }
236     if (selectEventGroups_.find(FS_GROUP_CLOSE) == selectEventGroups_.end()) {
237         bpf_program__set_autoload(skel_->progs.__close_fd_entry, false);
238         bpf_program__set_autoload(skel_->progs.__close_fd_exit, false);
239     }
240 }
241 
InitTracerPid(const int fd,bool excludeTracer)242 static int InitTracerPid(const int fd, bool excludeTracer)
243 {
244     int32_t pid = -1;
245     if (excludeTracer) {
246         /* we write the tracer pid into BPF map to notify BPF progs
247          * to exclude the tracer itself
248         */
249         pid = static_cast<int32_t>(getpid());
250         CHECK_TRUE(pid >= 0, -1, "failed to get current pid");
251     }
252     constexpr __u32 pididx {TRACER_PID_INDEX};
253     int err = bpf_map_update_elem(fd, &pididx, &pid, BPF_ANY);
254     CHECK_TRUE(!err, -1, "failed to update tracer pid %d in config_var_map", pid);
255     return 0;
256 }
257 
InitBPFLogLevel(const int fd,const __u32 level)258 static inline int InitBPFLogLevel(const int fd, const __u32 level)
259 {
260     if (level == BPF_LOG_NONE) {
261         HHLOGD(true, "bpf log level is NONE!");
262         return 0;
263     }
264     constexpr __u32 levelidx {BPF_LOG_LEVEL_INDEX};
265     int err = bpf_map_update_elem(fd, &levelidx, &level, BPF_ANY);
266     CHECK_TRUE(!err, -1, "failed to set bpf log level in config_var_map");
267     return 0;
268 }
269 
InitUnwindFlag(const int fd,bool unwind)270 static inline int InitUnwindFlag(const int fd, bool unwind)
271 {
272     constexpr __u32 uflagidx {UNWIND_FLAG_INDEX};
273     __u32 uflag {0};
274     if (unwind) {
275         uflag = 1;
276     }
277     int err = bpf_map_update_elem(fd, &uflagidx, &uflag, BPF_ANY);
278     CHECK_TRUE(!err, -1, "failed to set unwind stack flag in config_var_map");
279     return 0;
280 }
281 
InitBPFVariables() const282 int BPFController::InitBPFVariables() const
283 {
284     int fd = bpf_map__fd(skel_->maps.config_var_map);
285     CHECK_TRUE(fd >= 0, -1, "failed to get fd of config_var_map");
286     HHLOGI(true, "InitBPFVariables() done");
287     CHECK_TRUE(InitTracerPid(fd, config_.excludeTracer_) == 0, -1,
288                "failed to init tracer pid in config_var_map");
289     HHLOGI(true, "InitTracerPid() done");
290     CHECK_TRUE(InitBPFLogLevel(fd, config_.BPFLogLevel_) == 0, -1,
291                "failed to init BPF log level in config_var_map");
292     HHLOGI(true, "InitBPFLogLevel() done");
293     CHECK_TRUE(InitUnwindFlag(fd, config_.unwindStack_) == 0, -1,
294                "failed to init unwind stack flag in config_var_map");
295     HHLOGI(true, "InitUnwindFlag() done");
296     return 0;
297 }
298 
FillTargetPidMap() const299 int BPFController::FillTargetPidMap() const
300 {
301     int fd = bpf_map__fd(skel_->maps.target_pid_map);
302     CHECK_TRUE(fd >= 0, -1, "failed to get fd of target_pid_map");
303     int index {0};
304     uint32_t val {1}; // target_pid_Map[0] = 1 means tracing all processes
305     int err {0};
306     int numPids {config_.targetPids_.size()};
307     HHLOGD(true, "target pid num = %d", numPids);
308     if (numPids == 0) {
309         // no target pid specified, trace all processes
310         err = bpf_map_update_elem(fd, &index, &val, BPF_ANY);
311         CHECK_TRUE(!err, -1, "failed to set target pid = %u", val);
312         return 0;
313     }
314     if (numPids > MAX_TARGET_PIDS) {
315         HHLOGW(true, "BPFController WARN: number of target pids exceeds the maximum limit");
316         numPids = MAX_TARGET_PIDS;
317     }
318     for (index = 1; index <= numPids; ++index) {
319         val = static_cast<uint32_t>(config_.targetPids_[index - 1]);
320         HHLOGD(true, "target pid = %u", val);
321         std::cout << "target pid = " << val << std::endl;
322         err = bpf_map_update_elem(fd, &index, &val, BPF_ANY);
323         CHECK_TRUE(!err, -1, "failed to set target pid = %d", val);
324     }
325     return 0;
326 }
327 
ConfigBPFLogger()328 inline int BPFController::ConfigBPFLogger()
329 {
330     if (config_.BPFLogLevel_ == BPF_LOG_NONE) {
331         HHLOGD(true, "bpf log level is NONE!");
332         return 0;
333     }
334 #if defined(BPF_LOGGER_DEBUG) || defined(BPF_LOGGER_INFO) || defined(BPF_LOGGER_WARN) ||    \
335     defined(BPF_LOGGER_ERROR) || defined(BPF_LOGGER_FATAL)
336     bpfLogReader_ = BPFLogReader::MakeUnique(config_.BPFLogFile_);
337     CHECK_NOTNULL(bpfLogReader_, -1, "failed to initialize BPFLogReader");
338 #endif
339     return 0;
340 }
341 
ConfigLIBBPFLogger() const342 inline int BPFController::ConfigLIBBPFLogger() const
343 {
344     // set up libbpf print callback
345     HHLOGI(true, "libbpf logger: file = %s, level = %d", config_.LIBBPFLogFile_.c_str(), config_.LIBBPFLogLevel_);
346     libbpf_set_print(BPFController::LIBBPFPrintFunc);
347     if (config_.LIBBPFLogLevel_ == LIBBPF_NONE) {
348         HHLOGD(true, "libbpf log level is NONE!");
349         return 0;
350     }
351     libbpfLogger = LIBBPFLogger::MakeUnique(config_.LIBBPFLogFile_, config_.LIBBPFLogLevel_);
352     CHECK_NOTNULL(libbpfLogger, -1, "libbpfLogger is nullptr");
353     return 0;
354 }
355 
ConfigReceivers()356 int BPFController::ConfigReceivers()
357 {
358     if (config_.dumpEvents_ == 0) {
359         rb_ = ring_buffer__new(
360             bpf_map__fd(skel_->maps.bpf_ringbuf_map),
361             BPFController::HandleEvent,
362             this, nullptr);
363         int err = libbpf_get_error(rb_);
364         CHECK_TRUE(!err, err, "failed to make BPF ring buffer: %s", strerror(-err));
365         if (config_.pipelines_ == 0) {
366             config_.pipelines_ = MIN_PIPELINES_LIMIT;
367         }
368         for (__u32 cnt = config_.pipelines_; cnt != 0; --cnt) {
369             receivers_.push_back(BPFEventReceiver::MakeShared(dataFile_));
370         }
371         CHECK_TRUE(receivers_.size() == config_.pipelines_, -1, "failed to make BPF event receivers");
372         last_ = 0;
373     } else {
374         rb_ = ring_buffer__new(
375             bpf_map__fd(skel_->maps.bpf_ringbuf_map),
376             BPFController::DumpEvent,
377             this, nullptr);
378         int err = libbpf_get_error(rb_);
379         CHECK_TRUE(!err, err, "failed to make BPF ring buffer: %s", strerror(-err));
380     }
381     return 0;
382 }
383 
GetSymOffset(const std::string & path,const std::string & symbol)384 uint64_t BPFController::GetSymOffset(const std::string &path, const std::string &symbol)
385 {
386     CHECK_TRUE(access(path.c_str(), F_OK) == 0, 0, "the file does not exist");
387     using namespace OHOS::Developtools::Hiebpf;
388     std::unique_ptr<ElfFile> elfFile = ElfFile::MakeUnique(path);
389     CHECK_NOTNULL(elfFile, 0, "ELF file open failed");
390     const std::string dynsym {".dynsym"};
391     CHECK_TRUE(elfFile->shdrs_.find(dynsym) != elfFile->shdrs_.end(), 0, "section dynsym failed to obtain data");
392     const auto &sym = elfFile->shdrs_[dynsym];
393     const uint8_t *symData = elfFile->GetSectionData(sym->secIndex_);
394     CHECK_NOTNULL(symData, 0, "symData is NULL!");
395 
396     const std::string dynstr {".dynstr"};
397     CHECK_TRUE(elfFile->shdrs_.find(dynstr) != elfFile->shdrs_.end(), 0, "section dynstr failed to obtain data");
398     const auto &str = elfFile->shdrs_[dynstr];
399     const uint8_t *strData = elfFile->GetSectionData(str->secIndex_);
400     CHECK_NOTNULL(strData, 0, "strData is NULL!");
401 
402     uint32_t st_name = 0;
403     uint64_t stepLength = 0;
404     uint64_t vaddr = 0;
405     while (stepLength < sym->secSize_) {
406         int ret = memcpy_s(&st_name, sizeof(uint32_t), symData + stepLength, sizeof(uint32_t));
407         CHECK_TRUE(ret == EOK, 0, "failed to memcpy symData");
408         auto name = const_cast<uint8_t*>(strData + st_name);
409         if (name != nullptr && std::string(reinterpret_cast<char*>(name)).compare(symbol) == 0) {
410             int32_t valueOffset = sym->secEntrySize_ == sizeof(Elf64_Sym) ? SYM_64_VALUE_OFFSET : SYM_32_VALUE_OFFSET;
411             int32_t valueSize = valueOffset == SYM_64_VALUE_OFFSET ? sizeof(uint64_t) : sizeof(uint32_t);
412             ret = memcpy_s(&vaddr, sizeof(uint64_t), symData + stepLength + valueOffset, valueSize);
413             CHECK_TRUE(ret == EOK, 0, "failed to memcpy symData");
414             break;
415         }
416         stepLength += sym->secEntrySize_;
417     }
418     CHECK_TRUE(vaddr != 0, 0, "get vaddr failed");
419 
420     const std::string text {".text"};
421     CHECK_TRUE(elfFile->shdrs_.find(text) != elfFile->shdrs_.end(), 0, "section text failed to obtain data");
422     const auto &textPtr = elfFile->shdrs_[text];
423     return vaddr - textPtr->secVaddr_ + textPtr->fileOffset_;
424 }
425 
ConfigDlopenBPFProg()426 int32_t BPFController::ConfigDlopenBPFProg()
427 {
428     uint64_t symOffset = GetSymOffset(THIRD_PARTY_MUSL_ADDR, "dlopen");
429     CHECK_TRUE(symOffset != 0, -1, "get symOffset failed");
430     skel_->links.uretprobe_dlopen = bpf_program__attach_uprobe(skel_->progs.uretprobe_dlopen,
431                                                                true,
432                                                                -1,
433                                                                THIRD_PARTY_MUSL_ADDR.c_str(),
434                                                                symOffset);
435     CHECK_TRUE(skel_->links.uretprobe_dlopen, -1, "failed to attach uretprobe_dlopen");
436     return 0;
437 }
438 
ConfigureBPF()439 int BPFController::ConfigureBPF()
440 {
441     CHECK_TRUE(InitBPFVariables() == 0, -1, "failed to fill config_var_map");
442     HHLOGI(true, "InitBPFVariables() done");
443     CHECK_TRUE(FillTargetPidMap() == 0, -1, "failed to fill target_pid_map");
444     HHLOGI(true, "FillTargetPidMap() done");
445     CHECK_TRUE(ConfigBPFLogger() == 0, -1, "failed to configure BPF logger");
446     HHLOGI(true, "ConfigBPFLogger() done");
447     CHECK_TRUE(ConfigReceivers() == 0, -1, "failed to configure BPF ringbuffer");
448     HHLOGI(true, "ConfigReceivers() done");
449     CHECK_TRUE(ConfigDlopenBPFProg() == 0, -1, "failed to configure user BPF prog");
450     return 0;
451 }
452 
Start()453 int BPFController::Start()
454 {
455 #if defined(BPF_LOGGER_DEBUG) || defined(BPF_LOGGER_INFO) || defined(BPF_LOGGER_WARN) ||    \
456     defined(BPF_LOGGER_ERROR) || defined(BPF_LOGGER_FATAL)
457     CHECK_TRUE(StartBPFLogReader() == 0, -1, "failed to start BPF log reader");
458 #endif
459     HHLOGI(true, "BPF log reader started");
460     CHECK_TRUE(StartReceivers() == 0, -1, "failed to start receivers");
461     HHLOGI(true, "receivers started");
462     // activate events
463     int err = hiebpf_bpf__attach(skel_);
464     CHECK_TRUE(!err, -1, "failed to attach bpf object: %s", strerror(-err));
465     HHLOGI(true, "BPF events activated");
466 
467     const auto endTime = std::chrono::steady_clock::now() + std::chrono::seconds(config_.traceDuration_);
468     while (!loopStop_) {
469         if (BPFEventLoopOnce() != 0) {
470             printf("libbpf error occured, hiebpf exit\n");
471             err = -1;
472             break;
473         }
474         if (std::chrono::steady_clock::now() >= endTime) {
475             printf("timeout(%us), hiebpf exit\n", config_.traceDuration_);
476             break;
477         }
478     }
479     // receivers_ must stop after BPFEventLoopOnce();
480     for (size_t k = 0; k < receivers_.size(); ++k) {
481         receivers_[k]->Stop();
482     }
483     if (bpfLogReader_) {
484         bpfLogReader_->Stop();
485     }
486 
487     HHLOGI(true, "hiebpf stopped");
488 
489     return err;
490 }
491 
Stop()492 void BPFController::Stop()
493 {
494     loopStop_ = true;
495 }
496 
HandleEvent(void * ctx,void * data,size_t dataSize)497 int BPFController::HandleEvent(void *ctx, void *data, size_t dataSize)
498 {
499     // get the next running receiver
500     BPFController *bpfctlr = static_cast<BPFController *>(ctx);
501     auto wrecv = bpfctlr->NextActiveReceiver();
502     auto receiver = wrecv.lock();
503     if (receiver == nullptr) {
504         HHLOGF(true, "all receivers have stopped, will stop BPF event loop");
505         bpfctlr->Stop();
506         return -1;
507     }
508 
509     // move data and notify receiver
510     int ret = receiver->Put(data, dataSize);
511     HHLOGE((ret < 0), "event lost: failed to move data to receiver"); // try other receivers ?
512     HHLOGF(
513         (0 <= ret and ret < static_cast<int>(dataSize)),
514         "incomplete data movement: this should never happen");
515     return ret;
516 }
517 
DumpOpenat2Args(const struct fstrace_cmplt_event_t & cmpltEvent)518 static int DumpOpenat2Args(const struct fstrace_cmplt_event_t &cmpltEvent)
519 {
520     std::cout << "\nArgs:";
521     std::cout << "\n    dfd = " << cmpltEvent.start_event.openat2_args.dfd;
522     std::cout << "\n    filename = " << cmpltEvent.start_event.openat2_args.filename;
523     std::cout << "\n    how = " << cmpltEvent.start_event.openat2_args.how;
524     return 0;
525 }
526 
DumpReadvArgs(const struct fstrace_cmplt_event_t & cmpltEvent)527 static int DumpReadvArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
528 {
529     std::cout << "\nArgs:";
530     std::cout << "\n    fd = " << cmpltEvent.start_event.readv_args.fd;
531     std::cout << "\n    vec = " << cmpltEvent.start_event.readv_args.vec;
532     std::cout << "\n    vlen = " << cmpltEvent.start_event.readv_args.vlen;
533     std::cout << "\n    flags = " << cmpltEvent.start_event.readv_args.flags;
534     return 0;
535 }
536 
DumpPreadvArgs(const struct fstrace_cmplt_event_t & cmpltEvent)537 static int DumpPreadvArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
538 {
539     std::cout << "\nArgs:";
540     std::cout << "\n    fd = " << cmpltEvent.start_event.preadv_args.fd;
541     std::cout << "\n    vec = " << cmpltEvent.start_event.preadv_args.vec;
542     std::cout << "\n    vlen = " << cmpltEvent.start_event.preadv_args.vlen;
543     std::cout << "\n    pos = " << cmpltEvent.start_event.preadv_args.pos;
544     std::cout << "\n    flags = " << cmpltEvent.start_event.preadv_args.flags;
545     return 0;
546 }
547 
DumpReadArgs(const struct fstrace_cmplt_event_t & cmpltEvent)548 static int DumpReadArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
549 {
550     std::cout << "\nArgs:";
551     std::cout << "\n    fd = " << cmpltEvent.start_event.read_args.fd;
552     std::cout << "\n    buf = " << cmpltEvent.start_event.read_args.buf;
553     std::cout << "\n    count = " << cmpltEvent.start_event.read_args.count;
554     return 0;
555 }
556 
DumpPread64Args(const struct fstrace_cmplt_event_t & cmpltEvent)557 static int DumpPread64Args(const struct fstrace_cmplt_event_t &cmpltEvent)
558 {
559     std::cout << "\nArgs:";
560     std::cout << "\n    fd = " << cmpltEvent.start_event.pread64_args.fd;
561     std::cout << "\n    buf = " << cmpltEvent.start_event.pread64_args.buf;
562     std::cout << "\n    count = " << cmpltEvent.start_event.pread64_args.count;
563     std::cout << "\n    pos = " << cmpltEvent.start_event.pread64_args.pos;
564     return 0;
565 }
566 
DumpWritevArgs(const struct fstrace_cmplt_event_t & cmpltEvent)567 static int DumpWritevArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
568 {
569     std::cout << "\nArgs:";
570     std::cout << "\n    fd = " << cmpltEvent.start_event.writev_args.fd;
571     std::cout << "\n    vec = " << cmpltEvent.start_event.writev_args.vec;
572     std::cout << "\n    vlen = " << cmpltEvent.start_event.writev_args.vlen;
573     std::cout << "\n    flags = " << cmpltEvent.start_event.writev_args.flags;
574     return 0;
575 }
576 
DumpPwritevArgs(const struct fstrace_cmplt_event_t & cmpltEvent)577 static int DumpPwritevArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
578 {
579     std::cout << "\nArgs:";
580     std::cout << "\n    fd = " << cmpltEvent.start_event.pwritev_args.fd;
581     std::cout << "\n    vec = " << cmpltEvent.start_event.pwritev_args.vec;
582     std::cout << "\n    vlen = " << cmpltEvent.start_event.pwritev_args.vlen;
583     std::cout << "\n    pos = " << cmpltEvent.start_event.pwritev_args.pos;
584     std::cout << "\n    flags = " << cmpltEvent.start_event.pwritev_args.flags;
585     return 0;
586 }
587 
DumpWriteArgs(const struct fstrace_cmplt_event_t & cmpltEvent)588 static int DumpWriteArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
589 {
590     std::cout << "\nArgs:";
591     std::cout << "\n    fd = " << cmpltEvent.start_event.write_args.fd;
592     std::cout << "\n    buf = " << cmpltEvent.start_event.write_args.buf;
593     std::cout << "\n    count = " << cmpltEvent.start_event.write_args.count;
594     return 0;
595 }
596 
DumpPwrite64Args(const struct fstrace_cmplt_event_t & cmpltEvent)597 static int DumpPwrite64Args(const struct fstrace_cmplt_event_t &cmpltEvent)
598 {
599     std::cout << "\nArgs:";
600     std::cout << "\n    fd = " << cmpltEvent.start_event.pwrite64_args.fd;
601     std::cout << "\n    buf = " << cmpltEvent.start_event.pwrite64_args.buf;
602     std::cout << "\n    count = " << cmpltEvent.start_event.pwrite64_args.count;
603     std::cout << "\n    pos = " << cmpltEvent.start_event.pwrite64_args.pos;
604     return 0;
605 }
606 
DumpCloseArgs(const struct fstrace_cmplt_event_t & cmpltEvent)607 static int DumpCloseArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
608 {
609     std::cout << "\nArgs:";
610     std::cout << "\n    files = " << cmpltEvent.start_event.close_args.files;
611     std::cout << "\n    fd = " << cmpltEvent.start_event.close_args.fd;
612     return 0;
613 }
614 
DumpTypeAndArgs(const struct fstrace_cmplt_event_t & cmpltEvent)615 static int DumpTypeAndArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
616 {
617     std::cout << "\nevent type:     ";
618     switch (cmpltEvent.start_event.type) {
619         case SYS_OPENAT2: std::cout << "openat2"; return DumpOpenat2Args(cmpltEvent);
620 
621         case SYS_READV: std::cout << "readv"; return DumpReadvArgs(cmpltEvent);
622         case SYS_PREADV: std::cout << "preadv"; return DumpPreadvArgs(cmpltEvent);
623         case SYS_READ: std::cout << "read"; return DumpReadArgs(cmpltEvent);
624         case SYS_PREAD64: std::cout << "pread64"; return DumpPread64Args(cmpltEvent);
625 
626         case SYS_WRITEV: std::cout << "writev"; return DumpWritevArgs(cmpltEvent);
627         case SYS_PWRITEV: std::cout << "pwritev"; return DumpPwritevArgs(cmpltEvent);
628         case SYS_WRITE: std::cout << "write"; return DumpWriteArgs(cmpltEvent);
629         case SYS_PWRITE64: std::cout << "pwrite64"; return DumpPwrite64Args(cmpltEvent);
630 
631         case SYS_CLOSE: std::cout << "close"; return DumpCloseArgs(cmpltEvent);
632     }
633     HHLOGE(true, "unreognized fstrace event type = %d", cmpltEvent.start_event.type);
634     return -1;
635 }
636 
DumpFSTraceEvent(BPFController * bpfctlr,void * data,size_t dataSize)637 int BPFController::DumpFSTraceEvent(BPFController *bpfctlr, void *data, size_t dataSize)
638 {
639     if (dataSize != sizeof(fstrace_cmplt_event_t)) {
640         std::cout << "DumpFSTraceEvent ERROR: size dismatch:"
641                   << " data size = " << dataSize
642                   << " fstrace event size = " << sizeof(fstrace_cmplt_event_t)
643                   << std::endl;
644         return -1;
645     }
646     struct fstrace_cmplt_event_t cmpltEvent {};
647     if (memcpy_s(&cmpltEvent, sizeof(fstrace_cmplt_event_t), data, dataSize) != EOK) {
648         std::cout << "failed to copy data to fstrace_cmplt_event_t" << std::endl;
649         return -1;
650     }
651     std::cout << "\nFSTrace Event:"
652               << "\ndata size:      " << dataSize;
653     DumpTypeAndArgs(cmpltEvent);
654     std::cout << "\nretval:         " << cmpltEvent.retval
655               << "\nstart time:     " << cmpltEvent.start_event.stime
656               << "\nexit time:      " << cmpltEvent.ctime
657               << "\npid:            " << cmpltEvent.pid
658               << "\ntgid:           " << cmpltEvent.tgid
659               << "\ncomm:           " << cmpltEvent.comm
660               << "\nips:            " << cmpltEvent.nips
661               << "\nips:"
662               << std::setw(WIDE_SIXTEEN) << std::hex;
663     for (uint32_t i = 0; i < cmpltEvent.nips; ++i) {
664         std::cout << "\n    " << cmpltEvent.ips[i];
665     }
666     std::cout << std::dec << std::endl;
667     return 0;
668 }
669 
DumpPFTraceEvent(BPFController * bpfctlr,void * data,size_t dataSize)670 int BPFController::DumpPFTraceEvent(BPFController *bpfctlr, void *data, size_t dataSize)
671 {
672     if (dataSize != sizeof(pftrace_cmplt_event_t)) {
673         std::cout << "DumpPFTraceEvent ERROR: size dismatch:"
674                   << " data size = " << dataSize
675                   << " pftrace event size = " << sizeof(pftrace_cmplt_event_t)
676                   << std::endl;
677         return -1;
678     }
679     struct pftrace_cmplt_event_t cmpltEvent {};
680     if (memcpy_s(&cmpltEvent, sizeof(pftrace_cmplt_event_t), data, dataSize) != EOK) {
681         std::cout << "failed to copy data to pftrace_cmplt_event_t" << std::endl;
682         return -1;
683     }
684     std::cout << "PFTrace Event:"
685               << "\ndata size:      " << dataSize
686               << "\nevent type:     ";
687     switch (cmpltEvent.start_event.type) {
688         case PF_COPY_ON_WRITE:  std::cout << "Copy On  Write"; break;
689         case PF_FAKE_ZERO_PAGE: std::cout << "Zero FAKE Page"; break;
690         case PF_FILE_BACKED_IN: std::cout << "File Backed In"; break;
691         case PF_PAGE_CACHE_HIT: std::cout << "Page Cache Hit"; break;
692         case PF_SWAP_FROM_DISK: std::cout << "Swap From Disk"; break;
693         case PF_SWAP_FROM_ZRAM: std::cout << "Swap From Zram"; break;
694         case PF_ZERO_FILL_PAGE: std::cout << "Zero Fill Page"; break;
695         default: std::cout << cmpltEvent.start_event.type;
696     }
697     std::cout << "\naddress:        " << cmpltEvent.start_event.addr
698               << "\nsize:           " << cmpltEvent.size
699               << "\nstart time:     " << cmpltEvent.start_event.stime
700               << "\nexit time:      " << cmpltEvent.ctime
701               << "\npid:            " << cmpltEvent.pid
702               << "\ntgid:           " << cmpltEvent.tgid
703               << "\ncomm:           " << cmpltEvent.comm
704               << "\nips:            " << cmpltEvent.nips
705               << std::setw(WIDE_SIXTEEN) << std::hex;
706     for (uint32_t i = 0; i < cmpltEvent.nips; ++i) {
707         std::cout << "\n    " << cmpltEvent.ips[i];
708     }
709     std::cout << std::dec << std::endl;
710     return 0;
711 }
712 
DumpBIOTraceEvent(BPFController * bpfctlr,void * data,size_t dataSize)713 int BPFController::DumpBIOTraceEvent(BPFController *bpfctlr, void *data, size_t dataSize)
714 {
715     if (dataSize != sizeof(biotrace_cmplt_event_t)) {
716         std::cout << "DumpBIOTraceEvent ERROR: size dismatch:"
717                   << " data size = " << dataSize
718                   << " biotrace event size = " << sizeof(biotrace_cmplt_event_t)
719                   << std::endl;
720         return -1;
721     }
722     struct biotrace_cmplt_event_t cmpltEvent {};
723     if (memcpy_s(&cmpltEvent, sizeof(biotrace_cmplt_event_t), data, dataSize) != EOK) {
724         std::cout << "failed to copy data to biotrace_cmplt_event_t" << std::endl;
725         return -1;
726     }
727     std::cout << "BIOTrace Event:"
728               << "\ndata size:      " << dataSize
729               << "\nevent type:     ";
730     switch (cmpltEvent.start_event.type) {
731         case BIO_DATA_READ: std::cout << "DATA_READ"; break;
732         case BIO_DATA_WRITE: std::cout << "DATA_WRITE"; break;
733         case BIO_METADATA_READ: std::cout << "METADATA_READ"; break;
734         case BIO_METADATA_WRITE: std::cout << "METADATA_WRITE"; break;
735         case BIO_PAGE_IN: std::cout << "PAGE_IN"; break;
736         case BIO_PAGE_OUT: std::cout << "PAGE_OUT"; break;
737         default: std::cout << cmpltEvent.start_event.type;
738     }
739 
740     std::cout << "\nstart time:     " << cmpltEvent.start_event.stime
741               << "\nexit time:      " << cmpltEvent.ctime
742               << "\npid:            " << cmpltEvent.start_event.pid
743               << "\ntgid:           " << cmpltEvent.start_event.tgid
744               << "\ncomm:           " << cmpltEvent.start_event.comm
745               << "\nprio:           " << cmpltEvent.prio
746               << "\nsize:           " << cmpltEvent.start_event.size
747               << "\nblkcnt:         " << cmpltEvent.blkcnt
748               << "\nips:            " << cmpltEvent.nips
749               << std::setw(WIDE_SIXTEEN) << std::hex;
750     for (uint32_t i = 0; i < cmpltEvent.nips; ++i) {
751         std::cout << "\n    " << cmpltEvent.ips[i];
752     }
753     std::cout << std::dec << std::endl;
754     return 0;
755 }
756 
DumpSTRTraceEvent(void * data,size_t dataSize)757 int BPFController::DumpSTRTraceEvent(void *data, size_t dataSize)
758 {
759     if (dataSize != sizeof(strtrace_cmplt_event_t)) {
760         std::cout << "DumpSTRTraceEvent ERROR: size dismatch:"
761                   << " data size = " << dataSize
762                   << " strtrace event size = " << sizeof(strtrace_cmplt_event_t)
763                   << std::endl;
764         return -1;
765     }
766     struct strtrace_cmplt_event_t cmpltEvent {};
767     if (memcpy_s(&cmpltEvent, sizeof(strtrace_cmplt_event_t), data, dataSize) != EOK) {
768         std::cout << "failed to copy data to strtrace_cmplt_event_t" << std::endl;
769         return -1;
770     }
771     std::cout << "STRTrace Event:"
772               << "\ndata size:      " << dataSize
773               << "\ntracer:         " << cmpltEvent.start_event.stracer
774               << "\ntype:           " << cmpltEvent.start_event.type
775               << "\naddress:        " << cmpltEvent.start_event.addr
776               << "\nstart time:     " << cmpltEvent.start_event.stime
777               << "\npid:            " << cmpltEvent.pid
778               << "\ntgid:           " << cmpltEvent.tgid
779               << "\nfilename len:   " << cmpltEvent.len
780               << "\nfilename:       " << cmpltEvent.filename
781               << std::endl;
782     return 0;
783 }
784 
DumpEvent(void * ctx,void * data,size_t dataSize)785 int BPFController::DumpEvent(void *ctx, void *data, size_t dataSize)
786 {
787     const __u32 *tracer = static_cast<const __u32 *>(data);
788     BPFController *bpfctlr = static_cast<BPFController *>(ctx);
789     if (bpfctlr->config_.dumpEvents_) {
790         --bpfctlr->config_.dumpEvents_;
791         static __u32 counter {0};
792         std::cout << "\ncounter = " << ++counter;
793         switch (*tracer) {
794             case FSTRACE: return DumpFSTraceEvent(bpfctlr, data, dataSize);
795             case PFTRACE: return DumpPFTraceEvent(bpfctlr, data, dataSize);
796             case BIOTRACE: return DumpBIOTraceEvent(bpfctlr, data, dataSize);
797             case STRTRACE: return DumpSTRTraceEvent(data, dataSize);
798         }
799         std::cout << "DumpEvent ERROR: bad tracer type = " << (*tracer) << std::endl;
800     }
801     return 0;
802 }
803 
NextActiveReceiver()804 std::weak_ptr<BPFEventReceiver> BPFController::NextActiveReceiver()
805 {
806     __u32 next = last_ + 1;
807     __u32 total = receivers_.size();
808     for (;;) {
809         if (next >= total) {
810             next -= total;
811         }
812         if (receivers_[next]->Running() or next == last_) {
813             break;
814         }
815         ++next;
816     }
817     if (receivers_[next]->Running()) {
818         last_ = next;
819         return receivers_[last_];
820     }
821     return std::weak_ptr<BPFEventReceiver>();
822 }