aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/probe-finder.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r--tools/perf/util/probe-finder.c100
1 files changed, 84 insertions, 16 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index b5247d777f0e..b5bf9d5efeaf 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -456,11 +456,12 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
return -EINVAL;
}
if (field->name[0] == '[') {
- pr_err("Semantic error: %s is not a pointor"
+ pr_err("Semantic error: %s is not a pointer"
" nor array.\n", varname);
return -EINVAL;
}
- if (field->ref) {
+ /* While prcessing 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);
return -EINVAL;
@@ -491,6 +492,11 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
}
ref->offset += (long)offs;
+ /* If this member is unnamed, we need to reuse this field */
+ if (!dwarf_diename(die_mem))
+ return convert_variable_fields(die_mem, varname, field,
+ &ref, die_mem);
+
next:
/* Converting next field */
if (field->next)
@@ -849,11 +855,22 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
{
int ret = 0;
+ char *fpath;
if (intlist__empty(pf->lcache)) {
+ const char *comp_dir;
+
+ comp_dir = cu_get_comp_dir(&pf->cu_die);
+ ret = get_real_path(pf->fname, comp_dir, &fpath);
+ if (ret < 0) {
+ pr_warning("Failed to find source file path.\n");
+ return ret;
+ }
+
/* Matching lazy line pattern */
- ret = find_lazy_match_lines(pf->lcache, pf->fname,
+ ret = find_lazy_match_lines(pf->lcache, fpath,
pf->pev->point.lazy_line);
+ free(fpath);
if (ret <= 0)
return ret;
}
@@ -915,17 +932,13 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
dwarf_decl_line(sp_die, &pf->lno);
pf->lno += pp->line;
param->retval = find_probe_point_by_line(pf);
- } else if (!dwarf_func_inline(sp_die)) {
+ } else if (die_is_func_instance(sp_die)) {
+ /* Instances always have the entry address */
+ dwarf_entrypc(sp_die, &pf->addr);
/* Real function */
if (pp->lazy_line)
param->retval = find_probe_point_lazy(sp_die, pf);
else {
- if (dwarf_entrypc(sp_die, &pf->addr) != 0) {
- pr_warning("Failed to get entry address of "
- "%s.\n", dwarf_diename(sp_die));
- param->retval = -ENOENT;
- return DWARF_CB_ABORT;
- }
pf->addr += pp->offset;
/* TODO: Check the address in this function */
param->retval = call_probe_finder(sp_die, pf);
@@ -1053,7 +1066,7 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
if (pp->function)
ret = find_probe_point_by_func(pf);
else if (pp->lazy_line)
- ret = find_probe_point_lazy(NULL, pf);
+ ret = find_probe_point_lazy(&pf->cu_die, pf);
else {
pf->lno = pp->line;
ret = find_probe_point_by_line(pf);
@@ -1349,11 +1362,8 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr,
const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp;
int baseline = 0, lineno = 0, ret = 0;
- /* Adjust address with bias */
- addr += dbg->bias;
-
/* Find cu die */
- if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr - dbg->bias, &cudie)) {
+ if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) {
pr_warning("Failed to find debug information for address %lx\n",
addr);
ret = -EINVAL;
@@ -1536,7 +1546,7 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e);
lr->start = lf->lno_s;
lr->end = lf->lno_e;
- if (dwarf_func_inline(sp_die))
+ if (!die_is_func_instance(sp_die))
param->retval = die_walk_instances(sp_die,
line_range_inline_cb, lf);
else
@@ -1623,3 +1633,61 @@ found:
return (ret < 0) ? ret : lf.found;
}
+/*
+ * 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)
+{
+ const char *prefix = symbol_conf.source_prefix;
+
+ if (!prefix) {
+ if (raw_path[0] != '/' && comp_dir)
+ /* If not an absolute path, try to use comp_dir */
+ prefix = comp_dir;
+ else {
+ if (access(raw_path, R_OK) == 0) {
+ *new_path = strdup(raw_path);
+ return *new_path ? 0 : -ENOMEM;
+ } else
+ return -errno;
+ }
+ }
+
+ *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2));
+ if (!*new_path)
+ return -ENOMEM;
+
+ for (;;) {
+ sprintf(*new_path, "%s/%s", prefix, raw_path);
+
+ if (access(*new_path, R_OK) == 0)
+ return 0;
+
+ if (!symbol_conf.source_prefix) {
+ /* In case of searching comp_dir, don't retry */
+ zfree(new_path);
+ return -errno;
+ }
+
+ switch (errno) {
+ case ENAMETOOLONG:
+ case ENOENT:
+ case EROFS:
+ case EFAULT:
+ raw_path = strchr(++raw_path, '/');
+ if (!raw_path) {
+ zfree(new_path);
+ return -ENOENT;
+ }
+ continue;
+
+ default:
+ zfree(new_path);
+ return -errno;
+ }
+ }
+}