diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2013-10-11 03:10:23 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2013-10-23 08:55:37 -0400 |
commit | 7969ec7728ba6340de8000ddb0a8833273629d6a (patch) | |
tree | 9dfcf92c7e150c1c87701a9ec874577a41e1870d /tools | |
parent | c824c4338ac47979c69ba6f8faab33670ae179df (diff) |
perf probe: Support "$vars" meta argument syntax for local variables
Support "$vars" meta argument syntax for tracing all local variables at
probe point.
Now you can trace all available local variables (including function
parameters) at the probe point by passing $vars.
# perf probe --add foo $vars
This automatically finds all local variables at foo() and adds it as
probe arguments.
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20131011071023.15557.51770.stgit@udc4-manage.rcp.hitachi.co.jp
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/util/probe-event.c | 1 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 96 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.h | 1 |
3 files changed, 89 insertions, 9 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 779b2dacd43f..9c6989ca2bea 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -47,7 +47,6 @@ | |||
47 | #include "session.h" | 47 | #include "session.h" |
48 | 48 | ||
49 | #define MAX_CMDLEN 256 | 49 | #define MAX_CMDLEN 256 |
50 | #define MAX_PROBE_ARGS 128 | ||
51 | #define PERFPROBE_GROUP "probe" | 50 | #define PERFPROBE_GROUP "probe" |
52 | 51 | ||
53 | bool probe_event_dry_run; /* Dry run flag */ | 52 | bool probe_event_dry_run; /* Dry run flag */ |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index c09e0a9fdf4c..5a46be968c0b 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -1136,12 +1136,78 @@ found: | |||
1136 | return ret; | 1136 | return ret; |
1137 | } | 1137 | } |
1138 | 1138 | ||
1139 | struct local_vars_finder { | ||
1140 | struct probe_finder *pf; | ||
1141 | struct perf_probe_arg *args; | ||
1142 | int max_args; | ||
1143 | int nargs; | ||
1144 | int ret; | ||
1145 | }; | ||
1146 | |||
1147 | /* Collect available variables in this scope */ | ||
1148 | static int copy_variables_cb(Dwarf_Die *die_mem, void *data) | ||
1149 | { | ||
1150 | struct local_vars_finder *vf = data; | ||
1151 | int tag; | ||
1152 | |||
1153 | tag = dwarf_tag(die_mem); | ||
1154 | if (tag == DW_TAG_formal_parameter || | ||
1155 | tag == DW_TAG_variable) { | ||
1156 | if (convert_variable_location(die_mem, vf->pf->addr, | ||
1157 | vf->pf->fb_ops, NULL) == 0) { | ||
1158 | vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem); | ||
1159 | if (vf->args[vf->nargs].var == NULL) { | ||
1160 | vf->ret = -ENOMEM; | ||
1161 | return DIE_FIND_CB_END; | ||
1162 | } | ||
1163 | pr_debug(" %s", vf->args[vf->nargs].var); | ||
1164 | vf->nargs++; | ||
1165 | } | ||
1166 | } | ||
1167 | |||
1168 | if (dwarf_haspc(die_mem, vf->pf->addr)) | ||
1169 | return DIE_FIND_CB_CONTINUE; | ||
1170 | else | ||
1171 | return DIE_FIND_CB_SIBLING; | ||
1172 | } | ||
1173 | |||
1174 | static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf, | ||
1175 | struct perf_probe_arg *args) | ||
1176 | { | ||
1177 | Dwarf_Die die_mem; | ||
1178 | int i; | ||
1179 | int n = 0; | ||
1180 | struct local_vars_finder vf = {.pf = pf, .args = args, | ||
1181 | .max_args = MAX_PROBE_ARGS, .ret = 0}; | ||
1182 | |||
1183 | for (i = 0; i < pf->pev->nargs; i++) { | ||
1184 | /* var never be NULL */ | ||
1185 | if (strcmp(pf->pev->args[i].var, "$vars") == 0) { | ||
1186 | pr_debug("Expanding $vars into:"); | ||
1187 | vf.nargs = n; | ||
1188 | /* Special local variables */ | ||
1189 | die_find_child(sc_die, copy_variables_cb, (void *)&vf, | ||
1190 | &die_mem); | ||
1191 | pr_debug(" (%d)\n", vf.nargs - n); | ||
1192 | if (vf.ret < 0) | ||
1193 | return vf.ret; | ||
1194 | n = vf.nargs; | ||
1195 | } else { | ||
1196 | /* Copy normal argument */ | ||
1197 | args[n] = pf->pev->args[i]; | ||
1198 | n++; | ||
1199 | } | ||
1200 | } | ||
1201 | return n; | ||
1202 | } | ||
1203 | |||
1139 | /* Add a found probe point into trace event list */ | 1204 | /* Add a found probe point into trace event list */ |
1140 | static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) | 1205 | static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) |
1141 | { | 1206 | { |
1142 | struct trace_event_finder *tf = | 1207 | struct trace_event_finder *tf = |
1143 | container_of(pf, struct trace_event_finder, pf); | 1208 | container_of(pf, struct trace_event_finder, pf); |
1144 | struct probe_trace_event *tev; | 1209 | struct probe_trace_event *tev; |
1210 | struct perf_probe_arg *args; | ||
1145 | int ret, i; | 1211 | int ret, i; |
1146 | 1212 | ||
1147 | /* Check number of tevs */ | 1213 | /* Check number of tevs */ |
@@ -1161,21 +1227,35 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) | |||
1161 | pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, | 1227 | pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, |
1162 | tev->point.offset); | 1228 | tev->point.offset); |
1163 | 1229 | ||
1164 | /* Find each argument */ | 1230 | /* Expand special probe argument if exist */ |
1165 | tev->nargs = pf->pev->nargs; | 1231 | args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS); |
1166 | tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); | 1232 | if (args == NULL) |
1167 | if (tev->args == NULL) | ||
1168 | return -ENOMEM; | 1233 | return -ENOMEM; |
1169 | for (i = 0; i < pf->pev->nargs; i++) { | 1234 | |
1170 | pf->pvar = &pf->pev->args[i]; | 1235 | ret = expand_probe_args(sc_die, pf, args); |
1236 | if (ret < 0) | ||
1237 | goto end; | ||
1238 | |||
1239 | tev->nargs = ret; | ||
1240 | tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); | ||
1241 | if (tev->args == NULL) { | ||
1242 | ret = -ENOMEM; | ||
1243 | goto end; | ||
1244 | } | ||
1245 | |||
1246 | /* Find each argument */ | ||
1247 | for (i = 0; i < tev->nargs; i++) { | ||
1248 | pf->pvar = &args[i]; | ||
1171 | pf->tvar = &tev->args[i]; | 1249 | pf->tvar = &tev->args[i]; |
1172 | /* Variable should be found from scope DIE */ | 1250 | /* Variable should be found from scope DIE */ |
1173 | ret = find_variable(sc_die, pf); | 1251 | ret = find_variable(sc_die, pf); |
1174 | if (ret != 0) | 1252 | if (ret != 0) |
1175 | return ret; | 1253 | break; |
1176 | } | 1254 | } |
1177 | 1255 | ||
1178 | return 0; | 1256 | end: |
1257 | free(args); | ||
1258 | return ret; | ||
1179 | } | 1259 | } |
1180 | 1260 | ||
1181 | /* Find probe_trace_events specified by perf_probe_event from debuginfo */ | 1261 | /* Find probe_trace_events specified by perf_probe_event from debuginfo */ |
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index 3f0c29dd6ac5..d6dab0e0a937 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
@@ -7,6 +7,7 @@ | |||
7 | 7 | ||
8 | #define MAX_PROBE_BUFFER 1024 | 8 | #define MAX_PROBE_BUFFER 1024 |
9 | #define MAX_PROBES 128 | 9 | #define MAX_PROBES 128 |
10 | #define MAX_PROBE_ARGS 128 | ||
10 | 11 | ||
11 | static inline int is_c_varname(const char *name) | 12 | static inline int is_c_varname(const char *name) |
12 | { | 13 | { |