From nobody Sat Nov 23 04:55:46 2024 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B072518BB84; Wed, 13 Nov 2024 22:50:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731538219; cv=none; b=eyGf0XuLoHkqDbD/nn3hAFR2/YbGTG2tnqmHvhfDwYKxE2EKtb1RPIBDYmwChTRMifbjgkLMoiYnBRKM+vUiwhp1mws6qRovDEBX8cFd8UrVLmLTwRKaMUcKlcZRSxd9jIL7bHUq6OUqGfIgySCSBly23z/unhaUBXBAUmzAXQM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731538219; c=relaxed/simple; bh=cxpxSXBuCEx/21qxfPKUlSPRl62W4RleSGj9yzpAbUI=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type; b=nig7BRlIWGV9TNJSV/kmZ8rlYr8MaT1Ts5lQueKJxDp7u772UUjqEfWlA21hOcsKif2ItkQhdeyHBV08fshiW3WCyxQw9dScBzpSeY/9VfD9rUEn3dHZyplS8ZfIRjquyBQ/HPA/jYF/H7Xwn8ga8A2DF02bdunqK+pbyfXpSnI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OVdgvrWR; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="OVdgvrWR" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 86104C4CEC3; Wed, 13 Nov 2024 22:50:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1731538219; bh=cxpxSXBuCEx/21qxfPKUlSPRl62W4RleSGj9yzpAbUI=; h=From:To:Cc:Subject:Date:From; b=OVdgvrWRlZCKgPquKxPpwNO7taKPpghTVf60FaueYm4PPfTIBKQO1Z5rXmBOjNbI/ ryz1kuJSL909VAd6OGgqgV9VXeazXW1KcJlRr5nJp+7fDBZ9SDQitYTfMPyfwHCE9n brOPVQW01oxb2SnRgtWKzOD3RrAvz5I+Ephqjuts/M2g+EEH8tDgCWFUJlFRY7WbjR PeqJMHaKdWLvCVkNhELLW5xojMyIJqsMf3lHJ0kUbjHTmTSspStR0OnLzBMODGRnRm PP33lv6MKFNAdn+pfit5yiyT9a66h/EH9Xwxv4/FbbHzaD8sls7IgPw2IlwunHZ0IQ g+2Kk4IcFql9A== From: "Masami Hiramatsu (Google)" To: Arnaldo Carvalho de Melo , Namhyung Kim Cc: Li Huafei , Peter Zijlstra , Ingo Molnar , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Liang Kan , Masami Hiramatsu , James Clark , Yury Norov , Przemek Kitszel , Alexander Lobakin , "David S . Miller" , linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] perf-probe: Fix --line option to show correct offset line number from function Date: Thu, 14 Nov 2024 07:50:14 +0900 Message-ID: <173153821454.2776880.582308516721515492.stgit@mhiramat.roam.corp.google.com> X-Mailer: git-send-email 2.47.0.277.g8800431eea-goog User-Agent: StGit/0.19 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Masami Hiramatsu (Google) Fix --line option to show correct offset if the DWARF line info of the probe address has the statement lines in differnt functions. Currently debuginfo__find_probe_point() does (1) Get the line and file from CU's lineinfo (2) Get the real function(function instance) of the address (use this function's decl_line/decl_file as basement) (2-1) Search the inlined function scope in the real function for the given address. (2-2) if there is inlined function, update basement line/file. (2-3) verify the filename is same as basement filename. (3) calculate the relative line number from basement. The problem is in (1). Since we have no basement file/line info, we can not verify that the file/line info from CU's lineinfo. Li Huafei reported[1], the lineinfo may have several different lines for one address. We need to find most appropriate one based on the basement file/line. [1] https://lore.kernel.org/all/20241108181909.3515716-2-lihuafei1@huawei.c= om/ This basically does - Introduce cu_find_lineinfo_after() which find the line after the basement file/line information so that it can choose correct one. - Swap the order of (1) and (2) so that we can pass the basement file/line when searching lineinfo. Reported-by: Li Huafei Closes: https://lore.kernel.org/all/20241108181909.3515716-2-lihuafei1@huaw= ei.com/ Fixes: 57f95bf5f882 ("perf probe: Show correct statement line number by per= f probe -l") Signed-off-by: Masami Hiramatsu (Google) Tested-by: Li Huafei --- tools/perf/util/dwarf-aux.c | 78 ++++++++++++++++++++++++++++++++++--= ---- tools/perf/util/dwarf-aux.h | 7 ++++ tools/perf/util/probe-finder.c | 44 ++++++++++++++++------- 3 files changed, 105 insertions(+), 24 deletions(-) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 92eb9c8dc3e5..4e3bf41746c1 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -60,14 +60,33 @@ const char *cu_get_comp_dir(Dwarf_Die *cu_die) return dwarf_formstring(&attr); } =20 +static Dwarf_Line *get_next_statement_line(Dwarf_Lines *lines, size_t *idx= , Dwarf_Addr addr) +{ + bool is_statement =3D false; + Dwarf_Line *line; + Dwarf_Addr laddr; + size_t l =3D *idx; + + while (!is_statement) { + line =3D dwarf_onesrcline(lines, ++l); + if (!line || dwarf_lineaddr(line, &laddr) !=3D 0 || + dwarf_linebeginstatement(line, &is_statement) !=3D 0) + return NULL; + if (laddr > addr) + return NULL; + } + *idx =3D l; + return line; +} + /* Unlike dwarf_getsrc_die(), cu_getsrc_die() only returns statement line = */ -static Dwarf_Line *cu_getsrc_die(Dwarf_Die *cu_die, Dwarf_Addr addr) +static Dwarf_Line *cu_getsrc_die(Dwarf_Die *cu_die, Dwarf_Addr addr, + Dwarf_Lines **lines_p, size_t *idx) { Dwarf_Addr laddr; Dwarf_Lines *lines; Dwarf_Line *line; size_t nlines, l, u, n; - bool flag; =20 if (dwarf_getsrclines(cu_die, &lines, &nlines) !=3D 0 || nlines =3D=3D 0) @@ -91,16 +110,14 @@ static Dwarf_Line *cu_getsrc_die(Dwarf_Die *cu_die, Dw= arf_Addr addr) if (!line || dwarf_lineaddr(line, &laddr) !=3D 0) return NULL; } while (laddr =3D=3D addr); - l++; /* Going forward to find the statement line */ - do { - line =3D dwarf_onesrcline(lines, l++); - if (!line || dwarf_lineaddr(line, &laddr) !=3D 0 || - dwarf_linebeginstatement(line, &flag) !=3D 0) - return NULL; - if (laddr > addr) - return NULL; - } while (!flag); + line =3D get_next_statement_line(lines, &l, addr); + if (!line) + return NULL; + if (lines_p) + *lines_p =3D lines; + if (idx) + *idx =3D l; =20 return line; } @@ -129,7 +146,7 @@ int cu_find_lineinfo(Dwarf_Die *cu_die, Dwarf_Addr addr, goto out; } =20 - line =3D cu_getsrc_die(cu_die, addr); + line =3D cu_getsrc_die(cu_die, addr, NULL, NULL); if (line && dwarf_lineno(line, lineno) =3D=3D 0) { *fname =3D dwarf_linesrc(line, NULL, NULL); if (!*fname) @@ -141,6 +158,43 @@ int cu_find_lineinfo(Dwarf_Die *cu_die, Dwarf_Addr add= r, return (*lineno && *fname) ? *lineno : -ENOENT; } =20 +/** + * cu_find_lineinfo_after - Get a line number after file:line for given ad= dress + * @cu_die: a CU DIE + * @addr: An address + * @lineno: a pointer which returns the line number + * @fname: the filename where searching the line + * @baseline: the basement line number + * + * Find a line number after @baseline in @fname for @addr in @cu_die. + * Return the found line number, or -ENOENT if not found. + */ +int cu_find_lineinfo_after(Dwarf_Die *cu_die, Dwarf_Addr addr, + int *lineno, const char *fname, int baseline) +{ + const char *line_fname; + Dwarf_Lines *lines; + Dwarf_Line *line; + size_t idx =3D 0; + + if (cu_find_lineinfo(cu_die, addr, &line_fname, lineno) < 0) + return -ENOENT; + + if (!strcmp(line_fname, fname) && baseline <=3D *lineno) + return *lineno; + + line =3D cu_getsrc_die(cu_die, addr, &lines, &idx); + + while (line && dwarf_lineno(line, lineno) =3D=3D 0) { + line_fname =3D dwarf_linesrc(line, NULL, NULL); + if (line_fname && !strcmp(line_fname, fname) && baseline <=3D *lineno) + return *lineno; + line =3D get_next_statement_line(lines, &idx, addr); + } + + return -ENOENT; +} + static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data); =20 /** diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index bd7505812569..19edf21e2f78 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -23,6 +23,13 @@ const char *cu_get_comp_dir(Dwarf_Die *cu_die); int cu_find_lineinfo(Dwarf_Die *cudie, Dwarf_Addr addr, const char **fname, int *lineno); =20 +/* + * Get the most likely line number for given address in given filename + * and basement line number. + */ +int cu_find_lineinfo_after(Dwarf_Die *cudie, Dwarf_Addr addr, + int *lineno, const char *fname, int baseline); + /* Walk on functions at given address */ int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, int (*callback)(Dwarf_Die *, void *), void *data); diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 13ff45d3d6a4..efcacb5568e5 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -1578,7 +1578,8 @@ int debuginfo__find_probe_point(struct debuginfo *dbg= , u64 addr, { Dwarf_Die cudie, spdie, indie; Dwarf_Addr _addr =3D 0, baseaddr =3D 0; - const char *fname =3D NULL, *func =3D NULL, *basefunc =3D NULL, *tmp; + const char *fname =3D NULL, *func =3D NULL, *basefunc =3D NULL; + const char *basefname =3D NULL, *tmp; int baseline =3D 0, lineno =3D 0, ret =3D 0; =20 /* We always need to relocate the address for aranges */ @@ -1592,11 +1593,7 @@ int debuginfo__find_probe_point(struct debuginfo *db= g, u64 addr, goto end; } =20 - /* Find a corresponding line (filename and lineno) */ - cu_find_lineinfo(&cudie, (Dwarf_Addr)addr, &fname, &lineno); - /* Don't care whether it failed or not */ - - /* Find a corresponding function (name, baseline and baseaddr) */ + /* Find the basement function (name, baseline and baseaddr) */ if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { /* Get function entry information */ func =3D basefunc =3D dwarf_diename(&spdie); @@ -1607,10 +1604,16 @@ int debuginfo__find_probe_point(struct debuginfo *d= bg, u64 addr, goto post; } =20 - fname =3D die_get_decl_file(&spdie); + basefname =3D die_get_decl_file(&spdie); + if (!basefname) { + lineno =3D 0; + goto post; + } + if (addr =3D=3D baseaddr) { /* Function entry - Relative line number is 0 */ lineno =3D baseline; + fname =3D basefname; goto post; } =20 @@ -1627,7 +1630,9 @@ int debuginfo__find_probe_point(struct debuginfo *dbg= , u64 addr, */ lineno =3D die_get_call_lineno(&indie); fname =3D die_get_call_file(&indie); - break; + if (!fname || strcmp(fname, basefname)) + lineno =3D 0; + goto post; } else { /* * addr is in an inline function body. @@ -1636,20 +1641,35 @@ int debuginfo__find_probe_point(struct debuginfo *d= bg, u64 addr, * be the entry line of the inline function. */ tmp =3D dwarf_diename(&indie); - if (!tmp || - dwarf_decl_line(&indie, &baseline) !=3D 0) - break; + basefname =3D die_get_decl_file(&indie); + if (!tmp || !basefname || + dwarf_decl_line(&indie, &baseline) !=3D 0) { + lineno =3D 0; + goto post; + } func =3D tmp; spdie =3D indie; } } + } + + if (!lineno) { + /* Find a corresponding line (filename and lineno) */ + if (cu_find_lineinfo_after(&cudie, (Dwarf_Addr)addr, &lineno, + basefname, baseline) < 0) + lineno =3D 0; + else + fname =3D basefname; + } + +post: + if (lineno) { /* Verify the lineno and baseline are in a same file */ tmp =3D die_get_decl_file(&spdie); if (!tmp || (fname && strcmp(tmp, fname) !=3D 0)) lineno =3D 0; } =20 -post: /* Make a relative line number or an offset */ if (lineno) ppt->line =3D lineno - baseline;