File: KFuncExample.cc

package info (click to toggle)
bpfcc 0.18.0%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 12,368 kB
  • sloc: ansic: 132,727; python: 36,226; cpp: 26,973; sh: 710; yacc: 525; makefile: 141; lex: 94
file content (127 lines) | stat: -rw-r--r-- 2,939 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
 * Copyright (c) Facebook, Inc.
 * Licensed under the Apache License, Version 2.0 (the "License")
 *
 * Usage:
 *   ./KFunc
 * A sample output:
 *   Started tracing, hit Ctrl-C to terminate.
 *      FD  FNAME
 *    NONE  /proc/stat
 *      87  /proc/stat
 *    NONE  /proc/8208/status
 *      36  /proc/8208/status
 *    NONE  /proc/8208/status
 *      36  /proc/8208/status
 *    ...
 *
 * KFunc support is only available at kernel version 5.5 and later.
 * This example only works for x64.
 */

#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>

#include "bcc_version.h"
#include "BPF.h"

const std::string BPF_PROGRAM = R"(
#include <linux/ptrace.h>

struct info_t {
  char name[64];
  int fd;
  int is_ret;
};
BPF_PERF_OUTPUT(events);

KFUNC_PROBE(__x64_sys_openat, struct pt_regs *regs)
{
  const char __user *filename = (char *)PT_REGS_PARM2(regs);
  struct info_t info = {};

  bpf_probe_read_user_str(info.name, sizeof(info.name), filename);
  info.is_ret = 0;
  events.perf_submit(ctx, &info, sizeof(info));
  return 0;
}

KRETFUNC_PROBE(__x64_sys_openat, struct pt_regs *regs, int ret)
{
  const char __user *filename = (char *)PT_REGS_PARM2(regs);
  struct info_t info = {};

  bpf_probe_read_user_str(info.name, sizeof(info.name), filename);
  info.fd = ret;
  info.is_ret = 1;
  events.perf_submit(ctx, &info, sizeof(info));
  return 0;
}
)";

struct info_t {
  char name[64];
  int fd;
  int is_ret;
};

void handle_output(void *cb_cookie, void *data, int data_size) {
  auto info = static_cast<info_t *>(data);
  if (info->is_ret)
    std::cout << std::setw(5) << info->fd << "  " << info->name << std::endl;
  else
    std::cout << " NONE  " << info->name << std::endl;
}

int main() {
  ebpf::BPF bpf;
  auto res = bpf.init(BPF_PROGRAM);
  if (res.code() != 0) {
    std::cerr << res.msg() << std::endl;
    return 1;
  }

  int prog_fd;
  res = bpf.load_func("kfunc____x64_sys_openat", BPF_PROG_TYPE_TRACING, prog_fd);
  if (res.code() != 0) {
    std::cerr << res.msg() << std::endl;
    return 1;
  }

  int ret = bpf_attach_kfunc(prog_fd);
  if (ret < 0) {
    std::cerr << "bpf_attach_kfunc failed: " << ret << std::endl;
    return 1;
  }

  res = bpf.load_func("kretfunc____x64_sys_openat", BPF_PROG_TYPE_TRACING, prog_fd);
  if (res.code() != 0) {
    std::cerr << res.msg() << std::endl;
    return 1;
  }

  ret = bpf_attach_kfunc(prog_fd);
  if (ret < 0) {
    std::cerr << "bpf_attach_kfunc failed: " << ret << std::endl;
    return 1;
  }

  auto open_res = bpf.open_perf_buffer("events", &handle_output);
  if (open_res.code() != 0) {
    std::cerr << open_res.msg() << std::endl;
    return 1;
  }

  std::cout << "Started tracing, hit Ctrl-C to terminate." << std::endl;
  std::cout << "   FD  FNAME" << std::endl;
  auto perf_buffer = bpf.get_perf_buffer("events");
  if (perf_buffer) {
    while (true)
      // 100ms timeout
      perf_buffer->poll(100);
  }

  return 0;
}