#include <bpf/libbpf.h>
 #include <linux/btf.h>
 #include <linux/err.h>
+#include <linux/string.h>
+#include <internal/lib.h>
+#include <symbol/kallsyms.h>
 #include "bpf-event.h"
 #include "debug.h"
 #include "dso.h"
        return err ? -1 : 0;
 }
 
+struct kallsyms_parse {
+       union perf_event        *event;
+       perf_event__handler_t    process;
+       struct machine          *machine;
+       struct perf_tool        *tool;
+};
+
+static int
+process_bpf_image(char *name, u64 addr, struct kallsyms_parse *data)
+{
+       struct machine *machine = data->machine;
+       union perf_event *event = data->event;
+       struct perf_record_ksymbol *ksymbol;
+       int len;
+
+       ksymbol = &event->ksymbol;
+
+       *ksymbol = (struct perf_record_ksymbol) {
+               .header = {
+                       .type = PERF_RECORD_KSYMBOL,
+                       .size = offsetof(struct perf_record_ksymbol, name),
+               },
+               .addr      = addr,
+               .len       = page_size,
+               .ksym_type = PERF_RECORD_KSYMBOL_TYPE_BPF,
+               .flags     = 0,
+       };
+
+       len = scnprintf(ksymbol->name, KSYM_NAME_LEN, "%s", name);
+       ksymbol->header.size += PERF_ALIGN(len + 1, sizeof(u64));
+       memset((void *) event + event->header.size, 0, machine->id_hdr_size);
+       event->header.size += machine->id_hdr_size;
+
+       return perf_tool__process_synth_event(data->tool, event, machine,
+                                             data->process);
+}
+
+static int
+kallsyms_process_symbol(void *data, const char *_name,
+                       char type __maybe_unused, u64 start)
+{
+       char disp[KSYM_NAME_LEN];
+       char *module, *name;
+       unsigned long id;
+       int err = 0;
+
+       module = strchr(_name, '\t');
+       if (!module)
+               return 0;
+
+       /* We are going after [bpf] module ... */
+       if (strcmp(module + 1, "[bpf]"))
+               return 0;
+
+       name = memdup(_name, (module - _name) + 1);
+       if (!name)
+               return -ENOMEM;
+
+       name[module - _name] = 0;
+
+       /* .. and only for trampolines and dispatchers */
+       if ((sscanf(name, "bpf_trampoline_%lu", &id) == 1) ||
+           (sscanf(name, "bpf_dispatcher_%s", disp) == 1))
+               err = process_bpf_image(name, start, data);
+
+       free(name);
+       return err;
+}
+
 int perf_event__synthesize_bpf_events(struct perf_session *session,
                                      perf_event__handler_t process,
                                      struct machine *machine,
                                      struct record_opts *opts)
 {
+       const char *kallsyms_filename = "/proc/kallsyms";
+       struct kallsyms_parse arg;
        union perf_event *event;
        __u32 id = 0;
        int err;
        event = malloc(sizeof(event->bpf) + KSYM_NAME_LEN + machine->id_hdr_size);
        if (!event)
                return -1;
+
+       /* Synthesize all the bpf programs in system. */
        while (true) {
                err = bpf_prog_get_next_id(id, &id);
                if (err) {
                        break;
                }
        }
+
+       /* Synthesize all the bpf images - trampolines/dispatchers. */
+       if (symbol_conf.kallsyms_name != NULL)
+               kallsyms_filename = symbol_conf.kallsyms_name;
+
+       arg = (struct kallsyms_parse) {
+               .event   = event,
+               .process = process,
+               .machine = machine,
+               .tool    = session->tool,
+       };
+
+       if (kallsyms__parse(kallsyms_filename, &arg, kallsyms_process_symbol)) {
+               pr_err("%s: failed to synthesize bpf images: %s\n",
+                      __func__, strerror(errno));
+       }
+
        free(event);
        return err;
 }