aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/probe-finder.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2019-11-19 12:59:03 +0100
committerIngo Molnar <mingo@kernel.org>2019-11-19 12:59:03 +0100
commit8f6ee51d772d0dab407d868449d2c5d9c8d2b6fc (patch)
treec60f37861216429b8aef61af401f750701969d6b /tools/perf/util/probe-finder.c
parentMerge tag 'perf-core-for-mingo-5.5-20191112' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core (diff)
parentperf parse: Report initial event parsing error (diff)
downloadlinux-dev-8f6ee51d772d0dab407d868449d2c5d9c8d2b6fc.tar.xz
linux-dev-8f6ee51d772d0dab407d868449d2c5d9c8d2b6fc.zip
Merge tag 'perf-core-for-mingo-5.5-20191119' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: x86/insn: Adrian Hunter: - Add some more Intel instructions to the opcode map: cldemote, encls, enclu, enclv, enqcmd, enqcmds, movdir64b, movdiri, pconfig, tpause, umonitor, umwait, wbnoinvd. - The instruction decoding can be tested using the perf tools' "x86 instruction decoder - new instructions" test as folllows: $ perf test -v "new " 2>&1 | grep -i cldemote Decoded ok: 0f 1c 00 cldemote (%eax) Decoded ok: 0f 1c 05 78 56 34 12 cldemote 0x12345678 Decoded ok: 0f 1c 84 c8 78 56 34 12 cldemote 0x12345678(%eax,%ecx,8) Decoded ok: 0f 1c 00 cldemote (%rax) Decoded ok: 41 0f 1c 00 cldemote (%r8) Decoded ok: 0f 1c 04 25 78 56 34 12 cldemote 0x12345678 Decoded ok: 0f 1c 84 c8 78 56 34 12 cldemote 0x12345678(%rax,%rcx,8) Decoded ok: 41 0f 1c 84 c8 78 56 34 12 cldemote 0x12345678(%r8,%rcx,8) $ perf test -v "new " 2>&1 | grep -i tpause Decoded ok: 66 0f ae f3 tpause %ebx Decoded ok: 66 0f ae f3 tpause %ebx Decoded ok: 66 41 0f ae f0 tpause %r8d callchains: Adrian Hunter: - Fix segfault in thread__resolve_callchain_sample(). perf probe: - Line fixes to show only lines where probes can be used with 'perf probe -L', and when reporting them via 'perf probe -l'. - Support multiprobe events. perf scripts python: Adrian Hunter: - Fix use of TRUE with SQLite < 3.23 in exported-sql-viewer.py. perf maps: - Trim 'struct map' by removing the rb_node member for sorting by map name, as that is only needed for processing kernel maps, and only when classifying symbols by section at load time. Sort them by name using qsort() and do lookups using bsearch() when map_groups__find_by_name() is used. perf parse: Ian Rogers: - Report initial event parsing error, providing a less cryptic message to state that a PMU wasn't found in the system. perf vendor events: James Clark: - Fix commas so that PMU event files for arm64, power8 and power nine become valid JSON. libtraceevent: Konstantin Khlebnikov: - Fix parsing of event %o and %X argument types. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r--tools/perf/util/probe-finder.c116
1 files changed, 112 insertions, 4 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 9ecea45da4ca..38d6cd22779f 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -177,6 +177,17 @@ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
goto static_var;
+ /* Constant value */
+ if (dwarf_attr(vr_die, DW_AT_const_value, &attr) &&
+ immediate_value_is_supported()) {
+ Dwarf_Sword snum;
+
+ dwarf_formsdata(&attr, &snum);
+ ret = asprintf(&tvar->value, "\\%ld", (long)snum);
+
+ return ret < 0 ? -ENOMEM : 0;
+ }
+
/* TODO: handle more than 1 exprs */
if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
return -EINVAL; /* Broken DIE ? */
@@ -525,6 +536,14 @@ next:
return 0;
}
+static void print_var_not_found(const char *varname)
+{
+ pr_err("Failed to find the location of the '%s' variable at this address.\n"
+ " Perhaps it has been optimized out.\n"
+ " Use -V with the --range option to show '%s' location range.\n",
+ varname, varname);
+}
+
/* Show a variables in kprobe event format */
static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
{
@@ -536,11 +555,11 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
&pf->sp_die, pf->machine, pf->tvar);
+ if (ret == -ENOENT && pf->skip_empty_arg)
+ /* This can be found in other place. skip it */
+ return 0;
if (ret == -ENOENT || ret == -EINVAL) {
- pr_err("Failed to find the location of the '%s' variable at this address.\n"
- " Perhaps it has been optimized out.\n"
- " Use -V with the --range option to show '%s' location range.\n",
- pf->pvar->var, pf->pvar->var);
+ print_var_not_found(pf->pvar->var);
} else if (ret == -ENOTSUP)
pr_err("Sorry, we don't support this variable location yet.\n");
else if (ret == 0 && pf->pvar->field) {
@@ -587,6 +606,8 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
/* Search again in global variables */
if (!die_find_variable_at(&pf->cu_die, pf->pvar->var,
0, &vr_die)) {
+ if (pf->skip_empty_arg)
+ return 0;
pr_warning("Failed to find '%s' in this function.\n",
pf->pvar->var);
ret = -ENOENT;
@@ -776,6 +797,39 @@ static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem)
return fsp.found ? die_mem : NULL;
}
+static int verify_representive_line(struct probe_finder *pf, const char *fname,
+ int lineno, Dwarf_Addr addr)
+{
+ const char *__fname, *__func = NULL;
+ Dwarf_Die die_mem;
+ int __lineno;
+
+ /* Verify line number and address by reverse search */
+ if (cu_find_lineinfo(&pf->cu_die, addr, &__fname, &__lineno) < 0)
+ return 0;
+
+ pr_debug2("Reversed line: %s:%d\n", __fname, __lineno);
+ if (strcmp(fname, __fname) || lineno == __lineno)
+ return 0;
+
+ pr_warning("This line is sharing the addrees with other lines.\n");
+
+ if (pf->pev->point.function) {
+ /* Find best match function name and lines */
+ pf->addr = addr;
+ if (find_best_scope(pf, &die_mem)
+ && die_match_name(&die_mem, pf->pev->point.function)
+ && dwarf_decl_line(&die_mem, &lineno) == 0) {
+ __func = dwarf_diename(&die_mem);
+ __lineno -= lineno;
+ }
+ }
+ pr_warning("Please try to probe at %s:%d instead.\n",
+ __func ? : __fname, __lineno);
+
+ return -ENOENT;
+}
+
static int probe_point_line_walker(const char *fname, int lineno,
Dwarf_Addr addr, void *data)
{
@@ -786,6 +840,9 @@ static int probe_point_line_walker(const char *fname, int lineno,
if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
return 0;
+ if (verify_representive_line(pf, fname, lineno, addr))
+ return -ENOENT;
+
pf->addr = addr;
sc_die = find_best_scope(pf, &die_mem);
if (!sc_die) {
@@ -1337,6 +1394,44 @@ end:
return ret;
}
+static int fill_empty_trace_arg(struct perf_probe_event *pev,
+ struct probe_trace_event *tevs, int ntevs)
+{
+ char **valp;
+ char *type;
+ int i, j, ret;
+
+ for (i = 0; i < pev->nargs; i++) {
+ type = NULL;
+ for (j = 0; j < ntevs; j++) {
+ if (tevs[j].args[i].value) {
+ type = tevs[j].args[i].type;
+ break;
+ }
+ }
+ if (j == ntevs) {
+ print_var_not_found(pev->args[i].var);
+ return -ENOENT;
+ }
+ for (j = 0; j < ntevs; j++) {
+ valp = &tevs[j].args[i].value;
+ if (*valp)
+ continue;
+
+ ret = asprintf(valp, "\\%lx", probe_conf.magic_num);
+ if (ret < 0)
+ return -ENOMEM;
+ /* Note that type can be NULL */
+ if (type) {
+ tevs[j].args[i].type = strdup(type);
+ if (!tevs[j].args[i].type)
+ return -ENOMEM;
+ }
+ }
+ }
+ return 0;
+}
+
/* Find probe_trace_events specified by perf_probe_event from debuginfo */
int debuginfo__find_trace_events(struct debuginfo *dbg,
struct perf_probe_event *pev,
@@ -1355,7 +1450,13 @@ int debuginfo__find_trace_events(struct debuginfo *dbg,
tf.tevs = *tevs;
tf.ntevs = 0;
+ if (pev->nargs != 0 && immediate_value_is_supported())
+ tf.pf.skip_empty_arg = true;
+
ret = debuginfo__find_probes(dbg, &tf.pf);
+ if (ret >= 0 && tf.pf.skip_empty_arg)
+ ret = fill_empty_trace_arg(pev, tf.tevs, tf.ntevs);
+
if (ret < 0) {
for (i = 0; i < tf.ntevs; i++)
clear_probe_trace_event(&tf.tevs[i]);
@@ -1698,12 +1799,19 @@ static int line_range_walk_cb(const char *fname, int lineno,
void *data)
{
struct line_finder *lf = data;
+ const char *__fname;
+ int __lineno;
int err;
if ((strtailcmp(fname, lf->fname) != 0) ||
(lf->lno_s > lineno || lf->lno_e < lineno))
return 0;
+ /* Make sure this line can be reversable */
+ if (cu_find_lineinfo(&lf->cu_die, addr, &__fname, &__lineno) > 0
+ && (lineno != __lineno || strcmp(fname, __fname)))
+ return 0;
+
err = line_range_add_line(fname, lineno, lf->lr);
if (err < 0 && err != -EEXIST)
return err;