diff options
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r-- | tools/perf/util/probe-finder.c | 120 |
1 files changed, 96 insertions, 24 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 1c817add6ca4..50d861a80f57 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -31,6 +31,10 @@ #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 @@ -51,6 +55,7 @@ static const Dwfl_Callbacks offline_callbacks = { static int debuginfo__init_offline_dwarf(struct debuginfo *dbg, const char *path) { + GElf_Addr dummy; int fd; fd = open(path, O_RDONLY); @@ -70,6 +75,8 @@ static int debuginfo__init_offline_dwarf(struct debuginfo *dbg, if (!dbg->dbg) goto error; + dwfl_module_build_id(dbg->mod, &dbg->build_id, &dummy); + dwfl_report_end(dbg->dwfl, NULL, NULL); return 0; @@ -101,6 +108,7 @@ enum dso_binary_type distro_dwarf_types[] = { DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, DSO_BINARY_TYPE__BUILDID_DEBUGINFO, + DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO, DSO_BINARY_TYPE__NOT_FOUND, }; @@ -110,12 +118,17 @@ struct debuginfo *debuginfo__new(const char *path) char buf[PATH_MAX], nil = '\0'; struct dso *dso; struct debuginfo *dinfo = NULL; + struct build_id bid; /* Try to open distro debuginfo files */ dso = dso__new(path); if (!dso) goto out; + /* Set the build id for DSO_BINARY_TYPE__BUILDID_DEBUGINFO */ + if (is_regular_file(path) && filename__read_build_id(path, &bid) > 0) + dso__set_build_id(dso, &bid); + for (type = distro_dwarf_types; !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND; type++) { @@ -156,7 +169,7 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) /* * Convert a location into trace_arg. * If tvar == NULL, this just checks variable can be converted. - * If fentry == true and vr_die is a parameter, do huristic search + * If fentry == true and vr_die is a parameter, do heuristic search * for the location fuzzed by function entry mcount. */ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, @@ -182,6 +195,9 @@ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, immediate_value_is_supported()) { Dwarf_Sword snum; + if (!tvar) + return 0; + dwarf_formsdata(&attr, &snum); ret = asprintf(&tvar->value, "\\%ld", (long)snum); @@ -490,7 +506,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, " nor array.\n", varname); return -EINVAL; } - /* While prcessing unnamed field, we don't care about this */ + /* While processing unnamed field, we don't care about this */ if (field->ref && dwarf_diename(vr_die)) { pr_err("Semantic error: %s must be referred by '.'\n", field->name); @@ -637,17 +653,22 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, return -EINVAL; } - /* Try to get actual symbol name from symtab */ - symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); + if (dwarf_entrypc(sp_die, &eaddr) == 0) { + /* If the DIE has entrypc, use it. */ + symbol = dwarf_diename(sp_die); + } else { + /* Try to get actual symbol name and address from symtab */ + symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); + eaddr = sym.st_value; + } if (!symbol) { pr_warning("Failed to find symbol at 0x%lx\n", (unsigned long)paddr); return -ENOENT; } - eaddr = sym.st_value; tp->offset = (unsigned long)(paddr - eaddr); - tp->address = (unsigned long)paddr; + tp->address = paddr; tp->symbol = strdup(symbol); if (!tp->symbol) return -ENOMEM; @@ -936,6 +957,8 @@ static int probe_point_lazy_walker(const char *fname, int lineno, /* Find probe points from lazy pattern */ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) { + struct build_id bid; + char sbuild_id[SBUILD_ID_SIZE] = ""; int ret = 0; char *fpath; @@ -943,7 +966,11 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) 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__init(&bid, pf->dbg->build_id, BUILD_ID_SIZE); + build_id__sprintf(&bid, 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; @@ -1168,8 +1195,10 @@ static int debuginfo__find_probe_location(struct debuginfo *dbg, while (!dwarf_nextcu(dbg->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { /* Get the DIE(Debugging Information Entry) of this CU */ diep = dwarf_offdie(dbg->dbg, off + cuhl, &pf->cu_die); - if (!diep) + if (!diep) { + off = noff; continue; + } /* Check if target file is included. */ if (pp->file) @@ -1402,6 +1431,9 @@ static int fill_empty_trace_arg(struct perf_probe_event *pev, char *type; int i, j, ret; + if (!ntevs) + return -ENOENT; + for (i = 0; i < pev->nargs; i++) { type = NULL; for (j = 0; j < ntevs; j++) { @@ -1439,7 +1471,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg, 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; @@ -1458,7 +1490,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg, if (ret >= 0 && tf.pf.skip_empty_arg) ret = fill_empty_trace_arg(pev, tf.tevs, tf.ntevs); - if (ret < 0) { + if (ret < 0 || tf.ntevs == 0) { for (i = 0; i < tf.ntevs; i++) clear_probe_trace_event(&tf.tevs[i]); zfree(tevs); @@ -1609,7 +1641,7 @@ int debuginfo__find_available_vars_at(struct debuginfo *dbg, 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; @@ -1675,7 +1707,7 @@ int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs, } /* Reverse search */ -int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, +int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr, struct perf_probe_point *ppt) { Dwarf_Die cudie, spdie, indie; @@ -1688,14 +1720,14 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, addr += baseaddr; /* Find cu die */ if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) { - pr_warning("Failed to find debug information for address %lx\n", + pr_warning("Failed to find debug information for address %" PRIx64 "\n", addr); ret = -EINVAL; goto end; } /* Find a corresponding line (filename and lineno) */ - cu_find_lineinfo(&cudie, addr, &fname, &lineno); + cu_find_lineinfo(&cudie, (Dwarf_Addr)addr, &fname, &lineno); /* Don't care whether it failed or not */ /* Find a corresponding function (name, baseline and baseaddr) */ @@ -1710,7 +1742,7 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, } fname = dwarf_decl_file(&spdie); - if (addr == (unsigned long)baseaddr) { + if (addr == baseaddr) { /* Function entry - Relative line number is 0 */ lineno = baseline; goto post; @@ -1756,7 +1788,7 @@ post: if (lineno) ppt->line = lineno - baseline; else if (basefunc) { - ppt->offset = addr - (unsigned long)baseaddr; + ppt->offset = addr - baseaddr; func = basefunc; } @@ -1796,8 +1828,7 @@ static int line_range_add_line(const char *src, unsigned int lineno, } static int line_range_walk_cb(const char *fname, int lineno, - Dwarf_Addr addr __maybe_unused, - void *data) + Dwarf_Addr addr, void *data) { struct line_finder *lf = data; const char *__fname; @@ -1808,7 +1839,7 @@ static int line_range_walk_cb(const char *fname, int lineno, (lf->lno_s > lineno || lf->lno_e < lineno)) return 0; - /* Make sure this line can be reversable */ + /* Make sure this line can be reversible */ if (cu_find_lineinfo(&lf->cu_die, addr, &__fname, &__lineno) > 0 && (lineno != __lineno || strcmp(fname, __fname))) return 0; @@ -1863,8 +1894,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) return DWARF_CB_OK; - if (die_is_func_def(sp_die) && - die_match_name(sp_die, lr->function)) { + if (die_match_name(sp_die, lr->function) && die_is_func_def(sp_die)) { lf->fname = dwarf_decl_file(sp_die); dwarf_decl_line(sp_die, &lr->offset); pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); @@ -1928,8 +1958,10 @@ int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr) /* Get the DIE(Debugging Information Entry) of this CU */ diep = dwarf_offdie(dbg->dbg, off + cuhl, &lf.cu_die); - if (!diep) + if (!diep) { + off = noff; continue; + } /* Check if target file is included. */ if (lr->file) @@ -1964,17 +1996,57 @@ found: 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 */ |