Commit dc9a5d2c authored by Masami Hiramatsu (Google)'s avatar Masami Hiramatsu (Google) Committed by Arnaldo Carvalho de Melo
Browse files

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: default avatarMasami Hiramatsu <mhiramat@kernel.org>
Acked-by: default avatarNamhyung 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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent f828929a
Loading
Loading
Loading
Loading
+32 −15
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ int cu_find_lineinfo(Dwarf_Die *cu_die, Dwarf_Addr addr,
	if (die_find_realfunc(cu_die, addr, &die_mem)
	    && die_entrypc(&die_mem, &faddr) == 0 &&
	    faddr == addr) {
		*fname = dwarf_decl_file(&die_mem);
		*fname = die_get_decl_file(&die_mem);
		dwarf_decl_line(&die_mem, lineno);
		goto out;
	}
@@ -486,6 +486,19 @@ static int die_get_decl_fileno(Dwarf_Die *pdie)
		return -ENOENT;
}

/* Return the file name by index */
static const char *die_get_file_name(Dwarf_Die *dw_die, int idx)
{
	Dwarf_Die cu_die;
	Dwarf_Files *files;

	if (idx < 0 || !dwarf_diecu(dw_die, &cu_die, NULL, NULL) ||
	    dwarf_getsrcfiles(&cu_die, &files, NULL) != 0)
		return NULL;

	return dwarf_filesrc(files, idx, NULL, NULL);
}

/**
 * die_get_call_file - Get callsite file name of inlined function instance
 * @in_die: a DIE of an inlined function instance
@@ -495,18 +508,22 @@ static int die_get_decl_fileno(Dwarf_Die *pdie)
 */
const char *die_get_call_file(Dwarf_Die *in_die)
{
	Dwarf_Die cu_die;
	Dwarf_Files *files;
	int idx;

	idx = die_get_call_fileno(in_die);
	if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) ||
	    dwarf_getsrcfiles(&cu_die, &files, NULL) != 0)
		return NULL;

	return dwarf_filesrc(files, idx, NULL, NULL);
	return die_get_file_name(in_die, die_get_call_fileno(in_die));
}

/**
 * die_get_decl_file - Find the declared file name of this DIE
 * @dw_die: a DIE for something declared.
 *
 * Get declared file name of @dw_die.
 * NOTE: Since some version of clang DWARF5 implementation incorrectly uses
 * file index 0 for DW_AT_decl_file, die_get_decl_file() will return NULL for
 * such cases. Use this function instead.
 */
const char *die_get_decl_file(Dwarf_Die *dw_die)
{
	return die_get_file_name(dw_die, die_get_decl_fileno(dw_die));
}

/**
 * die_find_child - Generic DIE search function in DIE tree
@@ -790,7 +807,7 @@ static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
	}

	if (addr) {
		fname = dwarf_decl_file(in_die);
		fname = die_get_decl_file(in_die);
		if (fname && dwarf_decl_line(in_die, &lineno) == 0) {
			lw->retval = lw->callback(fname, lineno, addr, lw->data);
			if (lw->retval != 0)
@@ -818,7 +835,7 @@ static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive,
	int lineno;

	/* Handle function declaration line */
	fname = dwarf_decl_file(sp_die);
	fname = die_get_decl_file(sp_die);
	if (fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
	    die_entrypc(sp_die, &addr) == 0) {
		lw.retval = callback(fname, lineno, addr, data);
@@ -873,7 +890,7 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
	if (dwarf_tag(rt_die) != DW_TAG_compile_unit) {
		cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL);
		dwarf_decl_line(rt_die, &decl);
		decf = dwarf_decl_file(rt_die);
		decf = die_get_decl_file(rt_die);
		if (!decf) {
			pr_debug2("Failed to get the declared file name of %s\n",
				  dwarf_diename(rt_die));
@@ -928,7 +945,7 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)

				dwarf_decl_line(&die_mem, &inl);
				if (inl != decl ||
				    decf != dwarf_decl_file(&die_mem))
				    decf != die_get_decl_file(&die_mem))
					continue;
			}
		}
+3 −0
Original line number Diff line number Diff line
@@ -50,6 +50,9 @@ int die_get_call_lineno(Dwarf_Die *in_die);
/* Get callsite file name of inlined function instance */
const char *die_get_call_file(Dwarf_Die *in_die);

/* Get declared file name of a DIE */
const char *die_get_decl_file(Dwarf_Die *dw_die);

/* Get type die */
Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem);

+7 −7
Original line number Diff line number Diff line
@@ -763,7 +763,7 @@ static int find_best_scope_cb(Dwarf_Die *fn_die, void *data)

	/* Skip if declared file name does not match */
	if (fsp->file) {
		file = dwarf_decl_file(fn_die);
		file = die_get_decl_file(fn_die);
		if (!file || strcmp(fsp->file, file) != 0)
			return 0;
	}
@@ -1071,7 +1071,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
		return DWARF_CB_OK;

	/* Check declared file */
	fname = dwarf_decl_file(sp_die);
	fname = die_get_decl_file(sp_die);
	if (!fname) {
		pr_warning("A function DIE doesn't have decl_line. Maybe broken DWARF?\n");
		return DWARF_CB_OK;
@@ -1151,7 +1151,7 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
				return DWARF_CB_OK;

			if (param->file) {
				fname = dwarf_decl_file(param->sp_die);
				fname = die_get_decl_file(param->sp_die);
				if (!fname || strtailcmp(param->file, fname))
					return DWARF_CB_OK;
			}
@@ -1750,7 +1750,7 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr,
			goto post;
		}

		fname = dwarf_decl_file(&spdie);
		fname = die_get_decl_file(&spdie);
		if (addr == baseaddr) {
			/* Function entry - Relative line number is 0 */
			lineno = baseline;
@@ -1787,7 +1787,7 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr,
			}
		}
		/* Verify the lineno and baseline are in a same file */
		tmp = dwarf_decl_file(&spdie);
		tmp = die_get_decl_file(&spdie);
		if (!tmp || (fname && strcmp(tmp, fname) != 0))
			lineno = 0;
	}
@@ -1902,13 +1902,13 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)

	/* Check declared file */
	if (lr->file) {
		fname = dwarf_decl_file(sp_die);
		fname = die_get_decl_file(sp_die);
		if (!fname || strtailcmp(lr->file, fname))
			return DWARF_CB_OK;
	}

	if (die_match_name(sp_die, lr->function) && die_is_func_def(sp_die)) {
		lf->fname = dwarf_decl_file(sp_die);
		lf->fname = die_get_decl_file(sp_die);
		dwarf_decl_line(sp_die, &lr->offset);
		pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
		lf->lno_s = lr->offset + lr->start;