bcc: Add kernel_struct_has_field function to BPF object
authorHengqi Chen <chenhengqi@outlook.com>
Sun, 31 Oct 2021 13:29:45 +0000 (21:29 +0800)
committeryonghong-song <ys114321@gmail.com>
Mon, 1 Nov 2021 15:07:53 +0000 (08:07 -0700)
Add a new function kernel_struct_has_field, which allows user to
check that whether a kernel struct has a specific field. This
enable us to deal with some kernel changes like in 2f064a59a1 ([0])
of the linux kernel.

  [0]: https://github.com/torvalds/linux/commit/2f064a59a1

Signed-off-by: Hengqi Chen <chenhengqi@outlook.com>
src/cc/libbpf.c
src/cc/libbpf.h
src/python/bcc/__init__.py
src/python/bcc/libbcc.py

index b1787e166dc2757440ca4adccf1587f9552bf1d2..6c2faed6ce900b63d34b55d711d955801ecdd481 100644 (file)
@@ -558,8 +558,8 @@ int bpf_prog_compute_tag(const struct bpf_insn *insns, int prog_len,
   }
 
   union {
-         unsigned char sha[20];
-         unsigned long long tag;
+    unsigned char sha[20];
+    unsigned long long tag;
   } u = {};
   ret = read(shafd2, u.sha, 20);
   if (ret != 20) {
@@ -1109,8 +1109,8 @@ static int bpf_attach_probe(int progfd, enum bpf_probe_attach_type attach_type,
     // delete that event and start again without maxactive.
     if (is_kprobe && maxactive > 0 && attach_type == BPF_PROBE_RETURN) {
       if (snprintf(fname, sizeof(fname), "%s/id", buf) >= sizeof(fname)) {
-       fprintf(stderr, "filename (%s) is too long for buffer\n", buf);
-       goto error;
+        fprintf(stderr, "filename (%s) is too long for buffer\n", buf);
+        goto error;
       }
       if (access(fname, F_OK) == -1) {
         // Deleting kprobe event with incorrect name.
@@ -1286,6 +1286,39 @@ bool bpf_has_kernel_btf(void)
   return libbpf_find_vmlinux_btf_id("bpf_prog_put", 0) > 0;
 }
 
+int kernel_struct_has_field(const char *struct_name, const char *field_name)
+{
+  const struct btf_type *btf_type;
+  const struct btf_member *btf_member;
+  struct btf *btf;
+  int i, ret, btf_id;
+
+  btf = btf__load_vmlinux_btf();
+  ret = libbpf_get_error(btf);
+  if (ret)
+    return -1;
+
+  btf_id = btf__find_by_name_kind(btf, struct_name, BTF_KIND_STRUCT);
+  if (btf_id < 0) {
+    ret = -1;
+    goto cleanup;
+  }
+
+  btf_type = btf__type_by_id(btf, btf_id);
+  btf_member = btf_members(btf_type);
+  for (i = 0; i < btf_vlen(btf_type); i++, btf_member++) {
+    if (!strcmp(btf__name_by_offset(btf, btf_member->name_off), field_name)) {
+      ret = 1;
+      goto cleanup;
+    }
+  }
+  ret = 0;
+
+cleanup:
+  btf__free(btf);
+  return ret;
+}
+
 int bpf_attach_kfunc(int prog_fd)
 {
   int ret;
index 657ed7c9728bb0a8f8e1b3677ecaa346606dfa79..b3608e22a4f3db23cd45afafa6847a3e1c0a1f87 100644 (file)
@@ -101,6 +101,8 @@ int bpf_attach_lsm(int prog_fd);
 
 bool bpf_has_kernel_btf(void);
 
+int kernel_struct_has_field(const char *struct_name, const char *field_name);
+
 void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb,
                             perf_reader_lost_cb lost_cb, void *cb_cookie,
                             int pid, int cpu, int page_cnt);
index b4a05219f1cd21d7ddb4aac309a49cfec07a6c93..2c014c786505616ba0cbeb588d5f02918ccf6e4f 100644 (file)
@@ -104,7 +104,6 @@ class SymbolCache(object):
             return -1
         return addr.value
 
-
 class PerfType:
     # From perf_type_id in uapi/linux/perf_event.h
     HARDWARE = 0
@@ -896,7 +895,6 @@ class BPF(object):
         else:
             self.detach_kprobe_event(ev_name)
 
-
     def detach_kretprobe(self, event, fn_name=None):
         event = _assert_is_bytes(event)
         ev_name = b"r_" + event.replace(b"+", b"_").replace(b".", b"_")
@@ -939,8 +937,6 @@ class BPF(object):
             raise Exception("Failed to detach BPF from device %s: %s"
                             % (dev, errstr))
 
-
-
     @classmethod
     def _check_path_symbol(cls, module, symname, addr, pid, sym_off=0):
         module = _assert_is_bytes(module)
@@ -1183,6 +1179,12 @@ class BPF(object):
                     return True
             return False
 
+    @staticmethod
+    def kernel_struct_has_field(struct_name, field_name):
+        struct_name = _assert_is_bytes(struct_name)
+        field_name = _assert_is_bytes(field_name)
+        return lib.kernel_struct_has_field(struct_name, field_name)
+
     def detach_tracepoint(self, tp=b""):
         """detach_tracepoint(tp="")
 
index 049968bbe688338645746b77c707616a8ea90d38..3a39d04475541fd71826ea3feecc1fb909d1000b 100644 (file)
@@ -132,6 +132,8 @@ lib.bpf_prog_detach2.restype = ct.c_int
 lib.bpf_prog_detach2.argtype = [ct.c_int, ct.c_int, ct.c_int]
 lib.bpf_has_kernel_btf.restype = ct.c_bool
 lib.bpf_has_kernel_btf.argtypes = None
+lib.kernel_struct_has_field.restype = ct.c_int
+lib.kernel_struct_has_field.argtypes = [ct.c_char_p, ct.c_char_p]
 lib.bpf_open_perf_buffer.restype = ct.c_void_p
 lib.bpf_open_perf_buffer.argtypes = [_RAW_CB_TYPE, _LOST_CB_TYPE, ct.py_object, ct.c_int, ct.c_int, ct.c_int]
 lib.bpf_open_perf_event.restype = ct.c_int