Keyword **kernel** can be omitted.
 
+                 Note that when probed, some eBPF helpers (e.g.
+                 **bpf_trace_printk**\ () or **bpf_probe_write_user**\ ()) may
+                 print warnings to kernel logs.
+
        **bpftool feature help**
                  Print short help message.
 
 
        COMPONENT_KERNEL,
 };
 
+#define BPF_HELPER_MAKE_ENTRY(name)    [BPF_FUNC_ ## name] = "bpf_" # name
+static const char * const helper_name[] = {
+       __BPF_FUNC_MAPPER(BPF_HELPER_MAKE_ENTRY)
+};
+
+#undef BPF_HELPER_MAKE_ENTRY
+
 /* Miscellaneous utility functions */
 
 static bool check_procfs(void)
        print_bool_feature(feat_name, plain_desc, res);
 }
 
+static void
+probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type)
+{
+       const char *ptype_name = prog_type_name[prog_type];
+       char feat_name[128];
+       unsigned int id;
+       bool res;
+
+       if (json_output) {
+               sprintf(feat_name, "%s_available_helpers", ptype_name);
+               jsonw_name(json_wtr, feat_name);
+               jsonw_start_array(json_wtr);
+       } else {
+               printf("eBPF helpers supported for program type %s:",
+                      ptype_name);
+       }
+
+       for (id = 1; id < ARRAY_SIZE(helper_name); id++) {
+               if (!supported_type)
+                       res = false;
+               else
+                       res = bpf_probe_helper(id, prog_type, 0);
+
+               if (json_output) {
+                       if (res)
+                               jsonw_string(json_wtr, helper_name[id]);
+               } else {
+                       if (res)
+                               printf("\n\t- %s", helper_name[id]);
+               }
+       }
+
+       if (json_output)
+               jsonw_end_array(json_wtr);
+       else
+               printf("\n");
+}
+
 static int do_probe(int argc, char **argv)
 {
        enum probe_component target = COMPONENT_UNSPEC;
        for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++)
                probe_map_type(i);
 
+       print_end_then_start_section("helpers",
+                                    "Scanning eBPF helper functions...");
+
+       for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++)
+               probe_helpers_for_progtype(i, supported_types[i]);
+
 exit_close_json:
        if (json_output) {
                /* End current "section" of probes */
 
 LIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type,
                                    __u32 ifindex);
 LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
+LIBBPF_API bool bpf_probe_helper(enum bpf_func_id id,
+                                enum bpf_prog_type prog_type, __u32 ifindex);
 
 #ifdef __cplusplus
 } /* extern "C" */
 
 
 LIBBPF_0.0.2 {
        global:
+               bpf_probe_helper;
                bpf_probe_map_type;
                bpf_probe_prog_type;
 } LIBBPF_0.0.1;
 
 /* Copyright (c) 2019 Netronome Systems, Inc. */
 
 #include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
 #include <unistd.h>
+#include <net/if.h>
 #include <sys/utsname.h>
 
 #include <linux/filter.h>
 #include "bpf.h"
 #include "libbpf.h"
 
+static bool grep(const char *buffer, const char *pattern)
+{
+       return !!strstr(buffer, pattern);
+}
+
+static int get_vendor_id(int ifindex)
+{
+       char ifname[IF_NAMESIZE], path[64], buf[8];
+       ssize_t len;
+       int fd;
+
+       if (!if_indextoname(ifindex, ifname))
+               return -1;
+
+       snprintf(path, sizeof(path), "/sys/class/net/%s/device/vendor", ifname);
+
+       fd = open(path, O_RDONLY);
+       if (fd < 0)
+               return -1;
+
+       len = read(fd, buf, sizeof(buf));
+       close(fd);
+       if (len < 0)
+               return -1;
+       if (len >= (ssize_t)sizeof(buf))
+               return -1;
+       buf[len] = '\0';
+
+       return strtol(buf, NULL, 0);
+}
+
 static int get_kernel_version(void)
 {
        int version, subversion, patchlevel;
 
        return fd >= 0;
 }
+
+bool bpf_probe_helper(enum bpf_func_id id, enum bpf_prog_type prog_type,
+                     __u32 ifindex)
+{
+       struct bpf_insn insns[2] = {
+               BPF_EMIT_CALL(id),
+               BPF_EXIT_INSN()
+       };
+       char buf[4096] = {};
+       bool res;
+
+       probe_load(prog_type, insns, ARRAY_SIZE(insns), buf, sizeof(buf),
+                  ifindex);
+       res = !grep(buf, "invalid func ") && !grep(buf, "unknown func ");
+
+       if (ifindex) {
+               switch (get_vendor_id(ifindex)) {
+               case 0x19ee: /* Netronome specific */
+                       res = res && !grep(buf, "not supported by FW") &&
+                               !grep(buf, "unsupported function id");
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return res;
+}