lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20241108181909.3515716-2-lihuafei1@huawei.com>
Date: Sat, 9 Nov 2024 02:19:09 +0800
From: Li Huafei <lihuafei1@...wei.com>
To: <mhiramat@...nel.org>, <acme@...nel.org>
CC: <peterz@...radead.org>, <mingo@...hat.com>, <namhyung@...nel.org>,
	<mark.rutland@....com>, <alexander.shishkin@...ux.intel.com>,
	<jolsa@...nel.org>, <irogers@...gle.com>, <adrian.hunter@...el.com>,
	<kan.liang@...ux.intel.com>, <dima@...retsauce.net>,
	<aleksander.lobakin@...el.com>, <linux-perf-users@...r.kernel.org>,
	<linux-kernel@...r.kernel.org>, <lihuafei1@...wei.com>
Subject: [PATCH 2/2] perf probe: Fix the incorrect line number display in 'perf probe -l'

I found an issue with the line number display in perf probe -l:

  # perf probe -l
    probe:schedule       (on schedule:-6751@...nel/sched/core.c)

I founded that in debuginfo__find_probe_point(), the fname obtained by
cu_find_lineinfo() is different from the result returned by
die_get_decl_file(). The 'baseline' and 'lineno' do not correspond to
the same file, resulting in an incorrect calculation of the line number
(lineno - baseline).

The DWARF dump information shows that the probed address
0xffff800080e55bc4 (i.e., schedule+20) has two source file information:

  # readelf --debug-dump=decodedline vmlinux | grep ffff800080e55bc4 -C 2
  ./arch/arm64/include/asm/current.h:
  current.h                                     19  0xffff800080e55bc0
  current.h                                     21  0xffff800080e55bc4               x
  current.h                                     21  0xffff800080e55bc4       1

  kernel/sched/core.c:
  core.c                                      6777  0xffff800080e55bc4       2       x
  core.c                                      6777  0xffff800080e55bc4       3       x
  core.c                                      6777  0xffff800080e55bc4       4       x
  core.c                                      6780  0xffff800080e55bc4       5       x

The first location corresponds to the inline function get_current(), and
cu_find_lineinfo() should have found this entry. However, the probed
instruction is actually in the schedule() function, which is
disassembled as follows:

  crash> disassemble/s schedule
  Dump of assembler code for function schedule:
  ./arch/arm64/include/asm/current.h:
  15      static __always_inline struct task_struct *get_current(void)
  16      {
  17              unsigned long sp_el0;
  18
  19              asm ("mrs %0, sp_el0" : "=r" (sp_el0));
     0xffff800080e55bb0 <+0>:     paciasp
  Dump of assembler code for function schedule:
  ./arch/arm64/include/asm/current.h:
  15      static __always_inline struct task_struct *get_current(void)
  16      {
  17              unsigned long sp_el0;
  18
  19              asm ("mrs %0, sp_el0" : "=r" (sp_el0));
     0xffff800080e55bb0 <+0>:     paciasp
     0xffff800080e55bb4 <+4>:     stp     x29, x30, [sp, #-32]!
     0xffff800080e55bb8 <+8>:     mov     x29, sp
     0xffff800080e55bbc <+12>:    stp     x19, x20, [sp, #16]
     0xffff800080e55bc0 <+16>:    mrs     x19, sp_el0

  kernel/sched/core.c:
  6780            if (!task_is_running(tsk))
     0xffff800080e55bc4 <+20>:    ldr     w0, [x19, #24]
     0xffff800080e55bc8 <+24>:    cbnz    w0, 0xffff800080e55bf8 <schedule+72>

And the DWARF function dump information:

  <1><11eae66>: Abbrev Number: 88 (DW_TAG_subprogram)
     <11eae67>   DW_AT_external    : 1
     <11eae67>   DW_AT_name        : (indirect string, offset: 0x233efb): schedule
     <11eae6b>   DW_AT_decl_file   : 18
     <11eae6c>   DW_AT_decl_line   : 6772
     <11eae6e>   DW_AT_decl_column : 35
     <11eae6f>   DW_AT_prototyped  : 1
     <11eae6f>   DW_AT_low_pc      : 0xffff800080e55bb0
     <11eae77>   DW_AT_high_pc     : 0xb8
     <11eae7f>   DW_AT_frame_base  : 1 byte block: 9c    (DW_OP_call_frame_cfa)
     <11eae81>   DW_AT_GNU_all_call_sites: 1
     <11eae81>   DW_AT_sibling     : <0x11eb12d>
  <2><11eae85>: Abbrev Number: 50 (DW_TAG_variable)
     <11eae86>   DW_AT_name        : tsk
     <11eae8a>   DW_AT_decl_file   : 18
     <11eae8b>   DW_AT_decl_line   : 6774
     <11eae8d>   DW_AT_decl_column : 22
     <11eae8e>   DW_AT_type        : <0x11b2b34>
     <11eae92>   DW_AT_location    : 0x5be6f0 (location list)
     <11eae96>   DW_AT_GNU_locviews: 0x5be6ec
  <2><11eae9a>: Abbrev Number: 78 (DW_TAG_lexical_block)
     <11eae9b>   DW_AT_low_pc      : 0xffff800080e55bc4
     <11eaea3>   DW_AT_high_pc     : 0x0
     <11eaeab>   DW_AT_sibling     : <0x11eaeb9>

Therefore, here we should use the result of die_find_realfunc() +
die_get_decl_file(). However, regardless, we should verify if the fname
obtained from both is the same. If they are different, we should use the
latter to avoid inconsistencies between lineno, fname, and basefunc.

After the modification, the output is as follows:

  # perf probe -l
    probe:schedule       (on schedule+20@...nel/sched/core.c)

Fixes: 57f95bf5f882 ("perf probe: Show correct statement line number by perf probe -l")
Signed-off-by: Li Huafei <lihuafei1@...wei.com>
---
 tools/perf/util/probe-finder.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 630e16c54ed5..106c9d6bd728 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -1592,7 +1592,16 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr,
 			goto post;
 		}
 
-		fname = die_get_decl_file(&spdie);
+		tmp = die_get_decl_file(&spdie);
+		/*
+		 * cu_find_lineinfo() uses cu_getsrc_die() to get fname, which
+		 * may differ from the result of die_get_decl_file(). Add a check
+		 * to ensure that lineno and baseline are in the same file.
+		 */
+		if (!tmp || (fname && strcmp(tmp, fname) != 0))
+			lineno = 0;
+		fname = tmp;
+
 		if (addr == baseaddr) {
 			/* Function entry - Relative line number is 0 */
 			lineno = baseline;
-- 
2.25.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ