diff options
author | Ingo Molnar <mingo@elte.hu> | 2011-08-14 05:48:29 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-08-14 05:48:29 -0400 |
commit | bdc2209fd246820de2816691ac0e82600885e1a8 (patch) | |
tree | 34dca4b8f1a94d1a4b6a79cff6931e8284e27718 /tools | |
parent | eeca7360f756f7e36e846f35018df20808c7ef63 (diff) | |
parent | 3f4460a28fb2f73df6c32c3a305797abc01c0f9c (diff) |
Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-probe.c | 14 | ||||
-rw-r--r-- | tools/perf/util/dwarf-aux.c | 210 | ||||
-rw-r--r-- | tools/perf/util/dwarf-aux.h | 11 | ||||
-rw-r--r-- | tools/perf/util/header.c | 11 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 231 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.h | 2 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 59 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 1 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/top.c | 1 |
9 files changed, 403 insertions, 137 deletions
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 5f2a5c7046df..710ae3d0a489 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -134,10 +134,18 @@ static int opt_show_lines(const struct option *opt __used, | |||
134 | { | 134 | { |
135 | int ret = 0; | 135 | int ret = 0; |
136 | 136 | ||
137 | if (str) | 137 | if (!str) |
138 | ret = parse_line_range_desc(str, ¶ms.line_range); | 138 | return 0; |
139 | INIT_LIST_HEAD(¶ms.line_range.line_list); | 139 | |
140 | if (params.show_lines) { | ||
141 | pr_warning("Warning: more than one --line options are" | ||
142 | " detected. Only the first one is valid.\n"); | ||
143 | return 0; | ||
144 | } | ||
145 | |||
140 | params.show_lines = true; | 146 | params.show_lines = true; |
147 | ret = parse_line_range_desc(str, ¶ms.line_range); | ||
148 | INIT_LIST_HEAD(¶ms.line_range.line_list); | ||
141 | 149 | ||
142 | return ret; | 150 | return ret; |
143 | } | 151 | } |
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index fddf40f30d3e..ee51e9b4dc09 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c | |||
@@ -96,6 +96,39 @@ int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr, | |||
96 | return *lineno ?: -ENOENT; | 96 | return *lineno ?: -ENOENT; |
97 | } | 97 | } |
98 | 98 | ||
99 | static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data); | ||
100 | |||
101 | /** | ||
102 | * cu_walk_functions_at - Walk on function DIEs at given address | ||
103 | * @cu_die: A CU DIE | ||
104 | * @addr: An address | ||
105 | * @callback: A callback which called with found DIEs | ||
106 | * @data: A user data | ||
107 | * | ||
108 | * Walk on function DIEs at given @addr in @cu_die. Passed DIEs | ||
109 | * should be subprogram or inlined-subroutines. | ||
110 | */ | ||
111 | int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, | ||
112 | int (*callback)(Dwarf_Die *, void *), void *data) | ||
113 | { | ||
114 | Dwarf_Die die_mem; | ||
115 | Dwarf_Die *sc_die; | ||
116 | int ret = -ENOENT; | ||
117 | |||
118 | /* Inlined function could be recursive. Trace it until fail */ | ||
119 | for (sc_die = die_find_realfunc(cu_die, addr, &die_mem); | ||
120 | sc_die != NULL; | ||
121 | sc_die = die_find_child(sc_die, __die_find_inline_cb, &addr, | ||
122 | &die_mem)) { | ||
123 | ret = callback(sc_die, data); | ||
124 | if (ret) | ||
125 | break; | ||
126 | } | ||
127 | |||
128 | return ret; | ||
129 | |||
130 | } | ||
131 | |||
99 | /** | 132 | /** |
100 | * die_compare_name - Compare diename and tname | 133 | * die_compare_name - Compare diename and tname |
101 | * @dw_die: a DIE | 134 | * @dw_die: a DIE |
@@ -198,6 +231,19 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name, | |||
198 | return 0; | 231 | return 0; |
199 | } | 232 | } |
200 | 233 | ||
234 | /* Get attribute and translate it as a sdata */ | ||
235 | static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name, | ||
236 | Dwarf_Sword *result) | ||
237 | { | ||
238 | Dwarf_Attribute attr; | ||
239 | |||
240 | if (dwarf_attr(tp_die, attr_name, &attr) == NULL || | ||
241 | dwarf_formsdata(&attr, result) != 0) | ||
242 | return -ENOENT; | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
201 | /** | 247 | /** |
202 | * die_is_signed_type - Check whether a type DIE is signed or not | 248 | * die_is_signed_type - Check whether a type DIE is signed or not |
203 | * @tp_die: a DIE of a type | 249 | * @tp_die: a DIE of a type |
@@ -250,6 +296,50 @@ int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs) | |||
250 | return 0; | 296 | return 0; |
251 | } | 297 | } |
252 | 298 | ||
299 | /* Get the call file index number in CU DIE */ | ||
300 | static int die_get_call_fileno(Dwarf_Die *in_die) | ||
301 | { | ||
302 | Dwarf_Sword idx; | ||
303 | |||
304 | if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0) | ||
305 | return (int)idx; | ||
306 | else | ||
307 | return -ENOENT; | ||
308 | } | ||
309 | |||
310 | /* Get the declared file index number in CU DIE */ | ||
311 | static int die_get_decl_fileno(Dwarf_Die *pdie) | ||
312 | { | ||
313 | Dwarf_Sword idx; | ||
314 | |||
315 | if (die_get_attr_sdata(pdie, DW_AT_decl_file, &idx) == 0) | ||
316 | return (int)idx; | ||
317 | else | ||
318 | return -ENOENT; | ||
319 | } | ||
320 | |||
321 | /** | ||
322 | * die_get_call_file - Get callsite file name of inlined function instance | ||
323 | * @in_die: a DIE of an inlined function instance | ||
324 | * | ||
325 | * Get call-site file name of @in_die. This means from which file the inline | ||
326 | * function is called. | ||
327 | */ | ||
328 | const char *die_get_call_file(Dwarf_Die *in_die) | ||
329 | { | ||
330 | Dwarf_Die cu_die; | ||
331 | Dwarf_Files *files; | ||
332 | int idx; | ||
333 | |||
334 | idx = die_get_call_fileno(in_die); | ||
335 | if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) || | ||
336 | dwarf_getsrcfiles(&cu_die, &files, NULL) != 0) | ||
337 | return NULL; | ||
338 | |||
339 | return dwarf_filesrc(files, idx, NULL, NULL); | ||
340 | } | ||
341 | |||
342 | |||
253 | /** | 343 | /** |
254 | * die_find_child - Generic DIE search function in DIE tree | 344 | * die_find_child - Generic DIE search function in DIE tree |
255 | * @rt_die: a root DIE | 345 | * @rt_die: a root DIE |
@@ -374,9 +464,78 @@ Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | |||
374 | return die_mem; | 464 | return die_mem; |
375 | } | 465 | } |
376 | 466 | ||
467 | struct __instance_walk_param { | ||
468 | void *addr; | ||
469 | int (*callback)(Dwarf_Die *, void *); | ||
470 | void *data; | ||
471 | int retval; | ||
472 | }; | ||
473 | |||
474 | static int __die_walk_instances_cb(Dwarf_Die *inst, void *data) | ||
475 | { | ||
476 | struct __instance_walk_param *iwp = data; | ||
477 | Dwarf_Attribute attr_mem; | ||
478 | Dwarf_Die origin_mem; | ||
479 | Dwarf_Attribute *attr; | ||
480 | Dwarf_Die *origin; | ||
481 | int tmp; | ||
482 | |||
483 | attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem); | ||
484 | if (attr == NULL) | ||
485 | return DIE_FIND_CB_CONTINUE; | ||
486 | |||
487 | origin = dwarf_formref_die(attr, &origin_mem); | ||
488 | if (origin == NULL || origin->addr != iwp->addr) | ||
489 | return DIE_FIND_CB_CONTINUE; | ||
490 | |||
491 | /* Ignore redundant instances */ | ||
492 | if (dwarf_tag(inst) == DW_TAG_inlined_subroutine) { | ||
493 | dwarf_decl_line(origin, &tmp); | ||
494 | if (die_get_call_lineno(inst) == tmp) { | ||
495 | tmp = die_get_decl_fileno(origin); | ||
496 | if (die_get_call_fileno(inst) == tmp) | ||
497 | return DIE_FIND_CB_CONTINUE; | ||
498 | } | ||
499 | } | ||
500 | |||
501 | iwp->retval = iwp->callback(inst, iwp->data); | ||
502 | |||
503 | return (iwp->retval) ? DIE_FIND_CB_END : DIE_FIND_CB_CONTINUE; | ||
504 | } | ||
505 | |||
506 | /** | ||
507 | * die_walk_instances - Walk on instances of given DIE | ||
508 | * @or_die: an abstract original DIE | ||
509 | * @callback: a callback function which is called with instance DIE | ||
510 | * @data: user data | ||
511 | * | ||
512 | * Walk on the instances of give @in_die. @in_die must be an inlined function | ||
513 | * declartion. This returns the return value of @callback if it returns | ||
514 | * non-zero value, or -ENOENT if there is no instance. | ||
515 | */ | ||
516 | int die_walk_instances(Dwarf_Die *or_die, int (*callback)(Dwarf_Die *, void *), | ||
517 | void *data) | ||
518 | { | ||
519 | Dwarf_Die cu_die; | ||
520 | Dwarf_Die die_mem; | ||
521 | struct __instance_walk_param iwp = { | ||
522 | .addr = or_die->addr, | ||
523 | .callback = callback, | ||
524 | .data = data, | ||
525 | .retval = -ENOENT, | ||
526 | }; | ||
527 | |||
528 | if (dwarf_diecu(or_die, &cu_die, NULL, NULL) == NULL) | ||
529 | return -ENOENT; | ||
530 | |||
531 | die_find_child(&cu_die, __die_walk_instances_cb, &iwp, &die_mem); | ||
532 | |||
533 | return iwp.retval; | ||
534 | } | ||
535 | |||
377 | /* Line walker internal parameters */ | 536 | /* Line walker internal parameters */ |
378 | struct __line_walk_param { | 537 | struct __line_walk_param { |
379 | const char *fname; | 538 | bool recursive; |
380 | line_walk_callback_t callback; | 539 | line_walk_callback_t callback; |
381 | void *data; | 540 | void *data; |
382 | int retval; | 541 | int retval; |
@@ -385,39 +544,56 @@ struct __line_walk_param { | |||
385 | static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) | 544 | static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) |
386 | { | 545 | { |
387 | struct __line_walk_param *lw = data; | 546 | struct __line_walk_param *lw = data; |
388 | Dwarf_Addr addr; | 547 | Dwarf_Addr addr = 0; |
548 | const char *fname; | ||
389 | int lineno; | 549 | int lineno; |
390 | 550 | ||
391 | if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { | 551 | if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { |
552 | fname = die_get_call_file(in_die); | ||
392 | lineno = die_get_call_lineno(in_die); | 553 | lineno = die_get_call_lineno(in_die); |
393 | if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { | 554 | if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { |
394 | lw->retval = lw->callback(lw->fname, lineno, addr, | 555 | lw->retval = lw->callback(fname, lineno, addr, lw->data); |
395 | lw->data); | ||
396 | if (lw->retval != 0) | 556 | if (lw->retval != 0) |
397 | return DIE_FIND_CB_END; | 557 | return DIE_FIND_CB_END; |
398 | } | 558 | } |
399 | } | 559 | } |
400 | return DIE_FIND_CB_SIBLING; | 560 | if (!lw->recursive) |
561 | /* Don't need to search recursively */ | ||
562 | return DIE_FIND_CB_SIBLING; | ||
563 | |||
564 | if (addr) { | ||
565 | fname = dwarf_decl_file(in_die); | ||
566 | if (fname && dwarf_decl_line(in_die, &lineno) == 0) { | ||
567 | lw->retval = lw->callback(fname, lineno, addr, lw->data); | ||
568 | if (lw->retval != 0) | ||
569 | return DIE_FIND_CB_END; | ||
570 | } | ||
571 | } | ||
572 | |||
573 | /* Continue to search nested inlined function call-sites */ | ||
574 | return DIE_FIND_CB_CONTINUE; | ||
401 | } | 575 | } |
402 | 576 | ||
403 | /* Walk on lines of blocks included in given DIE */ | 577 | /* Walk on lines of blocks included in given DIE */ |
404 | static int __die_walk_funclines(Dwarf_Die *sp_die, | 578 | static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive, |
405 | line_walk_callback_t callback, void *data) | 579 | line_walk_callback_t callback, void *data) |
406 | { | 580 | { |
407 | struct __line_walk_param lw = { | 581 | struct __line_walk_param lw = { |
582 | .recursive = recursive, | ||
408 | .callback = callback, | 583 | .callback = callback, |
409 | .data = data, | 584 | .data = data, |
410 | .retval = 0, | 585 | .retval = 0, |
411 | }; | 586 | }; |
412 | Dwarf_Die die_mem; | 587 | Dwarf_Die die_mem; |
413 | Dwarf_Addr addr; | 588 | Dwarf_Addr addr; |
589 | const char *fname; | ||
414 | int lineno; | 590 | int lineno; |
415 | 591 | ||
416 | /* Handle function declaration line */ | 592 | /* Handle function declaration line */ |
417 | lw.fname = dwarf_decl_file(sp_die); | 593 | fname = dwarf_decl_file(sp_die); |
418 | if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 && | 594 | if (fname && dwarf_decl_line(sp_die, &lineno) == 0 && |
419 | dwarf_entrypc(sp_die, &addr) == 0) { | 595 | dwarf_entrypc(sp_die, &addr) == 0) { |
420 | lw.retval = callback(lw.fname, lineno, addr, data); | 596 | lw.retval = callback(fname, lineno, addr, data); |
421 | if (lw.retval != 0) | 597 | if (lw.retval != 0) |
422 | goto done; | 598 | goto done; |
423 | } | 599 | } |
@@ -430,7 +606,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) | |||
430 | { | 606 | { |
431 | struct __line_walk_param *lw = data; | 607 | struct __line_walk_param *lw = data; |
432 | 608 | ||
433 | lw->retval = __die_walk_funclines(sp_die, lw->callback, lw->data); | 609 | lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data); |
434 | if (lw->retval != 0) | 610 | if (lw->retval != 0) |
435 | return DWARF_CB_ABORT; | 611 | return DWARF_CB_ABORT; |
436 | 612 | ||
@@ -439,7 +615,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) | |||
439 | 615 | ||
440 | /** | 616 | /** |
441 | * die_walk_lines - Walk on lines inside given DIE | 617 | * die_walk_lines - Walk on lines inside given DIE |
442 | * @rt_die: a root DIE (CU or subprogram) | 618 | * @rt_die: a root DIE (CU, subprogram or inlined_subroutine) |
443 | * @callback: callback routine | 619 | * @callback: callback routine |
444 | * @data: user data | 620 | * @data: user data |
445 | * | 621 | * |
@@ -460,12 +636,12 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) | |||
460 | size_t nlines, i; | 636 | size_t nlines, i; |
461 | 637 | ||
462 | /* Get the CU die */ | 638 | /* Get the CU die */ |
463 | if (dwarf_tag(rt_die) == DW_TAG_subprogram) | 639 | if (dwarf_tag(rt_die) != DW_TAG_compile_unit) |
464 | cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL); | 640 | cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL); |
465 | else | 641 | else |
466 | cu_die = rt_die; | 642 | cu_die = rt_die; |
467 | if (!cu_die) { | 643 | if (!cu_die) { |
468 | pr_debug2("Failed to get CU from subprogram\n"); | 644 | pr_debug2("Failed to get CU from given DIE.\n"); |
469 | return -EINVAL; | 645 | return -EINVAL; |
470 | } | 646 | } |
471 | 647 | ||
@@ -509,7 +685,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. | 685 | * subroutines. We have to check functions list or given function. |
510 | */ | 686 | */ |
511 | if (rt_die != cu_die) | 687 | if (rt_die != cu_die) |
512 | ret = __die_walk_funclines(rt_die, callback, data); | 688 | /* |
689 | * Don't need walk functions recursively, because nested | ||
690 | * inlined functions don't have lines of the specified DIE. | ||
691 | */ | ||
692 | ret = __die_walk_funclines(rt_die, false, callback, data); | ||
513 | else { | 693 | else { |
514 | struct __line_walk_param param = { | 694 | struct __line_walk_param param = { |
515 | .callback = callback, | 695 | .callback = callback, |
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index bc3b21167e70..6ce1717784b7 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h | |||
@@ -34,12 +34,19 @@ extern const char *cu_get_comp_dir(Dwarf_Die *cu_die); | |||
34 | extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, | 34 | extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, |
35 | const char **fname, int *lineno); | 35 | const char **fname, int *lineno); |
36 | 36 | ||
37 | /* Walk on funcitons at given address */ | ||
38 | extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, | ||
39 | int (*callback)(Dwarf_Die *, void *), void *data); | ||
40 | |||
37 | /* Compare diename and tname */ | 41 | /* Compare diename and tname */ |
38 | extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); | 42 | extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); |
39 | 43 | ||
40 | /* Get callsite line number of inline-function instance */ | 44 | /* Get callsite line number of inline-function instance */ |
41 | extern int die_get_call_lineno(Dwarf_Die *in_die); | 45 | extern int die_get_call_lineno(Dwarf_Die *in_die); |
42 | 46 | ||
47 | /* Get callsite file name of inlined function instance */ | ||
48 | extern const char *die_get_call_file(Dwarf_Die *in_die); | ||
49 | |||
43 | /* Get type die */ | 50 | /* Get type die */ |
44 | extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); | 51 | extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); |
45 | 52 | ||
@@ -73,6 +80,10 @@ extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, | |||
73 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 80 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
74 | Dwarf_Die *die_mem); | 81 | Dwarf_Die *die_mem); |
75 | 82 | ||
83 | /* Walk on the instances of given DIE */ | ||
84 | extern int die_walk_instances(Dwarf_Die *in_die, | ||
85 | int (*callback)(Dwarf_Die *, void *), void *data); | ||
86 | |||
76 | /* Walker on lines (Note: line number will not be sorted) */ | 87 | /* Walker on lines (Note: line number will not be sorted) */ |
77 | typedef int (* line_walk_callback_t) (const char *fname, int lineno, | 88 | typedef int (* line_walk_callback_t) (const char *fname, int lineno, |
78 | Dwarf_Addr addr, void *data); | 89 | Dwarf_Addr addr, void *data); |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index d4f3101773db..b6c1ad123ca9 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -726,7 +726,16 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header, | |||
726 | return -1; | 726 | return -1; |
727 | 727 | ||
728 | bev.header = old_bev.header; | 728 | bev.header = old_bev.header; |
729 | bev.pid = 0; | 729 | |
730 | /* | ||
731 | * As the pid is the missing value, we need to fill | ||
732 | * it properly. The header.misc value give us nice hint. | ||
733 | */ | ||
734 | bev.pid = HOST_KERNEL_ID; | ||
735 | if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER || | ||
736 | bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL) | ||
737 | bev.pid = DEFAULT_GUEST_KERNEL_ID; | ||
738 | |||
730 | memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); | 739 | memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); |
731 | __event_process_build_id(&bev, filename, session); | 740 | __event_process_build_id(&bev, filename, session); |
732 | 741 | ||
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 3e44a3e36519..555fc3864b90 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -612,12 +612,12 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
612 | return ret; | 612 | return ret; |
613 | } | 613 | } |
614 | 614 | ||
615 | /* Find a variable in a subprogram die */ | 615 | /* Find a variable in a scope DIE */ |
616 | static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | 616 | static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) |
617 | { | 617 | { |
618 | Dwarf_Die vr_die, *scopes; | 618 | Dwarf_Die vr_die; |
619 | char buf[32], *ptr; | 619 | char buf[32], *ptr; |
620 | int ret, nscopes; | 620 | int ret = 0; |
621 | 621 | ||
622 | if (!is_c_varname(pf->pvar->var)) { | 622 | if (!is_c_varname(pf->pvar->var)) { |
623 | /* Copy raw parameters */ | 623 | /* Copy raw parameters */ |
@@ -652,30 +652,16 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
652 | if (pf->tvar->name == NULL) | 652 | if (pf->tvar->name == NULL) |
653 | return -ENOMEM; | 653 | return -ENOMEM; |
654 | 654 | ||
655 | pr_debug("Searching '%s' variable in context.\n", | 655 | pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); |
656 | pf->pvar->var); | ||
657 | /* Search child die for local variables and parameters. */ | 656 | /* Search child die for local variables and parameters. */ |
658 | if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die)) | 657 | if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { |
659 | ret = convert_variable(&vr_die, pf); | 658 | /* Search again in global variables */ |
660 | else { | 659 | if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) |
661 | /* Search upper class */ | 660 | ret = -ENOENT; |
662 | nscopes = dwarf_getscopes_die(sp_die, &scopes); | ||
663 | while (nscopes-- > 1) { | ||
664 | pr_debug("Searching variables in %s\n", | ||
665 | dwarf_diename(&scopes[nscopes])); | ||
666 | /* We should check this scope, so give dummy address */ | ||
667 | if (die_find_variable_at(&scopes[nscopes], | ||
668 | pf->pvar->var, 0, | ||
669 | &vr_die)) { | ||
670 | ret = convert_variable(&vr_die, pf); | ||
671 | goto found; | ||
672 | } | ||
673 | } | ||
674 | if (scopes) | ||
675 | free(scopes); | ||
676 | ret = -ENOENT; | ||
677 | } | 661 | } |
678 | found: | 662 | if (ret == 0) |
663 | ret = convert_variable(&vr_die, pf); | ||
664 | |||
679 | if (ret < 0) | 665 | if (ret < 0) |
680 | pr_warning("Failed to find '%s' in this function.\n", | 666 | pr_warning("Failed to find '%s' in this function.\n", |
681 | pf->pvar->var); | 667 | pf->pvar->var); |
@@ -718,26 +704,30 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, | |||
718 | return 0; | 704 | return 0; |
719 | } | 705 | } |
720 | 706 | ||
721 | /* Call probe_finder callback with real subprogram DIE */ | 707 | /* Call probe_finder callback with scope DIE */ |
722 | static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | 708 | static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) |
723 | { | 709 | { |
724 | Dwarf_Die die_mem; | ||
725 | Dwarf_Attribute fb_attr; | 710 | Dwarf_Attribute fb_attr; |
726 | size_t nops; | 711 | size_t nops; |
727 | int ret; | 712 | int ret; |
728 | 713 | ||
729 | /* If no real subprogram, find a real one */ | 714 | if (!sc_die) { |
730 | if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { | 715 | pr_err("Caller must pass a scope DIE. Program error.\n"); |
731 | sp_die = die_find_realfunc(&pf->cu_die, pf->addr, &die_mem); | 716 | return -EINVAL; |
732 | if (!sp_die) { | 717 | } |
718 | |||
719 | /* If not a real subprogram, find a real one */ | ||
720 | if (dwarf_tag(sc_die) != DW_TAG_subprogram) { | ||
721 | if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { | ||
733 | pr_warning("Failed to find probe point in any " | 722 | pr_warning("Failed to find probe point in any " |
734 | "functions.\n"); | 723 | "functions.\n"); |
735 | return -ENOENT; | 724 | return -ENOENT; |
736 | } | 725 | } |
737 | } | 726 | } else |
727 | memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); | ||
738 | 728 | ||
739 | /* Get the frame base attribute/ops */ | 729 | /* Get the frame base attribute/ops from subprogram */ |
740 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); | 730 | dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); |
741 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); | 731 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); |
742 | if (ret <= 0 || nops == 0) { | 732 | if (ret <= 0 || nops == 0) { |
743 | pf->fb_ops = NULL; | 733 | pf->fb_ops = NULL; |
@@ -755,7 +745,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
755 | } | 745 | } |
756 | 746 | ||
757 | /* Call finder's callback handler */ | 747 | /* Call finder's callback handler */ |
758 | ret = pf->callback(sp_die, pf); | 748 | ret = pf->callback(sc_die, pf); |
759 | 749 | ||
760 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ | 750 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ |
761 | pf->fb_ops = NULL; | 751 | pf->fb_ops = NULL; |
@@ -763,17 +753,82 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
763 | return ret; | 753 | return ret; |
764 | } | 754 | } |
765 | 755 | ||
756 | struct find_scope_param { | ||
757 | const char *function; | ||
758 | const char *file; | ||
759 | int line; | ||
760 | int diff; | ||
761 | Dwarf_Die *die_mem; | ||
762 | bool found; | ||
763 | }; | ||
764 | |||
765 | static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) | ||
766 | { | ||
767 | struct find_scope_param *fsp = data; | ||
768 | const char *file; | ||
769 | int lno; | ||
770 | |||
771 | /* Skip if declared file name does not match */ | ||
772 | if (fsp->file) { | ||
773 | file = dwarf_decl_file(fn_die); | ||
774 | if (!file || strcmp(fsp->file, file) != 0) | ||
775 | return 0; | ||
776 | } | ||
777 | /* If the function name is given, that's what user expects */ | ||
778 | if (fsp->function) { | ||
779 | if (die_compare_name(fn_die, fsp->function)) { | ||
780 | memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); | ||
781 | fsp->found = true; | ||
782 | return 1; | ||
783 | } | ||
784 | } else { | ||
785 | /* With the line number, find the nearest declared DIE */ | ||
786 | dwarf_decl_line(fn_die, &lno); | ||
787 | if (lno < fsp->line && fsp->diff > fsp->line - lno) { | ||
788 | /* Keep a candidate and continue */ | ||
789 | fsp->diff = fsp->line - lno; | ||
790 | memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); | ||
791 | fsp->found = true; | ||
792 | } | ||
793 | } | ||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | /* Find an appropriate scope fits to given conditions */ | ||
798 | static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) | ||
799 | { | ||
800 | struct find_scope_param fsp = { | ||
801 | .function = pf->pev->point.function, | ||
802 | .file = pf->fname, | ||
803 | .line = pf->lno, | ||
804 | .diff = INT_MAX, | ||
805 | .die_mem = die_mem, | ||
806 | .found = false, | ||
807 | }; | ||
808 | |||
809 | cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); | ||
810 | |||
811 | return fsp.found ? die_mem : NULL; | ||
812 | } | ||
813 | |||
766 | static int probe_point_line_walker(const char *fname, int lineno, | 814 | static int probe_point_line_walker(const char *fname, int lineno, |
767 | Dwarf_Addr addr, void *data) | 815 | Dwarf_Addr addr, void *data) |
768 | { | 816 | { |
769 | struct probe_finder *pf = data; | 817 | struct probe_finder *pf = data; |
818 | Dwarf_Die *sc_die, die_mem; | ||
770 | int ret; | 819 | int ret; |
771 | 820 | ||
772 | if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) | 821 | if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) |
773 | return 0; | 822 | return 0; |
774 | 823 | ||
775 | pf->addr = addr; | 824 | pf->addr = addr; |
776 | ret = call_probe_finder(NULL, pf); | 825 | sc_die = find_best_scope(pf, &die_mem); |
826 | if (!sc_die) { | ||
827 | pr_warning("Failed to find scope of probe point.\n"); | ||
828 | return -ENOENT; | ||
829 | } | ||
830 | |||
831 | ret = call_probe_finder(sc_die, pf); | ||
777 | 832 | ||
778 | /* Continue if no error, because the line will be in inline function */ | 833 | /* Continue if no error, because the line will be in inline function */ |
779 | return ret < 0 ? ret : 0; | 834 | return ret < 0 ? ret : 0; |
@@ -827,6 +882,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno, | |||
827 | Dwarf_Addr addr, void *data) | 882 | Dwarf_Addr addr, void *data) |
828 | { | 883 | { |
829 | struct probe_finder *pf = data; | 884 | struct probe_finder *pf = data; |
885 | Dwarf_Die *sc_die, die_mem; | ||
830 | int ret; | 886 | int ret; |
831 | 887 | ||
832 | if (!line_list__has_line(&pf->lcache, lineno) || | 888 | if (!line_list__has_line(&pf->lcache, lineno) || |
@@ -836,7 +892,14 @@ static int probe_point_lazy_walker(const char *fname, int lineno, | |||
836 | pr_debug("Probe line found: line:%d addr:0x%llx\n", | 892 | pr_debug("Probe line found: line:%d addr:0x%llx\n", |
837 | lineno, (unsigned long long)addr); | 893 | lineno, (unsigned long long)addr); |
838 | pf->addr = addr; | 894 | pf->addr = addr; |
839 | ret = call_probe_finder(NULL, pf); | 895 | pf->lno = lineno; |
896 | sc_die = find_best_scope(pf, &die_mem); | ||
897 | if (!sc_die) { | ||
898 | pr_warning("Failed to find scope of probe point.\n"); | ||
899 | return -ENOENT; | ||
900 | } | ||
901 | |||
902 | ret = call_probe_finder(sc_die, pf); | ||
840 | 903 | ||
841 | /* | 904 | /* |
842 | * Continue if no error, because the lazy pattern will match | 905 | * Continue if no error, because the lazy pattern will match |
@@ -861,42 +924,39 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
861 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); | 924 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); |
862 | } | 925 | } |
863 | 926 | ||
864 | /* Callback parameter with return value */ | ||
865 | struct dwarf_callback_param { | ||
866 | void *data; | ||
867 | int retval; | ||
868 | }; | ||
869 | |||
870 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | 927 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) |
871 | { | 928 | { |
872 | struct dwarf_callback_param *param = data; | 929 | struct probe_finder *pf = data; |
873 | struct probe_finder *pf = param->data; | ||
874 | struct perf_probe_point *pp = &pf->pev->point; | 930 | struct perf_probe_point *pp = &pf->pev->point; |
875 | Dwarf_Addr addr; | 931 | Dwarf_Addr addr; |
932 | int ret; | ||
876 | 933 | ||
877 | if (pp->lazy_line) | 934 | if (pp->lazy_line) |
878 | param->retval = find_probe_point_lazy(in_die, pf); | 935 | ret = find_probe_point_lazy(in_die, pf); |
879 | else { | 936 | else { |
880 | /* Get probe address */ | 937 | /* Get probe address */ |
881 | if (dwarf_entrypc(in_die, &addr) != 0) { | 938 | if (dwarf_entrypc(in_die, &addr) != 0) { |
882 | pr_warning("Failed to get entry address of %s.\n", | 939 | pr_warning("Failed to get entry address of %s.\n", |
883 | dwarf_diename(in_die)); | 940 | dwarf_diename(in_die)); |
884 | param->retval = -ENOENT; | 941 | return -ENOENT; |
885 | return DWARF_CB_ABORT; | ||
886 | } | 942 | } |
887 | pf->addr = addr; | 943 | pf->addr = addr; |
888 | pf->addr += pp->offset; | 944 | pf->addr += pp->offset; |
889 | pr_debug("found inline addr: 0x%jx\n", | 945 | pr_debug("found inline addr: 0x%jx\n", |
890 | (uintmax_t)pf->addr); | 946 | (uintmax_t)pf->addr); |
891 | 947 | ||
892 | param->retval = call_probe_finder(in_die, pf); | 948 | ret = call_probe_finder(in_die, pf); |
893 | if (param->retval < 0) | ||
894 | return DWARF_CB_ABORT; | ||
895 | } | 949 | } |
896 | 950 | ||
897 | return DWARF_CB_OK; | 951 | return ret; |
898 | } | 952 | } |
899 | 953 | ||
954 | /* Callback parameter with return value for libdw */ | ||
955 | struct dwarf_callback_param { | ||
956 | void *data; | ||
957 | int retval; | ||
958 | }; | ||
959 | |||
900 | /* Search function from function name */ | 960 | /* Search function from function name */ |
901 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | 961 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) |
902 | { | 962 | { |
@@ -933,14 +993,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | |||
933 | /* TODO: Check the address in this function */ | 993 | /* TODO: Check the address in this function */ |
934 | param->retval = call_probe_finder(sp_die, pf); | 994 | param->retval = call_probe_finder(sp_die, pf); |
935 | } | 995 | } |
936 | } else { | 996 | } else |
937 | struct dwarf_callback_param _param = {.data = (void *)pf, | ||
938 | .retval = 0}; | ||
939 | /* Inlined function: search instances */ | 997 | /* Inlined function: search instances */ |
940 | dwarf_func_inline_instances(sp_die, probe_point_inline_cb, | 998 | param->retval = die_walk_instances(sp_die, |
941 | &_param); | 999 | probe_point_inline_cb, (void *)pf); |
942 | param->retval = _param.retval; | ||
943 | } | ||
944 | 1000 | ||
945 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ | 1001 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ |
946 | } | 1002 | } |
@@ -1060,7 +1116,7 @@ found: | |||
1060 | } | 1116 | } |
1061 | 1117 | ||
1062 | /* Add a found probe point into trace event list */ | 1118 | /* Add a found probe point into trace event list */ |
1063 | static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | 1119 | static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) |
1064 | { | 1120 | { |
1065 | struct trace_event_finder *tf = | 1121 | struct trace_event_finder *tf = |
1066 | container_of(pf, struct trace_event_finder, pf); | 1122 | container_of(pf, struct trace_event_finder, pf); |
@@ -1075,8 +1131,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1075 | } | 1131 | } |
1076 | tev = &tf->tevs[tf->ntevs++]; | 1132 | tev = &tf->tevs[tf->ntevs++]; |
1077 | 1133 | ||
1078 | ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, | 1134 | /* Trace point should be converted from subprogram DIE */ |
1079 | &tev->point); | 1135 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, |
1136 | pf->pev->point.retprobe, &tev->point); | ||
1080 | if (ret < 0) | 1137 | if (ret < 0) |
1081 | return ret; | 1138 | return ret; |
1082 | 1139 | ||
@@ -1091,7 +1148,8 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1091 | for (i = 0; i < pf->pev->nargs; i++) { | 1148 | for (i = 0; i < pf->pev->nargs; i++) { |
1092 | pf->pvar = &pf->pev->args[i]; | 1149 | pf->pvar = &pf->pev->args[i]; |
1093 | pf->tvar = &tev->args[i]; | 1150 | pf->tvar = &tev->args[i]; |
1094 | ret = find_variable(sp_die, pf); | 1151 | /* Variable should be found from scope DIE */ |
1152 | ret = find_variable(sc_die, pf); | ||
1095 | if (ret != 0) | 1153 | if (ret != 0) |
1096 | return ret; | 1154 | return ret; |
1097 | } | 1155 | } |
@@ -1159,13 +1217,13 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) | |||
1159 | } | 1217 | } |
1160 | 1218 | ||
1161 | /* Add a found vars into available variables list */ | 1219 | /* Add a found vars into available variables list */ |
1162 | static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | 1220 | static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) |
1163 | { | 1221 | { |
1164 | struct available_var_finder *af = | 1222 | struct available_var_finder *af = |
1165 | container_of(pf, struct available_var_finder, pf); | 1223 | container_of(pf, struct available_var_finder, pf); |
1166 | struct variable_list *vl; | 1224 | struct variable_list *vl; |
1167 | Dwarf_Die die_mem, *scopes = NULL; | 1225 | Dwarf_Die die_mem; |
1168 | int ret, nscopes; | 1226 | int ret; |
1169 | 1227 | ||
1170 | /* Check number of tevs */ | 1228 | /* Check number of tevs */ |
1171 | if (af->nvls == af->max_vls) { | 1229 | if (af->nvls == af->max_vls) { |
@@ -1174,8 +1232,9 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1174 | } | 1232 | } |
1175 | vl = &af->vls[af->nvls++]; | 1233 | vl = &af->vls[af->nvls++]; |
1176 | 1234 | ||
1177 | ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, | 1235 | /* Trace point should be converted from subprogram DIE */ |
1178 | &vl->point); | 1236 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, |
1237 | pf->pev->point.retprobe, &vl->point); | ||
1179 | if (ret < 0) | 1238 | if (ret < 0) |
1180 | return ret; | 1239 | return ret; |
1181 | 1240 | ||
@@ -1187,19 +1246,14 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1187 | if (vl->vars == NULL) | 1246 | if (vl->vars == NULL) |
1188 | return -ENOMEM; | 1247 | return -ENOMEM; |
1189 | af->child = true; | 1248 | af->child = true; |
1190 | die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem); | 1249 | die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); |
1191 | 1250 | ||
1192 | /* Find external variables */ | 1251 | /* Find external variables */ |
1193 | if (!af->externs) | 1252 | if (!af->externs) |
1194 | goto out; | 1253 | goto out; |
1195 | /* Don't need to search child DIE for externs. */ | 1254 | /* Don't need to search child DIE for externs. */ |
1196 | af->child = false; | 1255 | af->child = false; |
1197 | nscopes = dwarf_getscopes_die(sp_die, &scopes); | 1256 | die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); |
1198 | while (nscopes-- > 1) | ||
1199 | die_find_child(&scopes[nscopes], collect_variables_cb, | ||
1200 | (void *)af, &die_mem); | ||
1201 | if (scopes) | ||
1202 | free(scopes); | ||
1203 | 1257 | ||
1204 | out: | 1258 | out: |
1205 | if (strlist__empty(vl->vars)) { | 1259 | if (strlist__empty(vl->vars)) { |
@@ -1391,10 +1445,14 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | |||
1391 | 1445 | ||
1392 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) | 1446 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) |
1393 | { | 1447 | { |
1394 | struct dwarf_callback_param *param = data; | 1448 | find_line_range_by_line(in_die, data); |
1395 | 1449 | ||
1396 | param->retval = find_line_range_by_line(in_die, param->data); | 1450 | /* |
1397 | return DWARF_CB_ABORT; /* No need to find other instances */ | 1451 | * We have to check all instances of inlined function, because |
1452 | * some execution paths can be optimized out depends on the | ||
1453 | * function argument of instances | ||
1454 | */ | ||
1455 | return 0; | ||
1398 | } | 1456 | } |
1399 | 1457 | ||
1400 | /* Search function from function name */ | 1458 | /* Search function from function name */ |
@@ -1422,15 +1480,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
1422 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); | 1480 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); |
1423 | lr->start = lf->lno_s; | 1481 | lr->start = lf->lno_s; |
1424 | lr->end = lf->lno_e; | 1482 | lr->end = lf->lno_e; |
1425 | if (dwarf_func_inline(sp_die)) { | 1483 | if (dwarf_func_inline(sp_die)) |
1426 | struct dwarf_callback_param _param; | 1484 | param->retval = die_walk_instances(sp_die, |
1427 | _param.data = (void *)lf; | 1485 | line_range_inline_cb, lf); |
1428 | _param.retval = 0; | 1486 | else |
1429 | dwarf_func_inline_instances(sp_die, | ||
1430 | line_range_inline_cb, | ||
1431 | &_param); | ||
1432 | param->retval = _param.retval; | ||
1433 | } else | ||
1434 | param->retval = find_line_range_by_line(sp_die, lf); | 1487 | param->retval = find_line_range_by_line(sp_die, lf); |
1435 | return DWARF_CB_ABORT; | 1488 | return DWARF_CB_ABORT; |
1436 | } | 1489 | } |
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index c478b42a2473..1132c8f0ce89 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
@@ -57,7 +57,7 @@ struct probe_finder { | |||
57 | struct perf_probe_event *pev; /* Target probe event */ | 57 | struct perf_probe_event *pev; /* Target probe event */ |
58 | 58 | ||
59 | /* Callback when a probe point is found */ | 59 | /* Callback when a probe point is found */ |
60 | int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf); | 60 | int (*callback)(Dwarf_Die *sc_die, struct probe_finder *pf); |
61 | 61 | ||
62 | /* For function searching */ | 62 | /* For function searching */ |
63 | int lno; /* Line number */ | 63 | int lno; /* Line number */ |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index a8b53714542a..469c0264ed29 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -1506,7 +1506,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1506 | if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { | 1506 | if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { |
1507 | struct stat st; | 1507 | struct stat st; |
1508 | 1508 | ||
1509 | if (stat(dso->name, &st) < 0) | 1509 | if (lstat(dso->name, &st) < 0) |
1510 | return -1; | 1510 | return -1; |
1511 | 1511 | ||
1512 | if (st.st_uid && (st.st_uid != geteuid())) { | 1512 | if (st.st_uid && (st.st_uid != geteuid())) { |
@@ -2181,27 +2181,22 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *machines, | |||
2181 | return ret; | 2181 | return ret; |
2182 | } | 2182 | } |
2183 | 2183 | ||
2184 | struct dso *dso__new_kernel(const char *name) | 2184 | static struct dso* |
2185 | dso__kernel_findnew(struct machine *machine, const char *name, | ||
2186 | const char *short_name, int dso_type) | ||
2185 | { | 2187 | { |
2186 | struct dso *dso = dso__new(name ?: "[kernel.kallsyms]"); | 2188 | /* |
2187 | 2189 | * The kernel dso could be created by build_id processing. | |
2188 | if (dso != NULL) { | 2190 | */ |
2189 | dso__set_short_name(dso, "[kernel]"); | 2191 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name); |
2190 | dso->kernel = DSO_TYPE_KERNEL; | ||
2191 | } | ||
2192 | |||
2193 | return dso; | ||
2194 | } | ||
2195 | 2192 | ||
2196 | static struct dso *dso__new_guest_kernel(struct machine *machine, | 2193 | /* |
2197 | const char *name) | 2194 | * We need to run this in all cases, since during the build_id |
2198 | { | 2195 | * processing we had no idea this was the kernel dso. |
2199 | char bf[PATH_MAX]; | 2196 | */ |
2200 | struct dso *dso = dso__new(name ?: machine__mmap_name(machine, bf, | ||
2201 | sizeof(bf))); | ||
2202 | if (dso != NULL) { | 2197 | if (dso != NULL) { |
2203 | dso__set_short_name(dso, "[guest.kernel]"); | 2198 | dso__set_short_name(dso, short_name); |
2204 | dso->kernel = DSO_TYPE_GUEST_KERNEL; | 2199 | dso->kernel = dso_type; |
2205 | } | 2200 | } |
2206 | 2201 | ||
2207 | return dso; | 2202 | return dso; |
@@ -2219,24 +2214,36 @@ void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) | |||
2219 | dso->has_build_id = true; | 2214 | dso->has_build_id = true; |
2220 | } | 2215 | } |
2221 | 2216 | ||
2222 | static struct dso *machine__create_kernel(struct machine *machine) | 2217 | static struct dso *machine__get_kernel(struct machine *machine) |
2223 | { | 2218 | { |
2224 | const char *vmlinux_name = NULL; | 2219 | const char *vmlinux_name = NULL; |
2225 | struct dso *kernel; | 2220 | struct dso *kernel; |
2226 | 2221 | ||
2227 | if (machine__is_host(machine)) { | 2222 | if (machine__is_host(machine)) { |
2228 | vmlinux_name = symbol_conf.vmlinux_name; | 2223 | vmlinux_name = symbol_conf.vmlinux_name; |
2229 | kernel = dso__new_kernel(vmlinux_name); | 2224 | if (!vmlinux_name) |
2225 | vmlinux_name = "[kernel.kallsyms]"; | ||
2226 | |||
2227 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
2228 | "[kernel]", | ||
2229 | DSO_TYPE_KERNEL); | ||
2230 | } else { | 2230 | } else { |
2231 | char bf[PATH_MAX]; | ||
2232 | |||
2231 | if (machine__is_default_guest(machine)) | 2233 | if (machine__is_default_guest(machine)) |
2232 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; | 2234 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; |
2233 | kernel = dso__new_guest_kernel(machine, vmlinux_name); | 2235 | if (!vmlinux_name) |
2236 | vmlinux_name = machine__mmap_name(machine, bf, | ||
2237 | sizeof(bf)); | ||
2238 | |||
2239 | kernel = dso__kernel_findnew(machine, vmlinux_name, | ||
2240 | "[guest.kernel]", | ||
2241 | DSO_TYPE_GUEST_KERNEL); | ||
2234 | } | 2242 | } |
2235 | 2243 | ||
2236 | if (kernel != NULL) { | 2244 | if (kernel != NULL && (!kernel->has_build_id)) |
2237 | dso__read_running_kernel_build_id(kernel, machine); | 2245 | dso__read_running_kernel_build_id(kernel, machine); |
2238 | dsos__add(&machine->kernel_dsos, kernel); | 2246 | |
2239 | } | ||
2240 | return kernel; | 2247 | return kernel; |
2241 | } | 2248 | } |
2242 | 2249 | ||
@@ -2340,7 +2347,7 @@ void machine__destroy_kernel_maps(struct machine *machine) | |||
2340 | 2347 | ||
2341 | int machine__create_kernel_maps(struct machine *machine) | 2348 | int machine__create_kernel_maps(struct machine *machine) |
2342 | { | 2349 | { |
2343 | struct dso *kernel = machine__create_kernel(machine); | 2350 | struct dso *kernel = machine__get_kernel(machine); |
2344 | 2351 | ||
2345 | if (kernel == NULL || | 2352 | if (kernel == NULL || |
2346 | __machine__create_kernel_maps(machine, kernel) < 0) | 2353 | __machine__create_kernel_maps(machine, kernel) < 0) |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 325ee36a9d29..4f377d92e75a 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -155,7 +155,6 @@ struct dso { | |||
155 | }; | 155 | }; |
156 | 156 | ||
157 | struct dso *dso__new(const char *name); | 157 | struct dso *dso__new(const char *name); |
158 | struct dso *dso__new_kernel(const char *name); | ||
159 | void dso__delete(struct dso *dso); | 158 | void dso__delete(struct dso *dso); |
160 | 159 | ||
161 | int dso__name_len(const struct dso *dso); | 160 | int dso__name_len(const struct dso *dso); |
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c index 5a06538532af..88403cf8396a 100644 --- a/tools/perf/util/ui/browsers/top.c +++ b/tools/perf/util/ui/browsers/top.c | |||
@@ -208,6 +208,5 @@ int perf_top__tui_browser(struct perf_top *top) | |||
208 | }, | 208 | }, |
209 | }; | 209 | }; |
210 | 210 | ||
211 | ui_helpline__push("Press <- or ESC to exit"); | ||
212 | return perf_top_browser__run(&browser); | 211 | return perf_top_browser__run(&browser); |
213 | } | 212 | } |