Commit 3d918a12a1b3088ac16ff37fa52760639d6e2403
Committed by
Arnaldo Carvalho de Melo
1 parent
7969ec7728
Exists in
master
and in
16 other branches
perf probe: Find fentry mcount fuzzed parameter location
At this point, --fentry (mcount function entry) option for gcc fuzzes the debuginfo variable locations by skipping the mcount instruction offset (on x86, this is a 5 byte call instruction). This makes variable searching fail at the entry of functions which are mcount'ed. e.g.) Available variables at vfs_read @<vfs_read+0> (No matched variables) This patch adds additional location search at the function entry point to solve this issue, which tries to find the earliest address for the variable location. Note that this only works with function parameters (formal parameters) because any local variables should not exist on the function entry address (those are not initialized yet). With this patch, perf probe shows correct parameters if possible; # perf probe --vars vfs_read Available variables at vfs_read @<vfs_read+0> char* buf loff_t* pos size_t count struct file* file 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/20131011071025.15557.13275.stgit@udc4-manage.rcp.hitachi.co.jp Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Showing 1 changed file with 31 additions and 8 deletions Side-by-side Diff
tools/perf/util/probe-finder.c
... | ... | @@ -273,12 +273,15 @@ |
273 | 273 | /* |
274 | 274 | * Convert a location into trace_arg. |
275 | 275 | * If tvar == NULL, this just checks variable can be converted. |
276 | + * If fentry == true and vr_die is a parameter, do huristic search | |
277 | + * for the location fuzzed by function entry mcount. | |
276 | 278 | */ |
277 | 279 | static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, |
278 | - Dwarf_Op *fb_ops, | |
280 | + Dwarf_Op *fb_ops, Dwarf_Die *sp_die, | |
279 | 281 | struct probe_trace_arg *tvar) |
280 | 282 | { |
281 | 283 | Dwarf_Attribute attr; |
284 | + Dwarf_Addr tmp = 0; | |
282 | 285 | Dwarf_Op *op; |
283 | 286 | size_t nops; |
284 | 287 | unsigned int regn; |
285 | 288 | |
... | ... | @@ -291,12 +294,29 @@ |
291 | 294 | goto static_var; |
292 | 295 | |
293 | 296 | /* TODO: handle more than 1 exprs */ |
294 | - if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || | |
295 | - dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 || | |
296 | - nops == 0) { | |
297 | - /* TODO: Support const_value */ | |
297 | + if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) | |
298 | + return -EINVAL; /* Broken DIE ? */ | |
299 | + if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0) { | |
300 | + ret = dwarf_entrypc(sp_die, &tmp); | |
301 | + if (ret || addr != tmp || | |
302 | + dwarf_tag(vr_die) != DW_TAG_formal_parameter || | |
303 | + dwarf_highpc(sp_die, &tmp)) | |
304 | + return -ENOENT; | |
305 | + /* | |
306 | + * This is fuzzed by fentry mcount. We try to find the | |
307 | + * parameter location at the earliest address. | |
308 | + */ | |
309 | + for (addr += 1; addr <= tmp; addr++) { | |
310 | + if (dwarf_getlocation_addr(&attr, addr, &op, | |
311 | + &nops, 1) > 0) | |
312 | + goto found; | |
313 | + } | |
298 | 314 | return -ENOENT; |
299 | 315 | } |
316 | +found: | |
317 | + if (nops == 0) | |
318 | + /* TODO: Support const_value */ | |
319 | + return -ENOENT; | |
300 | 320 | |
301 | 321 | if (op->atom == DW_OP_addr) { |
302 | 322 | static_var: |
... | ... | @@ -600,7 +620,7 @@ |
600 | 620 | dwarf_diename(vr_die)); |
601 | 621 | |
602 | 622 | ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, |
603 | - pf->tvar); | |
623 | + &pf->sp_die, pf->tvar); | |
604 | 624 | if (ret == -ENOENT) |
605 | 625 | pr_err("Failed to find the location of %s at this address.\n" |
606 | 626 | " Perhaps, it has been optimized out.\n", pf->pvar->var); |
607 | 627 | |
... | ... | @@ -1148,13 +1168,15 @@ |
1148 | 1168 | static int copy_variables_cb(Dwarf_Die *die_mem, void *data) |
1149 | 1169 | { |
1150 | 1170 | struct local_vars_finder *vf = data; |
1171 | + struct probe_finder *pf = vf->pf; | |
1151 | 1172 | int tag; |
1152 | 1173 | |
1153 | 1174 | tag = dwarf_tag(die_mem); |
1154 | 1175 | if (tag == DW_TAG_formal_parameter || |
1155 | 1176 | tag == DW_TAG_variable) { |
1156 | 1177 | if (convert_variable_location(die_mem, vf->pf->addr, |
1157 | - vf->pf->fb_ops, NULL) == 0) { | |
1178 | + vf->pf->fb_ops, &pf->sp_die, | |
1179 | + NULL) == 0) { | |
1158 | 1180 | vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem); |
1159 | 1181 | if (vf->args[vf->nargs].var == NULL) { |
1160 | 1182 | vf->ret = -ENOMEM; |
... | ... | @@ -1302,7 +1324,8 @@ |
1302 | 1324 | if (tag == DW_TAG_formal_parameter || |
1303 | 1325 | tag == DW_TAG_variable) { |
1304 | 1326 | ret = convert_variable_location(die_mem, af->pf.addr, |
1305 | - af->pf.fb_ops, NULL); | |
1327 | + af->pf.fb_ops, &af->pf.sp_die, | |
1328 | + NULL); | |
1306 | 1329 | if (ret == 0) { |
1307 | 1330 | ret = die_get_varname(die_mem, buf, MAX_VAR_LEN); |
1308 | 1331 | pr_debug2("Add new var: %s\n", buf); |
-
mentioned in commit 0c188a
-
mentioned in commit 0c188a
-
mentioned in commit 0c188a
-
mentioned in commit 0c188a
-
mentioned in commit 0c188a
-
mentioned in commit 0c188a
-
mentioned in commit 0c188a
-
mentioned in commit 0c188a
-
mentioned in commit 0c188a
-
mentioned in commit 0c188a
-
mentioned in commit 0c188a
-
mentioned in commit 0c188a
-
mentioned in commit 0c188a
-
mentioned in commit 0c188a