Skip to content

Commit cb40273

Browse files
mhiramatacmel
authored andcommitted
perf probe: Trace a magic number if variable is not found
Trace a magic number as immediate value if the target variable is not found at some probe points which is based on one probe event. This feature is good for the case if you trace a source code line with some local variables, which is compiled into several instructions and some of the variables are optimized out on some instructions. Even if so, with this feature, perf probe trace a magic number instead of such disappeared variables and fold those probes on one event. E.g. without this patch: # perf probe -D "pud_page_vaddr pud" Failed to find 'pud' in this function. Failed to find 'pud' in this function. Failed to find 'pud' in this function. Failed to find 'pud' in this function. Failed to find 'pud' in this function. Failed to find 'pud' in this function. Failed to find 'pud' in this function. Failed to find 'pud' in this function. Failed to find 'pud' in this function. Failed to find 'pud' in this function. Failed to find 'pud' in this function. Failed to find 'pud' in this function. Failed to find 'pud' in this function. Failed to find 'pud' in this function. Failed to find 'pud' in this function. Failed to find 'pud' in this function. p:probe/pud_page_vaddr _text+23480787 pud=%ax:x64 p:probe/pud_page_vaddr _text+23808453 pud=%bp:x64 p:probe/pud_page_vaddr _text+23558082 pud=%ax:x64 p:probe/pud_page_vaddr _text+328373 pud=%r8:x64 p:probe/pud_page_vaddr _text+348448 pud=%bx:x64 p:probe/pud_page_vaddr _text+23816818 pud=%bx:x64 With this patch: # perf probe -D "pud_page_vaddr pud" | head spurious_kernel_fault is blacklisted function, skip it. vmalloc_fault is blacklisted function, skip it. p:probe/pud_page_vaddr _text+23480787 pud=%ax:x64 p:probe/pud_page_vaddr _text+149051 pud=\deade12d:x64 p:probe/pud_page_vaddr _text+23808453 pud=%bp:x64 p:probe/pud_page_vaddr _text+315926 pud=\deade12d:x64 p:probe/pud_page_vaddr _text+23807209 pud=\deade12d:x64 p:probe/pud_page_vaddr _text+23557365 pud=%ax:x64 p:probe/pud_page_vaddr _text+314097 pud=%di:x64 p:probe/pud_page_vaddr _text+314015 pud=\deade12d:x64 p:probe/pud_page_vaddr _text+313893 pud=\deade12d:x64 p:probe/pud_page_vaddr _text+324083 pud=\deade12d:x64 Signed-off-by: Masami Hiramatsu <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Ravi Bangoria <[email protected]> Cc: Steven Rostedt (VMware) <[email protected]> Cc: Tom Zanussi <[email protected]> Link: http://lore.kernel.org/lkml/157406476931.24476.6261475888681844285.stgit@devnote2 Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 66f69b2 commit cb40273

File tree

4 files changed

+63
-5
lines changed

4 files changed

+63
-5
lines changed

tools/perf/util/probe-event.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
#define PERFPROBE_GROUP "probe"
4747

4848
bool probe_event_dry_run; /* Dry run flag */
49-
struct probe_conf probe_conf;
49+
struct probe_conf probe_conf = { .magic_num = DEFAULT_PROBE_MAGIC_NUM };
5050

5151
#define semantic_error(msg ...) pr_err("Semantic error :" msg)
5252

tools/perf/util/probe-event.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@ struct probe_conf {
1616
bool no_inlines;
1717
bool cache;
1818
int max_probes;
19+
unsigned long magic_num;
1920
};
2021
extern struct probe_conf probe_conf;
2122
extern bool probe_event_dry_run;
2223

24+
#define DEFAULT_PROBE_MAGIC_NUM 0xdeade12d /* u32: 3735937325 */
25+
2326
struct symbol;
2427

2528
/* kprobe-tracer and uprobe-tracer tracing point */

tools/perf/util/probe-finder.c

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,14 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
536536
return 0;
537537
}
538538

539+
static void print_var_not_found(const char *varname)
540+
{
541+
pr_err("Failed to find the location of the '%s' variable at this address.\n"
542+
" Perhaps it has been optimized out.\n"
543+
" Use -V with the --range option to show '%s' location range.\n",
544+
varname, varname);
545+
}
546+
539547
/* Show a variables in kprobe event format */
540548
static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
541549
{
@@ -547,11 +555,11 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
547555

548556
ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
549557
&pf->sp_die, pf->machine, pf->tvar);
558+
if (ret == -ENOENT && pf->skip_empty_arg)
559+
/* This can be found in other place. skip it */
560+
return 0;
550561
if (ret == -ENOENT || ret == -EINVAL) {
551-
pr_err("Failed to find the location of the '%s' variable at this address.\n"
552-
" Perhaps it has been optimized out.\n"
553-
" Use -V with the --range option to show '%s' location range.\n",
554-
pf->pvar->var, pf->pvar->var);
562+
print_var_not_found(pf->pvar->var);
555563
} else if (ret == -ENOTSUP)
556564
pr_err("Sorry, we don't support this variable location yet.\n");
557565
else if (ret == 0 && pf->pvar->field) {
@@ -598,6 +606,8 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
598606
/* Search again in global variables */
599607
if (!die_find_variable_at(&pf->cu_die, pf->pvar->var,
600608
0, &vr_die)) {
609+
if (pf->skip_empty_arg)
610+
return 0;
601611
pr_warning("Failed to find '%s' in this function.\n",
602612
pf->pvar->var);
603613
ret = -ENOENT;
@@ -1384,6 +1394,44 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
13841394
return ret;
13851395
}
13861396

1397+
static int fill_empty_trace_arg(struct perf_probe_event *pev,
1398+
struct probe_trace_event *tevs, int ntevs)
1399+
{
1400+
char **valp;
1401+
char *type;
1402+
int i, j, ret;
1403+
1404+
for (i = 0; i < pev->nargs; i++) {
1405+
type = NULL;
1406+
for (j = 0; j < ntevs; j++) {
1407+
if (tevs[j].args[i].value) {
1408+
type = tevs[j].args[i].type;
1409+
break;
1410+
}
1411+
}
1412+
if (j == ntevs) {
1413+
print_var_not_found(pev->args[i].var);
1414+
return -ENOENT;
1415+
}
1416+
for (j = 0; j < ntevs; j++) {
1417+
valp = &tevs[j].args[i].value;
1418+
if (*valp)
1419+
continue;
1420+
1421+
ret = asprintf(valp, "\\%lx", probe_conf.magic_num);
1422+
if (ret < 0)
1423+
return -ENOMEM;
1424+
/* Note that type can be NULL */
1425+
if (type) {
1426+
tevs[j].args[i].type = strdup(type);
1427+
if (!tevs[j].args[i].type)
1428+
return -ENOMEM;
1429+
}
1430+
}
1431+
}
1432+
return 0;
1433+
}
1434+
13871435
/* Find probe_trace_events specified by perf_probe_event from debuginfo */
13881436
int debuginfo__find_trace_events(struct debuginfo *dbg,
13891437
struct perf_probe_event *pev,
@@ -1402,7 +1450,13 @@ int debuginfo__find_trace_events(struct debuginfo *dbg,
14021450
tf.tevs = *tevs;
14031451
tf.ntevs = 0;
14041452

1453+
if (pev->nargs != 0 && immediate_value_is_supported())
1454+
tf.pf.skip_empty_arg = true;
1455+
14051456
ret = debuginfo__find_probes(dbg, &tf.pf);
1457+
if (ret >= 0 && tf.pf.skip_empty_arg)
1458+
ret = fill_empty_trace_arg(pev, tf.tevs, tf.ntevs);
1459+
14061460
if (ret < 0) {
14071461
for (i = 0; i < tf.ntevs; i++)
14081462
clear_probe_trace_event(&tf.tevs[i]);

tools/perf/util/probe-finder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ struct probe_finder {
8787
unsigned int machine; /* Target machine arch */
8888
struct perf_probe_arg *pvar; /* Current target variable */
8989
struct probe_trace_arg *tvar; /* Current result variable */
90+
bool skip_empty_arg; /* Skip non-exist args */
9091
};
9192

9293
struct trace_event_finder {

0 commit comments

Comments
 (0)