Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf probe: Fix to get declared file name from clang DWARF5

Fix to get the declared file name even if it uses file index 0
in DWARF5, using custom die_get_decl_file() function.

Actually, the DWARF5 standard says file index 0 of the DW_AT_decl_file
is invalid(1), but there is a discussion and maybe this will be updated
[2].

Anyway, clang generates such DWARF5 file for the linux kernel. Thus it
must be handled.

Without this, 'perf probe' returns an error:

$ ./perf probe -k $BIN_PATH/vmlinux -s $SRC_PATH -L vfs_read:10
Debuginfo analysis failed.
Error: Failed to show lines.

With this, it can handle the case correctly:

$ ./perf probe -k $BIN_PATH/vmlinux -s $SRC_PATH -L vfs_read:10
<vfs_read@$SRC_PATH/fs/read_write.c:10>

11 ret = rw_verify_area(READ, file, pos, count);
12 if (ret)
return ret;

[1] DWARF5 specification 2.14 says "The value 0 indicates that no source file has been specified.")
[2] http://wiki.dwarfstd.org/index.php?title=DWARF5_Line_Table_File_Numbers)

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Steven Rostedt (VMware) <rostedt@goodmis.org>
Link: https://lore.kernel.org/r/166731052936.2100653.13380621874859467731.stgit@devnote3
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Masami Hiramatsu (Google) and committed by
Arnaldo Carvalho de Melo
dc9a5d2c f828929a

+42 -22
+32 -15
tools/perf/util/dwarf-aux.c
··· 123 123 if (die_find_realfunc(cu_die, addr, &die_mem) 124 124 && die_entrypc(&die_mem, &faddr) == 0 && 125 125 faddr == addr) { 126 - *fname = dwarf_decl_file(&die_mem); 126 + *fname = die_get_decl_file(&die_mem); 127 127 dwarf_decl_line(&die_mem, lineno); 128 128 goto out; 129 129 } ··· 486 486 return -ENOENT; 487 487 } 488 488 489 + /* Return the file name by index */ 490 + static const char *die_get_file_name(Dwarf_Die *dw_die, int idx) 491 + { 492 + Dwarf_Die cu_die; 493 + Dwarf_Files *files; 494 + 495 + if (idx < 0 || !dwarf_diecu(dw_die, &cu_die, NULL, NULL) || 496 + dwarf_getsrcfiles(&cu_die, &files, NULL) != 0) 497 + return NULL; 498 + 499 + return dwarf_filesrc(files, idx, NULL, NULL); 500 + } 501 + 489 502 /** 490 503 * die_get_call_file - Get callsite file name of inlined function instance 491 504 * @in_die: a DIE of an inlined function instance ··· 508 495 */ 509 496 const char *die_get_call_file(Dwarf_Die *in_die) 510 497 { 511 - Dwarf_Die cu_die; 512 - Dwarf_Files *files; 513 - int idx; 514 - 515 - idx = die_get_call_fileno(in_die); 516 - if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) || 517 - dwarf_getsrcfiles(&cu_die, &files, NULL) != 0) 518 - return NULL; 519 - 520 - return dwarf_filesrc(files, idx, NULL, NULL); 498 + return die_get_file_name(in_die, die_get_call_fileno(in_die)); 521 499 } 522 500 501 + /** 502 + * die_get_decl_file - Find the declared file name of this DIE 503 + * @dw_die: a DIE for something declared. 504 + * 505 + * Get declared file name of @dw_die. 506 + * NOTE: Since some version of clang DWARF5 implementation incorrectly uses 507 + * file index 0 for DW_AT_decl_file, die_get_decl_file() will return NULL for 508 + * such cases. Use this function instead. 509 + */ 510 + const char *die_get_decl_file(Dwarf_Die *dw_die) 511 + { 512 + return die_get_file_name(dw_die, die_get_decl_fileno(dw_die)); 513 + } 523 514 524 515 /** 525 516 * die_find_child - Generic DIE search function in DIE tree ··· 807 790 } 808 791 809 792 if (addr) { 810 - fname = dwarf_decl_file(in_die); 793 + fname = die_get_decl_file(in_die); 811 794 if (fname && dwarf_decl_line(in_die, &lineno) == 0) { 812 795 lw->retval = lw->callback(fname, lineno, addr, lw->data); 813 796 if (lw->retval != 0) ··· 835 818 int lineno; 836 819 837 820 /* Handle function declaration line */ 838 - fname = dwarf_decl_file(sp_die); 821 + fname = die_get_decl_file(sp_die); 839 822 if (fname && dwarf_decl_line(sp_die, &lineno) == 0 && 840 823 die_entrypc(sp_die, &addr) == 0) { 841 824 lw.retval = callback(fname, lineno, addr, data); ··· 890 873 if (dwarf_tag(rt_die) != DW_TAG_compile_unit) { 891 874 cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL); 892 875 dwarf_decl_line(rt_die, &decl); 893 - decf = dwarf_decl_file(rt_die); 876 + decf = die_get_decl_file(rt_die); 894 877 if (!decf) { 895 878 pr_debug2("Failed to get the declared file name of %s\n", 896 879 dwarf_diename(rt_die)); ··· 945 928 946 929 dwarf_decl_line(&die_mem, &inl); 947 930 if (inl != decl || 948 - decf != dwarf_decl_file(&die_mem)) 931 + decf != die_get_decl_file(&die_mem)) 949 932 continue; 950 933 } 951 934 }
+3
tools/perf/util/dwarf-aux.h
··· 50 50 /* Get callsite file name of inlined function instance */ 51 51 const char *die_get_call_file(Dwarf_Die *in_die); 52 52 53 + /* Get declared file name of a DIE */ 54 + const char *die_get_decl_file(Dwarf_Die *dw_die); 55 + 53 56 /* Get type die */ 54 57 Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); 55 58
+7 -7
tools/perf/util/probe-finder.c
··· 763 763 764 764 /* Skip if declared file name does not match */ 765 765 if (fsp->file) { 766 - file = dwarf_decl_file(fn_die); 766 + file = die_get_decl_file(fn_die); 767 767 if (!file || strcmp(fsp->file, file) != 0) 768 768 return 0; 769 769 } ··· 1071 1071 return DWARF_CB_OK; 1072 1072 1073 1073 /* Check declared file */ 1074 - fname = dwarf_decl_file(sp_die); 1074 + fname = die_get_decl_file(sp_die); 1075 1075 if (!fname) { 1076 1076 pr_warning("A function DIE doesn't have decl_line. Maybe broken DWARF?\n"); 1077 1077 return DWARF_CB_OK; ··· 1151 1151 return DWARF_CB_OK; 1152 1152 1153 1153 if (param->file) { 1154 - fname = dwarf_decl_file(param->sp_die); 1154 + fname = die_get_decl_file(param->sp_die); 1155 1155 if (!fname || strtailcmp(param->file, fname)) 1156 1156 return DWARF_CB_OK; 1157 1157 } ··· 1750 1750 goto post; 1751 1751 } 1752 1752 1753 - fname = dwarf_decl_file(&spdie); 1753 + fname = die_get_decl_file(&spdie); 1754 1754 if (addr == baseaddr) { 1755 1755 /* Function entry - Relative line number is 0 */ 1756 1756 lineno = baseline; ··· 1787 1787 } 1788 1788 } 1789 1789 /* Verify the lineno and baseline are in a same file */ 1790 - tmp = dwarf_decl_file(&spdie); 1790 + tmp = die_get_decl_file(&spdie); 1791 1791 if (!tmp || (fname && strcmp(tmp, fname) != 0)) 1792 1792 lineno = 0; 1793 1793 } ··· 1902 1902 1903 1903 /* Check declared file */ 1904 1904 if (lr->file) { 1905 - fname = dwarf_decl_file(sp_die); 1905 + fname = die_get_decl_file(sp_die); 1906 1906 if (!fname || strtailcmp(lr->file, fname)) 1907 1907 return DWARF_CB_OK; 1908 1908 } 1909 1909 1910 1910 if (die_match_name(sp_die, lr->function) && die_is_func_def(sp_die)) { 1911 - lf->fname = dwarf_decl_file(sp_die); 1911 + lf->fname = die_get_decl_file(sp_die); 1912 1912 dwarf_decl_line(sp_die, &lr->offset); 1913 1913 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 1914 1914 lf->lno_s = lr->offset + lr->start;