diff options
| -rw-r--r-- | tools/perf/util/dwarf-aux.c | 91 | ||||
| -rw-r--r-- | tools/perf/util/dwarf-aux.h | 3 |
2 files changed, 82 insertions, 12 deletions
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index d35b454f98b8..d9b8ad098498 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c | |||
| @@ -198,6 +198,19 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name, | |||
| 198 | return 0; | 198 | return 0; |
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | /* Get attribute and translate it as a sdata */ | ||
| 202 | static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name, | ||
| 203 | Dwarf_Sword *result) | ||
| 204 | { | ||
| 205 | Dwarf_Attribute attr; | ||
| 206 | |||
| 207 | if (dwarf_attr(tp_die, attr_name, &attr) == NULL || | ||
| 208 | dwarf_formsdata(&attr, result) != 0) | ||
| 209 | return -ENOENT; | ||
| 210 | |||
| 211 | return 0; | ||
| 212 | } | ||
| 213 | |||
| 201 | /** | 214 | /** |
| 202 | * die_is_signed_type - Check whether a type DIE is signed or not | 215 | * die_is_signed_type - Check whether a type DIE is signed or not |
| 203 | * @tp_die: a DIE of a type | 216 | * @tp_die: a DIE of a type |
| @@ -250,6 +263,39 @@ int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs) | |||
| 250 | return 0; | 263 | return 0; |
| 251 | } | 264 | } |
| 252 | 265 | ||
| 266 | /* Get the call file index number in CU DIE */ | ||
| 267 | static int die_get_call_fileno(Dwarf_Die *in_die) | ||
| 268 | { | ||
| 269 | Dwarf_Sword idx; | ||
| 270 | |||
| 271 | if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0) | ||
| 272 | return (int)idx; | ||
| 273 | else | ||
| 274 | return -ENOENT; | ||
| 275 | } | ||
| 276 | |||
| 277 | /** | ||
| 278 | * die_get_call_file - Get callsite file name of inlined function instance | ||
| 279 | * @in_die: a DIE of an inlined function instance | ||
| 280 | * | ||
| 281 | * Get call-site file name of @in_die. This means from which file the inline | ||
| 282 | * function is called. | ||
| 283 | */ | ||
| 284 | const char *die_get_call_file(Dwarf_Die *in_die) | ||
| 285 | { | ||
| 286 | Dwarf_Die cu_die; | ||
| 287 | Dwarf_Files *files; | ||
| 288 | int idx; | ||
| 289 | |||
| 290 | idx = die_get_call_fileno(in_die); | ||
| 291 | if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) || | ||
| 292 | dwarf_getsrcfiles(&cu_die, &files, NULL) != 0) | ||
| 293 | return NULL; | ||
| 294 | |||
| 295 | return dwarf_filesrc(files, idx, NULL, NULL); | ||
| 296 | } | ||
| 297 | |||
| 298 | |||
| 253 | /** | 299 | /** |
| 254 | * die_find_child - Generic DIE search function in DIE tree | 300 | * die_find_child - Generic DIE search function in DIE tree |
| 255 | * @rt_die: a root DIE | 301 | * @rt_die: a root DIE |
| @@ -376,7 +422,7 @@ Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | |||
| 376 | 422 | ||
| 377 | /* Line walker internal parameters */ | 423 | /* Line walker internal parameters */ |
| 378 | struct __line_walk_param { | 424 | struct __line_walk_param { |
| 379 | const char *fname; | 425 | bool recursive; |
| 380 | line_walk_callback_t callback; | 426 | line_walk_callback_t callback; |
| 381 | void *data; | 427 | void *data; |
| 382 | int retval; | 428 | int retval; |
| @@ -385,39 +431,56 @@ struct __line_walk_param { | |||
| 385 | static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) | 431 | static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) |
| 386 | { | 432 | { |
| 387 | struct __line_walk_param *lw = data; | 433 | struct __line_walk_param *lw = data; |
| 388 | Dwarf_Addr addr; | 434 | Dwarf_Addr addr = 0; |
| 435 | const char *fname; | ||
| 389 | int lineno; | 436 | int lineno; |
| 390 | 437 | ||
| 391 | if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { | 438 | if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { |
| 439 | fname = die_get_call_file(in_die); | ||
| 392 | lineno = die_get_call_lineno(in_die); | 440 | lineno = die_get_call_lineno(in_die); |
| 393 | if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { | 441 | if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { |
| 394 | lw->retval = lw->callback(lw->fname, lineno, addr, | 442 | lw->retval = lw->callback(fname, lineno, addr, lw->data); |
| 395 | lw->data); | ||
| 396 | if (lw->retval != 0) | 443 | if (lw->retval != 0) |
| 397 | return DIE_FIND_CB_END; | 444 | return DIE_FIND_CB_END; |
| 398 | } | 445 | } |
| 399 | } | 446 | } |
| 400 | return DIE_FIND_CB_SIBLING; | 447 | if (!lw->recursive) |
| 448 | /* Don't need to search recursively */ | ||
| 449 | return DIE_FIND_CB_SIBLING; | ||
| 450 | |||
| 451 | if (addr) { | ||
| 452 | fname = dwarf_decl_file(in_die); | ||
| 453 | if (fname && dwarf_decl_line(in_die, &lineno) == 0) { | ||
| 454 | lw->retval = lw->callback(fname, lineno, addr, lw->data); | ||
| 455 | if (lw->retval != 0) | ||
| 456 | return DIE_FIND_CB_END; | ||
| 457 | } | ||
| 458 | } | ||
| 459 | |||
| 460 | /* Continue to search nested inlined function call-sites */ | ||
| 461 | return DIE_FIND_CB_CONTINUE; | ||
| 401 | } | 462 | } |
| 402 | 463 | ||
| 403 | /* Walk on lines of blocks included in given DIE */ | 464 | /* Walk on lines of blocks included in given DIE */ |
| 404 | static int __die_walk_funclines(Dwarf_Die *sp_die, | 465 | static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive, |
| 405 | line_walk_callback_t callback, void *data) | 466 | line_walk_callback_t callback, void *data) |
| 406 | { | 467 | { |
| 407 | struct __line_walk_param lw = { | 468 | struct __line_walk_param lw = { |
| 469 | .recursive = recursive, | ||
| 408 | .callback = callback, | 470 | .callback = callback, |
| 409 | .data = data, | 471 | .data = data, |
| 410 | .retval = 0, | 472 | .retval = 0, |
| 411 | }; | 473 | }; |
| 412 | Dwarf_Die die_mem; | 474 | Dwarf_Die die_mem; |
| 413 | Dwarf_Addr addr; | 475 | Dwarf_Addr addr; |
| 476 | const char *fname; | ||
| 414 | int lineno; | 477 | int lineno; |
| 415 | 478 | ||
| 416 | /* Handle function declaration line */ | 479 | /* Handle function declaration line */ |
| 417 | lw.fname = dwarf_decl_file(sp_die); | 480 | fname = dwarf_decl_file(sp_die); |
| 418 | if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 && | 481 | if (fname && dwarf_decl_line(sp_die, &lineno) == 0 && |
| 419 | dwarf_entrypc(sp_die, &addr) == 0) { | 482 | dwarf_entrypc(sp_die, &addr) == 0) { |
| 420 | lw.retval = callback(lw.fname, lineno, addr, data); | 483 | lw.retval = callback(fname, lineno, addr, data); |
| 421 | if (lw.retval != 0) | 484 | if (lw.retval != 0) |
| 422 | goto done; | 485 | goto done; |
| 423 | } | 486 | } |
| @@ -430,7 +493,7 @@ static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) | |||
| 430 | { | 493 | { |
| 431 | struct __line_walk_param *lw = data; | 494 | struct __line_walk_param *lw = data; |
| 432 | 495 | ||
| 433 | lw->retval = __die_walk_funclines(sp_die, lw->callback, lw->data); | 496 | lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data); |
| 434 | if (lw->retval != 0) | 497 | if (lw->retval != 0) |
| 435 | return DWARF_CB_ABORT; | 498 | return DWARF_CB_ABORT; |
| 436 | 499 | ||
| @@ -509,7 +572,11 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) | |||
| 509 | * subroutines. We have to check functions list or given function. | 572 | * subroutines. We have to check functions list or given function. |
| 510 | */ | 573 | */ |
| 511 | if (rt_die != cu_die) | 574 | if (rt_die != cu_die) |
| 512 | ret = __die_walk_funclines(rt_die, callback, data); | 575 | /* |
| 576 | * Don't need walk functions recursively, because nested | ||
| 577 | * inlined functions don't have lines of the specified DIE. | ||
| 578 | */ | ||
| 579 | ret = __die_walk_funclines(rt_die, false, callback, data); | ||
| 513 | else { | 580 | else { |
| 514 | struct __line_walk_param param = { | 581 | struct __line_walk_param param = { |
| 515 | .callback = callback, | 582 | .callback = callback, |
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index bc3b21167e70..c8e491bc133f 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h | |||
| @@ -40,6 +40,9 @@ extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); | |||
| 40 | /* Get callsite line number of inline-function instance */ | 40 | /* Get callsite line number of inline-function instance */ |
| 41 | extern int die_get_call_lineno(Dwarf_Die *in_die); | 41 | extern int die_get_call_lineno(Dwarf_Die *in_die); |
| 42 | 42 | ||
| 43 | /* Get callsite file name of inlined function instance */ | ||
| 44 | extern const char *die_get_call_file(Dwarf_Die *in_die); | ||
| 45 | |||
| 43 | /* Get type die */ | 46 | /* Get type die */ |
| 44 | extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); | 47 | extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); |
| 45 | 48 | ||
