#include <linux/ctype.h>
 #include <linux/zalloc.h>
 
+#ifdef HAVE_DEBUGINFOD_SUPPORT
+#include <elfutils/debuginfod.h>
+#endif
+
 #define PERFPROBE_GROUP "probe"
 
 bool probe_event_dry_run;      /* Dry run flag */
 
        map = machine__kernel_map(host_machine);
        dso = map->dso;
+       if (!dso->has_build_id)
+               dso__read_running_kernel_build_id(dso, host_machine);
 
        vmlinux_name = symbol_conf.vmlinux_name;
        dso->load_errno = 0;
        return ret;
 }
 
+#ifdef HAVE_DEBUGINFOD_SUPPORT
+static struct debuginfo *open_from_debuginfod(struct dso *dso, struct nsinfo *nsi,
+                                             bool silent)
+{
+       debuginfod_client *c = debuginfod_begin();
+       char sbuild_id[SBUILD_ID_SIZE + 1];
+       struct debuginfo *ret = NULL;
+       struct nscookie nsc;
+       char *path;
+       int fd;
+
+       if (!c)
+               return NULL;
+
+       build_id__sprintf(dso->build_id, BUILD_ID_SIZE, sbuild_id);
+       fd = debuginfod_find_debuginfo(c, (const unsigned char *)sbuild_id,
+                                       0, &path);
+       if (fd >= 0)
+               close(fd);
+       debuginfod_end(c);
+       if (fd < 0) {
+               if (!silent)
+                       pr_debug("Failed to find debuginfo in debuginfod.\n");
+               return NULL;
+       }
+       if (!silent)
+               pr_debug("Load debuginfo from debuginfod (%s)\n", path);
+
+       nsinfo__mountns_enter(nsi, &nsc);
+       ret = debuginfo__new((const char *)path);
+       nsinfo__mountns_exit(&nsc);
+       return ret;
+}
+#else
+static inline
+struct debuginfo *open_from_debuginfod(struct dso *dso __maybe_unused,
+                                      struct nsinfo *nsi __maybe_unused,
+                                      bool silent __maybe_unused)
+{
+       return NULL;
+}
+#endif
+
 /* Open new debuginfo of given module */
 static struct debuginfo *open_debuginfo(const char *module, struct nsinfo *nsi,
                                        bool silent)
                                        strcpy(reason, "(unknown)");
                        } else
                                dso__strerror_load(dso, reason, STRERR_BUFSIZE);
+                       if (dso)
+                               ret = open_from_debuginfod(dso, nsi, silent);
+                       if (ret)
+                               return ret;
                        if (!silent) {
                                if (module)
                                        pr_err("Module %s is not loaded, please specify its full path name.\n", module);
        int ret;
        char *tmp;
        char sbuf[STRERR_BUFSIZE];
+       char sbuild_id[SBUILD_ID_SIZE] = "";
 
        /* Search a line range */
        dinfo = open_debuginfo(module, NULL, false);
                if (!ret)
                        ret = debuginfo__find_line_range(dinfo, lr);
        }
+       if (dinfo->build_id)
+               build_id__sprintf(dinfo->build_id, BUILD_ID_SIZE, sbuild_id);
        debuginfo__delete(dinfo);
        if (ret == 0 || ret == -ENOENT) {
                pr_warning("Specified source line is not found.\n");
 
        /* Convert source file path */
        tmp = lr->path;
-       ret = get_real_path(tmp, lr->comp_dir, &lr->path);
+       ret = find_source_path(tmp, sbuild_id, lr->comp_dir, &lr->path);
 
        /* Free old path when new path is assigned */
        if (tmp != lr->path)
 
 #include "probe-file.h"
 #include "string2.h"
 
+#ifdef HAVE_DEBUGINFOD_SUPPORT
+#include <elfutils/debuginfod.h>
+#endif
+
 /* Kprobe tracer basic type is up to u64 */
 #define MAX_BASIC_TYPE_BITS    64
 
 static int debuginfo__init_offline_dwarf(struct debuginfo *dbg,
                                         const char *path)
 {
+       GElf_Addr dummy;
        int fd;
 
        fd = open(path, O_RDONLY);
        if (!dbg->dbg)
                goto error;
 
+       dwfl_module_build_id(dbg->mod, &dbg->build_id, &dummy);
+
        dwfl_report_end(dbg->dwfl, NULL, NULL);
 
        return 0;
 /* Find probe points from lazy pattern  */
 static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
 {
+       char sbuild_id[SBUILD_ID_SIZE] = "";
        int ret = 0;
        char *fpath;
 
                const char *comp_dir;
 
                comp_dir = cu_get_comp_dir(&pf->cu_die);
-               ret = get_real_path(pf->fname, comp_dir, &fpath);
+               if (pf->dbg->build_id)
+                       build_id__sprintf(pf->dbg->build_id,
+                                       BUILD_ID_SIZE, sbuild_id);
+               ret = find_source_path(pf->fname, sbuild_id, comp_dir, &fpath);
                if (ret < 0) {
                        pr_warning("Failed to find source file path.\n");
                        return ret;
                                 struct probe_trace_event **tevs)
 {
        struct trace_event_finder tf = {
-                       .pf = {.pev = pev, .callback = add_probe_trace_event},
+                       .pf = {.pev = pev, .dbg = dbg, .callback = add_probe_trace_event},
                        .max_tevs = probe_conf.max_probes, .mod = dbg->mod};
        int ret, i;
 
                                      struct variable_list **vls)
 {
        struct available_var_finder af = {
-                       .pf = {.pev = pev, .callback = add_available_vars},
+                       .pf = {.pev = pev, .dbg = dbg, .callback = add_available_vars},
                        .mod = dbg->mod,
                        .max_vls = probe_conf.max_probes};
        int ret;
        return (ret < 0) ? ret : lf.found;
 }
 
+#ifdef HAVE_DEBUGINFOD_SUPPORT
+/* debuginfod doesn't require the comp_dir but buildid is required */
+static int get_source_from_debuginfod(const char *raw_path,
+                               const char *sbuild_id, char **new_path)
+{
+       debuginfod_client *c = debuginfod_begin();
+       const char *p = raw_path;
+       int fd;
+
+       if (!c)
+               return -ENOMEM;
+
+       fd = debuginfod_find_source(c, (const unsigned char *)sbuild_id,
+                               0, p, new_path);
+       pr_debug("Search %s from debuginfod -> %d\n", p, fd);
+       if (fd >= 0)
+               close(fd);
+       debuginfod_end(c);
+       if (fd < 0) {
+               pr_debug("Failed to find %s in debuginfod (%s)\n",
+                       raw_path, sbuild_id);
+               return -ENOENT;
+       }
+       pr_debug("Got a source %s\n", *new_path);
+
+       return 0;
+}
+#else
+static inline int get_source_from_debuginfod(const char *raw_path __maybe_unused,
+                               const char *sbuild_id __maybe_unused,
+                               char **new_path __maybe_unused)
+{
+       return -ENOTSUP;
+}
+#endif
 /*
  * Find a src file from a DWARF tag path. Prepend optional source path prefix
  * and chop off leading directories that do not exist. Result is passed back as
  * a newly allocated path on success.
  * Return 0 if file was found and readable, -errno otherwise.
  */
-int get_real_path(const char *raw_path, const char *comp_dir,
-                        char **new_path)
+int find_source_path(const char *raw_path, const char *sbuild_id,
+               const char *comp_dir, char **new_path)
 {
        const char *prefix = symbol_conf.source_prefix;
 
+       if (sbuild_id && !prefix) {
+               if (!get_source_from_debuginfod(raw_path, sbuild_id, new_path))
+                       return 0;
+       }
+
        if (!prefix) {
                if (raw_path[0] != '/' && comp_dir)
                        /* If not an absolute path, try to use comp_dir */