Commit 98e4c68d authored by Masami Hiramatsu (Google)'s avatar Masami Hiramatsu (Google) Committed by Arnaldo Carvalho de Melo

perf probe: Fix to avoid crashing if DW_AT_decl_file is NULL

Since clang generates DWARF5 which sets DW_AT_decl_file as 0,
dwarf_decl_file() thinks that is invalid and returns NULL.  In that case
'perf probe' SIGSEGVs because it doesn't expect a NULL decl_file.

This adds a dwarf_decl_file() return value check to avoid such SEGV with
clang generated DWARF5 info.

Without this, 'perf probe' crashes:

  $ perf probe -k $BIN_PATH/vmlinux -s $SRC_PATH -L vfs_read:10
  Segmentation fault
  $

With this, it just warns about it:

  $ perf probe -k $BIN_PATH/vmlinux -s $SRC_PATH -L vfs_read:10
  Debuginfo analysis failed.
    Error: Failed to show lines.
  $
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/166731051077.2100653.15626653369345128302.stgit@devnote3Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 940da138
...@@ -137,7 +137,7 @@ int cu_find_lineinfo(Dwarf_Die *cu_die, Dwarf_Addr addr, ...@@ -137,7 +137,7 @@ int cu_find_lineinfo(Dwarf_Die *cu_die, Dwarf_Addr addr,
} }
out: out:
return *lineno ?: -ENOENT; return (*lineno && *fname) ? *lineno : -ENOENT;
} }
static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data); static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data);
...@@ -874,6 +874,11 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) ...@@ -874,6 +874,11 @@ int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data)
cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL); cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL);
dwarf_decl_line(rt_die, &decl); dwarf_decl_line(rt_die, &decl);
decf = dwarf_decl_file(rt_die); decf = dwarf_decl_file(rt_die);
if (!decf) {
pr_debug2("Failed to get the declared file name of %s\n",
dwarf_diename(rt_die));
return -EINVAL;
}
} else } else
cu_die = rt_die; cu_die = rt_die;
if (!cu_die) { if (!cu_die) {
......
...@@ -1063,6 +1063,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) ...@@ -1063,6 +1063,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
struct dwarf_callback_param *param = data; struct dwarf_callback_param *param = data;
struct probe_finder *pf = param->data; struct probe_finder *pf = param->data;
struct perf_probe_point *pp = &pf->pev->point; struct perf_probe_point *pp = &pf->pev->point;
const char *fname;
/* Check tag and diename */ /* Check tag and diename */
if (!die_is_func_def(sp_die) || if (!die_is_func_def(sp_die) ||
...@@ -1070,12 +1071,17 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) ...@@ -1070,12 +1071,17 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
return DWARF_CB_OK; return DWARF_CB_OK;
/* Check declared file */ /* Check declared file */
if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) fname = dwarf_decl_file(sp_die);
if (!fname) {
pr_warning("A function DIE doesn't have decl_line. Maybe broken DWARF?\n");
return DWARF_CB_OK;
}
if (pp->file && fname && strtailcmp(pp->file, fname))
return DWARF_CB_OK; return DWARF_CB_OK;
pr_debug("Matched function: %s [%lx]\n", dwarf_diename(sp_die), pr_debug("Matched function: %s [%lx]\n", dwarf_diename(sp_die),
(unsigned long)dwarf_dieoffset(sp_die)); (unsigned long)dwarf_dieoffset(sp_die));
pf->fname = dwarf_decl_file(sp_die); pf->fname = fname;
if (pp->line) { /* Function relative line */ if (pp->line) { /* Function relative line */
dwarf_decl_line(sp_die, &pf->lno); dwarf_decl_line(sp_die, &pf->lno);
pf->lno += pp->line; pf->lno += pp->line;
...@@ -1134,6 +1140,7 @@ struct pubname_callback_param { ...@@ -1134,6 +1140,7 @@ struct pubname_callback_param {
static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
{ {
struct pubname_callback_param *param = data; struct pubname_callback_param *param = data;
const char *fname;
if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) { if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) {
if (dwarf_tag(param->sp_die) != DW_TAG_subprogram) if (dwarf_tag(param->sp_die) != DW_TAG_subprogram)
...@@ -1143,9 +1150,11 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) ...@@ -1143,9 +1150,11 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die)) if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die))
return DWARF_CB_OK; return DWARF_CB_OK;
if (param->file && if (param->file) {
strtailcmp(param->file, dwarf_decl_file(param->sp_die))) fname = dwarf_decl_file(param->sp_die);
return DWARF_CB_OK; if (!fname || strtailcmp(param->file, fname))
return DWARF_CB_OK;
}
param->found = 1; param->found = 1;
return DWARF_CB_ABORT; return DWARF_CB_ABORT;
...@@ -1779,7 +1788,7 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr, ...@@ -1779,7 +1788,7 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr,
} }
/* Verify the lineno and baseline are in a same file */ /* Verify the lineno and baseline are in a same file */
tmp = dwarf_decl_file(&spdie); tmp = dwarf_decl_file(&spdie);
if (!tmp || strcmp(tmp, fname) != 0) if (!tmp || (fname && strcmp(tmp, fname) != 0))
lineno = 0; lineno = 0;
} }
...@@ -1889,10 +1898,14 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) ...@@ -1889,10 +1898,14 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
struct dwarf_callback_param *param = data; struct dwarf_callback_param *param = data;
struct line_finder *lf = param->data; struct line_finder *lf = param->data;
struct line_range *lr = lf->lr; struct line_range *lr = lf->lr;
const char *fname;
/* Check declared file */ /* Check declared file */
if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) if (lr->file) {
return DWARF_CB_OK; fname = dwarf_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)) { if (die_match_name(sp_die, lr->function) && die_is_func_def(sp_die)) {
lf->fname = dwarf_decl_file(sp_die); lf->fname = dwarf_decl_file(sp_die);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment