diff options
| -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 | } |
