aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2011-08-11 07:02:41 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-08-12 08:23:39 -0400
commitb0e9cb2802d4bf50955cca8a7d87cf94ebf750a5 (patch)
tree4ad27542e70558f7b3f13b4d56a031d3c53fc452 /tools/perf
parenta128405c6b40371c59c34b00cc66ed06285b9551 (diff)
perf probe: Fix to search nested inlined functions in CU
Fix perf probe to walk through the lines of all nested inlined function call sites and declared lines when a whole CU is passed to the line walker. The die_walk_lines() can have two different type of DIEs, subprogram (or inlined-subroutine) DIE and CU DIE. If a caller passes a subprogram DIE, this means that the walker walk on lines of given subprogram. In this case, it just needs to search on direct children of DIE tree for finding call-site information of inlined function which directly called from given subprogram. On the other hand, if a caller passes a CU DIE to the walker, this means that the walker have to walk on all lines in the source files included in given CU DIE. In this case, it has to search whole DIE trees of all subprograms to find the call-site information of all nested inlined functions. Without this patch: $ perf probe --line kernel/cpu.c:151-157 </home/mhiramat/ksrc/linux-2.6/kernel/cpu.c:151> static int cpu_notify(unsigned long val, void *v) { 154 return __cpu_notify(val, v, -1, NULL); } With this: $ perf probe --line kernel/cpu.c:151-157 </home/mhiramat/ksrc/linux-2.6/kernel/cpu.c:151> 152 static int cpu_notify(unsigned long val, void *v) { 154 return __cpu_notify(val, v, -1, NULL); } As you can see, --line option with source line range shows the declared lines as probe-able. Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Paul Mackerras <paulus@samba.org> Cc: Pekka Enberg <penberg@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: yrl.pp-manager.tt@hitachi.com Link: http://lkml.kernel.org/r/20110811110241.19900.34994.stgit@fedora15 Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/util/dwarf-aux.c91
-rw-r--r--tools/perf/util/dwarf-aux.h3
2 files changed, 82 insertions, 12 deletions
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index d35b454f98b8..d9b8ad098498 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -198,6 +198,19 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
198 return 0; 198 return 0;
199} 199}
200 200
201/* Get attribute and translate it as a sdata */
202static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name,
203 Dwarf_Sword *result)
204{
205 Dwarf_Attribute attr;
206
207 if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
208 dwarf_formsdata(&attr, result) != 0)
209 return -ENOENT;
210
211 return 0;
212}
213
201/** 214/**
202 * die_is_signed_type - Check whether a type DIE is signed or not 215 * die_is_signed_type - Check whether a type DIE is signed or not
203 * @tp_die: a DIE of a type 216 * @tp_die: a DIE of a type
@@ -250,6 +263,39 @@ int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
250 return 0; 263 return 0;
251} 264}
252 265
266/* Get the call file index number in CU DIE */
267static int die_get_call_fileno(Dwarf_Die *in_die)
268{
269 Dwarf_Sword idx;
270
271 if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0)
272 return (int)idx;
273 else
274 return -ENOENT;
275}
276
277/**
278 * die_get_call_file - Get callsite file name of inlined function instance
279 * @in_die: a DIE of an inlined function instance
280 *
281 * Get call-site file name of @in_die. This means from which file the inline
282 * function is called.
283 */
284const char *die_get_call_file(Dwarf_Die *in_die)
285{
286 Dwarf_Die cu_die;
287 Dwarf_Files *files;
288 int idx;
289
290 idx = die_get_call_fileno(in_die);
291 if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) ||
292 dwarf_getsrcfiles(&cu_die, &files, NULL) != 0)
293 return NULL;
294
295 return dwarf_filesrc(files, idx, NULL, NULL);
296}
297
298
253/** 299/**
254 * die_find_child - Generic DIE search function in DIE tree 300 * die_find_child - Generic DIE search function in DIE tree
255 * @rt_die: a root DIE 301 * @rt_die: a root DIE
@@ -376,7 +422,7 @@ Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
376 422
377/* Line walker internal parameters */ 423/* Line walker internal parameters */
378struct __line_walk_param { 424struct __line_walk_param {
379 const char *fname; 425 bool recursive;
380 line_walk_callback_t callback; 426 line_walk_callback_t callback;
381 void *data; 427 void *data;
382 int retval; 428 int retval;
@@ -385,39 +431,56 @@ struct __line_walk_param {
385static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) 431static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
386{ 432{
387 struct __line_walk_param *lw = data; 433 struct __line_walk_param *lw = data;
388 Dwarf_Addr addr; 434 Dwarf_Addr addr = 0;
435 const char *fname;
389 int lineno; 436 int lineno;
390 437
391 if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { 438 if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
439 fname = die_get_call_file(in_die);
392 lineno = die_get_call_lineno(in_die); 440 lineno = die_get_call_lineno(in_die);
393 if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { 441 if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
394 lw->retval = lw->callback(lw->fname, lineno, addr, 442 lw->retval = lw->callback(fname, lineno, addr, lw->data);
395 lw->data);
396 if (lw->retval != 0) 443 if (lw->retval != 0)
397 return DIE_FIND_CB_END; 444 return DIE_FIND_CB_END;
398 } 445 }
399 } 446 }
400 return DIE_FIND_CB_SIBLING; 447 if (!lw->recursive)
448 /* Don't need to search recursively */
449 return DIE_FIND_CB_SIBLING;
450
451 if (addr) {
452 fname = dwarf_decl_file(in_die);
453 if (fname && dwarf_decl_line(in_die, &lineno) == 0) {
454 lw->retval = lw->callback(fname, lineno, addr, lw->data);
455 if (lw->retval != 0)
456 return DIE_FIND_CB_END;
457 }
458 }
459
460 /* Continue to search nested inlined function call-sites */
461 return DIE_FIND_CB_CONTINUE;
401} 462}
402 463
403/* Walk on lines of blocks included in given DIE */ 464/* Walk on lines of blocks included in given DIE */
404static int __die_walk_funclines(Dwarf_Die *sp_die, 465static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive,
405 line_walk_callback_t callback, void *data) 466 line_walk_callback_t callback, void *data)
406{ 467{
407 struct __line_walk_param lw = { 468 struct __line_walk_param lw = {
469 .recursive = recursive,
408 .callback = callback, 470 .callback = callback,
409 .data = data, 471 .data = data,
410 .retval = 0, 472 .retval = 0,
411 }; 473 };
412 Dwarf_Die die_mem; 474 Dwarf_Die die_mem;
413 Dwarf_Addr addr; 475 Dwarf_Addr addr;
476 const char *fname;
414 int lineno; 477 int lineno;
415 478
416 /* Handle function declaration line */ 479 /* Handle function declaration line */
417 lw.fname = dwarf_decl_file(sp_die); 480 fname = dwarf_decl_file(sp_die);
418 if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 && 481 if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
419 dwarf_entrypc(sp_die, &addr) == 0) { 482 dwarf_entrypc(sp_die, &addr) == 0) {
420 lw.retval = callback(lw.fname, lineno, addr, data); 483 lw.retval = callback(fname, lineno, addr, data);
421 if (lw.retval != 0) 484 if (lw.retval != 0)
422 goto done; 485 goto done;
423 } 486 }
@@ -430,7 +493,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
430{ 493{
431 struct __line_walk_param *lw = data; 494 struct __line_walk_param *lw = data;
432 495
433 lw->retval = __die_walk_funclines(sp_die, lw->callback, lw->data); 496 lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data);
434 if (lw->retval != 0) 497 if (lw->retval != 0)
435 return DWARF_CB_ABORT; 498 return DWARF_CB_ABORT;
436 499
@@ -509,7 +572,11 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
509 * subroutines. We have to check functions list or given function. 572 * subroutines. We have to check functions list or given function.
510 */ 573 */
511 if (rt_die != cu_die) 574 if (rt_die != cu_die)
512 ret = __die_walk_funclines(rt_die, callback, data); 575 /*
576 * Don't need walk functions recursively, because nested
577 * inlined functions don't have lines of the specified DIE.
578 */
579 ret = __die_walk_funclines(rt_die, false, callback, data);
513 else { 580 else {
514 struct __line_walk_param param = { 581 struct __line_walk_param param = {
515 .callback = callback, 582 .callback = callback,
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h
index bc3b21167e70..c8e491bc133f 100644
--- a/tools/perf/util/dwarf-aux.h
+++ b/tools/perf/util/dwarf-aux.h
@@ -40,6 +40,9 @@ extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname);
40/* Get callsite line number of inline-function instance */ 40/* Get callsite line number of inline-function instance */
41extern int die_get_call_lineno(Dwarf_Die *in_die); 41extern int die_get_call_lineno(Dwarf_Die *in_die);
42 42
43/* Get callsite file name of inlined function instance */
44extern const char *die_get_call_file(Dwarf_Die *in_die);
45
43/* Get type die */ 46/* Get type die */
44extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); 47extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem);
45 48