Skip to content

Commit 556b58c

Browse files
Athira Rajeevnamhyung
authored andcommitted
perf probe: Pick the correct dwarf die while adding probe points
Perf probe on vfs_fstatat fails as below on a powerpc system $ ./perf probe -nf --max-probes=512 -a 'vfs_fstatat $params' Segmentation fault (core dumped) This is observed while running perftool-testsuite_probe testcase. While running with verbose, its observed that segfault happens at: synthesize_probe_trace_arg () synthesize_probe_trace_command () probe_file.add_event () apply_perf_probe_events () __cmd_probe () cmd_probe () run_builtin () handle_internal_command () main () Code in synthesize_probe_trace_arg() access a null value and results in segfault. Data structure which is null: struct probe_trace_arg arg->value We are hitting a case where arg->value is null in probe point: "vfs_fstatat $params". This is happening since 'commit e896474 ("getname_maybe_null() - the third variant of pathname copy-in")' Before the commit, probe point for vfs_fstatat was getting added only for one location: Writing event: p:probe/vfs_fstatat _text+6345404 dfd=%gpr3:s32 filename=%gpr4:x64 stat=%gpr5:x64 flags=%gpr6:s32 With this change, vfs_fstatat code is inlined for other locations in the code: Probe point found: __do_sys_lstat64+48 Probe point found: __do_sys_stat64+48 Probe point found: __do_sys_newlstat+48 Probe point found: __do_sys_newstat+48 Probe point found: vfs_fstatat+0 When trying to find matching dwarf information entry (DIE) from the debuginfo, the code incorrectly picks DIE which is not referring to vfs_fstatat. Snippet from dwarf entry in vmlinux debuginfo file. The main abstract die is: <1><4214883>: Abbrev Number: 147 (DW_TAG_subprogram) <4214885> DW_AT_external : 1 <4214885> DW_AT_name : (indirect string, offset: 0x17b9f3): vfs_fstatat With formal parameters: <2><4214896>: Abbrev Number: 51 (DW_TAG_formal_parameter) <4214897> DW_AT_name : dfd <2><42148a3>: Abbrev Number: 23 (DW_TAG_formal_parameter) <42148a4> DW_AT_name : (indirect string, offset: 0x8fda9): filename <2><42148b0>: Abbrev Number: 23 (DW_TAG_formal_parameter) <42148b1> DW_AT_name : (indirect string, offset: 0x16bd9c): stat <2><42148bd>: Abbrev Number: 23 (DW_TAG_formal_parameter) <42148be> DW_AT_name : (indirect string, offset: 0x39832b): flags While collecting variables/parameters for a probe point, the function copy_variables_cb() also looks at dwarf debug entries based on the instruction address. Snippet if (dwarf_haspc(die_mem, vf->pf->addr)) return DIE_FIND_CB_CONTINUE; else return DIE_FIND_CB_SIBLING; But incase of inlined function instance for vfs_fstatat, there are two entries which has the instruction address entry point as same. Instance 1: which is for vfs_fstatat and DW_AT_abstract_origin points to 0x4214883 (reference above for main abstract die) <3><42131fa>: Abbrev Number: 59 (DW_TAG_inlined_subroutine) <42131fb> DW_AT_abstract_origin: <0x4214883> <42131ff> DW_AT_entry_pc : 0xc00000000062b1e0 Instance 2: which is not for vfs_fstatat but for getname <5><4213270>: Abbrev Number: 39 (DW_TAG_inlined_subroutine) <4213271> DW_AT_abstract_origin: <0x4215b6b> <4213275> DW_AT_entry_pc : 0xc00000000062b1e0 But the copy_variables_cb() continues to add parameters from second instance also based on the dwarf_haspc() check. This results in formal parameters for getname also appended to params. But while filling in the args->value for these parameters, since these args are not part of dwarf with offset "42131fa". Hence value will be null. This incorrect args results in segfault when value field is accessed. Save the dwarf dieoffset of the actual DW_TAG_subprogram as part of "struct probe_finder". In copy_variables_cb(), include check to make sure the DW_AT_abstract_origin points to the correct entry if the dwarf_haspc() matches the instruction address. Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com> Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Link: https://lore.kernel.org/r/20250225123042.37263-1-atrajeev@linux.ibm.com Signed-off-by: Namhyung Kim <namhyung@kernel.org>
1 parent 833d025 commit 556b58c

File tree

2 files changed

+19
-3
lines changed

2 files changed

+19
-3
lines changed

tools/perf/util/probe-finder.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
973973
pr_debug("Matched function: %s [%lx]\n", dwarf_diename(sp_die),
974974
(unsigned long)dwarf_dieoffset(sp_die));
975975
pf->fname = fname;
976+
pf->abstrace_dieoffset = dwarf_dieoffset(sp_die);
976977
if (pp->line) { /* Function relative line */
977978
dwarf_decl_line(sp_die, &pf->lno);
978979
pf->lno += pp->line;
@@ -1179,6 +1180,8 @@ static int copy_variables_cb(Dwarf_Die *die_mem, void *data)
11791180
struct local_vars_finder *vf = data;
11801181
struct probe_finder *pf = vf->pf;
11811182
int tag;
1183+
Dwarf_Attribute attr;
1184+
Dwarf_Die var_die;
11821185

11831186
tag = dwarf_tag(die_mem);
11841187
if (tag == DW_TAG_formal_parameter ||
@@ -1196,10 +1199,22 @@ static int copy_variables_cb(Dwarf_Die *die_mem, void *data)
11961199
}
11971200
}
11981201

1199-
if (dwarf_haspc(die_mem, vf->pf->addr))
1202+
if (dwarf_haspc(die_mem, vf->pf->addr)) {
1203+
/*
1204+
* when DW_AT_entry_pc contains instruction address,
1205+
* also check if the DW_AT_abstract_origin of die_mem
1206+
* points to correct die.
1207+
*/
1208+
if (dwarf_attr(die_mem, DW_AT_abstract_origin, &attr)) {
1209+
dwarf_formref_die(&attr, &var_die);
1210+
if (pf->abstrace_dieoffset != dwarf_dieoffset(&var_die))
1211+
goto out;
1212+
}
12001213
return DIE_FIND_CB_CONTINUE;
1201-
else
1202-
return DIE_FIND_CB_SIBLING;
1214+
}
1215+
1216+
out:
1217+
return DIE_FIND_CB_SIBLING;
12031218
}
12041219

12051220
static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf,

tools/perf/util/probe-finder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ struct probe_finder {
6363
const char *fname; /* Real file name */
6464
Dwarf_Die cu_die; /* Current CU */
6565
Dwarf_Die sp_die;
66+
Dwarf_Off abstrace_dieoffset;
6667
struct intlist *lcache; /* Line cache for lazy match */
6768

6869
/* For variable searching */

0 commit comments

Comments
 (0)