1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
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
395 const std::string dynstr {".dynstr"};
396 CHECK_TRUE(elfFile->shdrs_.find(dynstr) != elfFile->shdrs_.end(), 0, "section dynstr failed to obtain data");
397 const auto &str = elfFile->shdrs_[dynstr];
398 const uint8_t *strData = elfFile->GetSectionData(str->secIndex_);
399
400 uint32_t st_name = 0;
401 uint64_t stepLength = 0;
402 uint64_t vaddr = 0;
403 while (stepLength < sym->secSize_) {
404 int ret = memcpy_s(&st_name, sizeof(uint32_t), symData + stepLength, sizeof(uint32_t));
405 CHECK_TRUE(ret == EOK, 0, "failed to memcpy symData");
406 auto name = const_cast<uint8_t*>(strData + st_name);
407 if (name != nullptr && std::string(reinterpret_cast<char*>(name)).compare(symbol) == 0) {
408 int32_t valueOffset = sym->secEntrySize_ == sizeof(Elf64_Sym) ? SYM_64_VALUE_OFFSET : SYM_32_VALUE_OFFSET;
409 int32_t valueSize = valueOffset == SYM_64_VALUE_OFFSET ? sizeof(uint64_t) : sizeof(uint32_t);
410 ret = memcpy_s(&vaddr, sizeof(uint64_t), symData + stepLength + valueOffset, valueSize);
411 CHECK_TRUE(ret == EOK, 0, "failed to memcpy symData");
412 break;
413 }
414 stepLength += sym->secEntrySize_;
415 }
416 CHECK_TRUE(vaddr != 0, 0, "get vaddr failed");
417
418 const std::string text {".text"};
419 CHECK_TRUE(elfFile->shdrs_.find(text) != elfFile->shdrs_.end(), 0, "section text failed to obtain data");
420 const auto &textPtr = elfFile->shdrs_[text];
421 return vaddr - textPtr->secVaddr_ + textPtr->fileOffset_;
422 }
423
ConfigDlopenBPFProg()424 int32_t BPFController::ConfigDlopenBPFProg()
425 {
426 uint64_t symOffset = GetSymOffset(THIRD_PARTY_MUSL_ADDR, "dlopen");
427 CHECK_TRUE(symOffset != 0, -1, "get symOffset failed");
428 skel_->links.uretprobe_dlopen = bpf_program__attach_uprobe(skel_->progs.uretprobe_dlopen,
429 true,
430 -1,
431 THIRD_PARTY_MUSL_ADDR.c_str(),
432 symOffset);
433 CHECK_TRUE(skel_->links.uretprobe_dlopen, -1, "failed to attach uretprobe_dlopen");
434 return 0;
435 }
436
ConfigureBPF()437 int BPFController::ConfigureBPF()
438 {
439 CHECK_TRUE(InitBPFVariables() == 0, -1, "failed to fill config_var_map");
440 HHLOGI(true, "InitBPFVariables() done");
441 CHECK_TRUE(FillTargetPidMap() == 0, -1, "failed to fill target_pid_map");
442 HHLOGI(true, "FillTargetPidMap() done");
443 CHECK_TRUE(ConfigBPFLogger() == 0, -1, "failed to configure BPF logger");
444 HHLOGI(true, "ConfigBPFLogger() done");
445 CHECK_TRUE(ConfigReceivers() == 0, -1, "failed to configure BPF ringbuffer");
446 HHLOGI(true, "ConfigReceivers() done");
447 CHECK_TRUE(ConfigDlopenBPFProg() == 0, -1, "failed to configure user BPF prog");
448 return 0;
449 }
450
Start()451 int BPFController::Start()
452 {
453 #if defined(BPF_LOGGER_DEBUG) || defined(BPF_LOGGER_INFO) || defined(BPF_LOGGER_WARN) || \
454 defined(BPF_LOGGER_ERROR) || defined(BPF_LOGGER_FATAL)
455 CHECK_TRUE(StartBPFLogReader() == 0, -1, "failed to start BPF log reader");
456 #endif
457 HHLOGI(true, "BPF log reader started");
458 CHECK_TRUE(StartReceivers() == 0, -1, "failed to start receivers");
459 HHLOGI(true, "receivers started");
460 // activate events
461 int err = hiebpf_bpf__attach(skel_);
462 CHECK_TRUE(!err, -1, "failed to attach bpf object: %s", strerror(-err));
463 HHLOGI(true, "BPF events activated");
464
465 const auto endTime = std::chrono::steady_clock::now() + std::chrono::seconds(config_.traceDuration_);
466 while (!loopStop_) {
467 if (BPFEventLoopOnce() != 0) {
468 printf("libbpf error occured, hiebpf exit\n");
469 err = -1;
470 break;
471 }
472 if (std::chrono::steady_clock::now() >= endTime) {
473 printf("timeout(%us), hiebpf exit\n", config_.traceDuration_);
474 break;
475 }
476 }
477 // receivers_ must stop after BPFEventLoopOnce();
478 for (size_t k = 0; k < receivers_.size(); ++k) {
479 receivers_[k]->Stop();
480 }
481 if (bpfLogReader_) {
482 bpfLogReader_->Stop();
483 }
484
485 HHLOGI(true, "hiebpf stopped");
486
487 return err;
488 }
489
Stop()490 void BPFController::Stop()
491 {
492 loopStop_ = true;
493 }
494
HandleEvent(void * ctx,void * data,size_t dataSize)495 int BPFController::HandleEvent(void *ctx, void *data, size_t dataSize)
496 {
497 // get the next running receiver
498 BPFController *bpfctlr = static_cast<BPFController *>(ctx);
499 auto wrecv = bpfctlr->NextActiveReceiver();
500 auto receiver = wrecv.lock();
501 if (receiver == nullptr) {
502 HHLOGF(true, "all receivers have stopped, will stop BPF event loop");
503 bpfctlr->Stop();
504 return -1;
505 }
506
507 // move data and notify receiver
508 int ret = receiver->Put(data, dataSize);
509 HHLOGE((ret < 0), "event lost: failed to move data to receiver"); // try other receivers ?
510 HHLOGF(
511 (0 <= ret and ret < static_cast<int>(dataSize)),
512 "incomplete data movement: this should never happen");
513 return ret;
514 }
515
DumpOpenat2Args(const struct fstrace_cmplt_event_t & cmpltEvent)516 static int DumpOpenat2Args(const struct fstrace_cmplt_event_t &cmpltEvent)
517 {
518 std::cout << "\nArgs:";
519 std::cout << "\n dfd = " << cmpltEvent.start_event.openat2_args.dfd;
520 std::cout << "\n filename = " << cmpltEvent.start_event.openat2_args.filename;
521 std::cout << "\n how = " << cmpltEvent.start_event.openat2_args.how;
522 return 0;
523 }
524
DumpReadvArgs(const struct fstrace_cmplt_event_t & cmpltEvent)525 static int DumpReadvArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
526 {
527 std::cout << "\nArgs:";
528 std::cout << "\n fd = " << cmpltEvent.start_event.readv_args.fd;
529 std::cout << "\n vec = " << cmpltEvent.start_event.readv_args.vec;
530 std::cout << "\n vlen = " << cmpltEvent.start_event.readv_args.vlen;
531 std::cout << "\n flags = " << cmpltEvent.start_event.readv_args.flags;
532 return 0;
533 }
534
DumpPreadvArgs(const struct fstrace_cmplt_event_t & cmpltEvent)535 static int DumpPreadvArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
536 {
537 std::cout << "\nArgs:";
538 std::cout << "\n fd = " << cmpltEvent.start_event.preadv_args.fd;
539 std::cout << "\n vec = " << cmpltEvent.start_event.preadv_args.vec;
540 std::cout << "\n vlen = " << cmpltEvent.start_event.preadv_args.vlen;
541 std::cout << "\n pos = " << cmpltEvent.start_event.preadv_args.pos;
542 std::cout << "\n flags = " << cmpltEvent.start_event.preadv_args.flags;
543 return 0;
544 }
545
DumpReadArgs(const struct fstrace_cmplt_event_t & cmpltEvent)546 static int DumpReadArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
547 {
548 std::cout << "\nArgs:";
549 std::cout << "\n fd = " << cmpltEvent.start_event.read_args.fd;
550 std::cout << "\n buf = " << cmpltEvent.start_event.read_args.buf;
551 std::cout << "\n count = " << cmpltEvent.start_event.read_args.count;
552 return 0;
553 }
554
DumpPread64Args(const struct fstrace_cmplt_event_t & cmpltEvent)555 static int DumpPread64Args(const struct fstrace_cmplt_event_t &cmpltEvent)
556 {
557 std::cout << "\nArgs:";
558 std::cout << "\n fd = " << cmpltEvent.start_event.pread64_args.fd;
559 std::cout << "\n buf = " << cmpltEvent.start_event.pread64_args.buf;
560 std::cout << "\n count = " << cmpltEvent.start_event.pread64_args.count;
561 std::cout << "\n pos = " << cmpltEvent.start_event.pread64_args.pos;
562 return 0;
563 }
564
DumpWritevArgs(const struct fstrace_cmplt_event_t & cmpltEvent)565 static int DumpWritevArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
566 {
567 std::cout << "\nArgs:";
568 std::cout << "\n fd = " << cmpltEvent.start_event.writev_args.fd;
569 std::cout << "\n vec = " << cmpltEvent.start_event.writev_args.vec;
570 std::cout << "\n vlen = " << cmpltEvent.start_event.writev_args.vlen;
571 std::cout << "\n flags = " << cmpltEvent.start_event.writev_args.flags;
572 return 0;
573 }
574
DumpPwritevArgs(const struct fstrace_cmplt_event_t & cmpltEvent)575 static int DumpPwritevArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
576 {
577 std::cout << "\nArgs:";
578 std::cout << "\n fd = " << cmpltEvent.start_event.pwritev_args.fd;
579 std::cout << "\n vec = " << cmpltEvent.start_event.pwritev_args.vec;
580 std::cout << "\n vlen = " << cmpltEvent.start_event.pwritev_args.vlen;
581 std::cout << "\n pos = " << cmpltEvent.start_event.pwritev_args.pos;
582 std::cout << "\n flags = " << cmpltEvent.start_event.pwritev_args.flags;
583 return 0;
584 }
585
DumpWriteArgs(const struct fstrace_cmplt_event_t & cmpltEvent)586 static int DumpWriteArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
587 {
588 std::cout << "\nArgs:";
589 std::cout << "\n fd = " << cmpltEvent.start_event.write_args.fd;
590 std::cout << "\n buf = " << cmpltEvent.start_event.write_args.buf;
591 std::cout << "\n count = " << cmpltEvent.start_event.write_args.count;
592 return 0;
593 }
594
DumpPwrite64Args(const struct fstrace_cmplt_event_t & cmpltEvent)595 static int DumpPwrite64Args(const struct fstrace_cmplt_event_t &cmpltEvent)
596 {
597 std::cout << "\nArgs:";
598 std::cout << "\n fd = " << cmpltEvent.start_event.pwrite64_args.fd;
599 std::cout << "\n buf = " << cmpltEvent.start_event.pwrite64_args.buf;
600 std::cout << "\n count = " << cmpltEvent.start_event.pwrite64_args.count;
601 std::cout << "\n pos = " << cmpltEvent.start_event.pwrite64_args.pos;
602 return 0;
603 }
604
DumpCloseArgs(const struct fstrace_cmplt_event_t & cmpltEvent)605 static int DumpCloseArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
606 {
607 std::cout << "\nArgs:";
608 std::cout << "\n files = " << cmpltEvent.start_event.close_args.files;
609 std::cout << "\n fd = " << cmpltEvent.start_event.close_args.fd;
610 return 0;
611 }
612
DumpTypeAndArgs(const struct fstrace_cmplt_event_t & cmpltEvent)613 static int DumpTypeAndArgs(const struct fstrace_cmplt_event_t &cmpltEvent)
614 {
615 std::cout << "\nevent type: ";
616 switch (cmpltEvent.start_event.type) {
617 case SYS_OPENAT2: std::cout << "openat2"; return DumpOpenat2Args(cmpltEvent);
618
619 case SYS_READV: std::cout << "readv"; return DumpReadvArgs(cmpltEvent);
620 case SYS_PREADV: std::cout << "preadv"; return DumpPreadvArgs(cmpltEvent);
621 case SYS_READ: std::cout << "read"; return DumpReadArgs(cmpltEvent);
622 case SYS_PREAD64: std::cout << "pread64"; return DumpPread64Args(cmpltEvent);
623
624 case SYS_WRITEV: std::cout << "writev"; return DumpWritevArgs(cmpltEvent);
625 case SYS_PWRITEV: std::cout << "pwritev"; return DumpPwritevArgs(cmpltEvent);
626 case SYS_WRITE: std::cout << "write"; return DumpWriteArgs(cmpltEvent);
627 case SYS_PWRITE64: std::cout << "pwrite64"; return DumpPwrite64Args(cmpltEvent);
628
629 case SYS_CLOSE: std::cout << "close"; return DumpCloseArgs(cmpltEvent);
630 }
631 HHLOGE(true, "unreognized fstrace event type = %d", cmpltEvent.start_event.type);
632 return -1;
633 }
634
DumpFSTraceEvent(BPFController * bpfctlr,void * data,size_t dataSize)635 int BPFController::DumpFSTraceEvent(BPFController *bpfctlr, void *data, size_t dataSize)
636 {
637 if (dataSize != sizeof(fstrace_cmplt_event_t)) {
638 std::cout << "DumpFSTraceEvent ERROR: size dismatch:"
639 << " data size = " << dataSize
640 << " fstrace event size = " << sizeof(fstrace_cmplt_event_t)
641 << std::endl;
642 return -1;
643 }
644 struct fstrace_cmplt_event_t cmpltEvent {};
645 if (memcpy_s(&cmpltEvent, sizeof(fstrace_cmplt_event_t), data, dataSize) != EOK) {
646 std::cout << "failed to copy data to fstrace_cmplt_event_t" << std::endl;
647 return -1;
648 }
649 std::cout << "\nFSTrace Event:"
650 << "\ndata size: " << dataSize;
651 DumpTypeAndArgs(cmpltEvent);
652 std::cout << "\nretval: " << cmpltEvent.retval
653 << "\nstart time: " << cmpltEvent.start_event.stime
654 << "\nexit time: " << cmpltEvent.ctime
655 << "\npid: " << cmpltEvent.pid
656 << "\ntgid: " << cmpltEvent.tgid
657 << "\ncomm: " << cmpltEvent.comm
658 << "\nips: " << cmpltEvent.nips
659 << "\nips:"
660 << std::setw(WIDE_SIXTEEN) << std::hex;
661 for (uint32_t i = 0; i < cmpltEvent.nips; ++i) {
662 std::cout << "\n " << cmpltEvent.ips[i];
663 }
664 std::cout << std::dec << std::endl;
665 return 0;
666 }
667
DumpPFTraceEvent(BPFController * bpfctlr,void * data,size_t dataSize)668 int BPFController::DumpPFTraceEvent(BPFController *bpfctlr, void *data, size_t dataSize)
669 {
670 if (dataSize != sizeof(pftrace_cmplt_event_t)) {
671 std::cout << "DumpPFTraceEvent ERROR: size dismatch:"
672 << " data size = " << dataSize
673 << " pftrace event size = " << sizeof(pftrace_cmplt_event_t)
674 << std::endl;
675 return -1;
676 }
677 struct pftrace_cmplt_event_t cmpltEvent {};
678 if (memcpy_s(&cmpltEvent, sizeof(pftrace_cmplt_event_t), data, dataSize) != EOK) {
679 std::cout << "failed to copy data to pftrace_cmplt_event_t" << std::endl;
680 return -1;
681 }
682 std::cout << "PFTrace Event:"
683 << "\ndata size: " << dataSize
684 << "\nevent type: ";
685 switch (cmpltEvent.start_event.type) {
686 case PF_COPY_ON_WRITE: std::cout << "Copy On Write"; break;
687 case PF_FAKE_ZERO_PAGE: std::cout << "Zero FAKE Page"; break;
688 case PF_FILE_BACKED_IN: std::cout << "File Backed In"; break;
689 case PF_PAGE_CACHE_HIT: std::cout << "Page Cache Hit"; break;
690 case PF_SWAP_FROM_DISK: std::cout << "Swap From Disk"; break;
691 case PF_SWAP_FROM_ZRAM: std::cout << "Swap From Zram"; break;
692 case PF_ZERO_FILL_PAGE: std::cout << "Zero Fill Page"; break;
693 default: std::cout << cmpltEvent.start_event.type;
694 }
695 std::cout << "\naddress: " << cmpltEvent.start_event.addr
696 << "\nsize: " << cmpltEvent.size
697 << "\nstart time: " << cmpltEvent.start_event.stime
698 << "\nexit time: " << cmpltEvent.ctime
699 << "\npid: " << cmpltEvent.pid
700 << "\ntgid: " << cmpltEvent.tgid
701 << "\ncomm: " << cmpltEvent.comm
702 << "\nips: " << cmpltEvent.nips
703 << std::setw(WIDE_SIXTEEN) << std::hex;
704 for (uint32_t i = 0; i < cmpltEvent.nips; ++i) {
705 std::cout << "\n " << cmpltEvent.ips[i];
706 }
707 std::cout << std::dec << std::endl;
708 return 0;
709 }
710
DumpBIOTraceEvent(BPFController * bpfctlr,void * data,size_t dataSize)711 int BPFController::DumpBIOTraceEvent(BPFController *bpfctlr, void *data, size_t dataSize)
712 {
713 if (dataSize != sizeof(biotrace_cmplt_event_t)) {
714 std::cout << "DumpBIOTraceEvent ERROR: size dismatch:"
715 << " data size = " << dataSize
716 << " biotrace event size = " << sizeof(biotrace_cmplt_event_t)
717 << std::endl;
718 return -1;
719 }
720 struct biotrace_cmplt_event_t cmpltEvent {};
721 if (memcpy_s(&cmpltEvent, sizeof(biotrace_cmplt_event_t), data, dataSize) != EOK) {
722 std::cout << "failed to copy data to biotrace_cmplt_event_t" << std::endl;
723 return -1;
724 }
725 std::cout << "BIOTrace Event:"
726 << "\ndata size: " << dataSize
727 << "\nevent type: ";
728 switch (cmpltEvent.start_event.type) {
729 case BIO_DATA_READ: std::cout << "DATA_READ"; break;
730 case BIO_DATA_WRITE: std::cout << "DATA_WRITE"; break;
731 case BIO_METADATA_READ: std::cout << "METADATA_READ"; break;
732 case BIO_METADATA_WRITE: std::cout << "METADATA_WRITE"; break;
733 case BIO_PAGE_IN: std::cout << "PAGE_IN"; break;
734 case BIO_PAGE_OUT: std::cout << "PAGE_OUT"; break;
735 default: std::cout << cmpltEvent.start_event.type;
736 }
737
738 std::cout << "\nstart time: " << cmpltEvent.start_event.stime
739 << "\nexit time: " << cmpltEvent.ctime
740 << "\npid: " << cmpltEvent.start_event.pid
741 << "\ntgid: " << cmpltEvent.start_event.tgid
742 << "\ncomm: " << cmpltEvent.start_event.comm
743 << "\nprio: " << cmpltEvent.prio
744 << "\nsize: " << cmpltEvent.start_event.size
745 << "\nblkcnt: " << cmpltEvent.blkcnt
746 << "\nips: " << cmpltEvent.nips
747 << std::setw(WIDE_SIXTEEN) << std::hex;
748 for (uint32_t i = 0; i < cmpltEvent.nips; ++i) {
749 std::cout << "\n " << cmpltEvent.ips[i];
750 }
751 std::cout << std::dec << std::endl;
752 return 0;
753 }
754
DumpSTRTraceEvent(void * data,size_t dataSize)755 int BPFController::DumpSTRTraceEvent(void *data, size_t dataSize)
756 {
757 if (dataSize != sizeof(strtrace_cmplt_event_t)) {
758 std::cout << "DumpSTRTraceEvent ERROR: size dismatch:"
759 << " data size = " << dataSize
760 << " strtrace event size = " << sizeof(strtrace_cmplt_event_t)
761 << std::endl;
762 return -1;
763 }
764 struct strtrace_cmplt_event_t cmpltEvent {};
765 if (memcpy_s(&cmpltEvent, sizeof(strtrace_cmplt_event_t), data, dataSize) != EOK) {
766 std::cout << "failed to copy data to strtrace_cmplt_event_t" << std::endl;
767 return -1;
768 }
769 std::cout << "STRTrace Event:"
770 << "\ndata size: " << dataSize
771 << "\ntracer: " << cmpltEvent.start_event.stracer
772 << "\ntype: " << cmpltEvent.start_event.type
773 << "\naddress: " << cmpltEvent.start_event.addr
774 << "\nstart time: " << cmpltEvent.start_event.stime
775 << "\npid: " << cmpltEvent.pid
776 << "\ntgid: " << cmpltEvent.tgid
777 << "\nfilename len: " << cmpltEvent.len
778 << "\nfilename: " << cmpltEvent.filename
779 << std::endl;
780 return 0;
781 }
782
DumpEvent(void * ctx,void * data,size_t dataSize)783 int BPFController::DumpEvent(void *ctx, void *data, size_t dataSize)
784 {
785 const __u32 *tracer = static_cast<const __u32 *>(data);
786 BPFController *bpfctlr = static_cast<BPFController *>(ctx);
787 if (bpfctlr->config_.dumpEvents_) {
788 --bpfctlr->config_.dumpEvents_;
789 static __u32 counter {0};
790 std::cout << "\ncounter = " << ++counter;
791 switch (*tracer) {
792 case FSTRACE: return DumpFSTraceEvent(bpfctlr, data, dataSize);
793 case PFTRACE: return DumpPFTraceEvent(bpfctlr, data, dataSize);
794 case BIOTRACE: return DumpBIOTraceEvent(bpfctlr, data, dataSize);
795 case STRTRACE: return DumpSTRTraceEvent(data, dataSize);
796 }
797 std::cout << "DumpEvent ERROR: bad tracer type = " << (*tracer) << std::endl;
798 }
799 return 0;
800 }
801
NextActiveReceiver()802 std::weak_ptr<BPFEventReceiver> BPFController::NextActiveReceiver()
803 {
804 __u32 next = last_ + 1;
805 __u32 total = receivers_.size();
806 for (;;) {
807 if (next >= total) {
808 next -= total;
809 }
810 if (receivers_[next]->Running() or next == last_) {
811 break;
812 }
813 ++next;
814 }
815 if (receivers_[next]->Running()) {
816 last_ = next;
817 return receivers_[last_];
818 }
819 return std::weak_ptr<BPFEventReceiver>();
820 }