hc
2023-12-09 b22da3d8526a935aa31e086e63f60ff3246cb61c
kernel/tools/perf/util/dwarf-aux.c
....@@ -1,28 +1,15 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * dwarf-aux.c : libdw auxiliary interfaces
3
- *
4
- * This program is free software; you can redistribute it and/or modify
5
- * it under the terms of the GNU General Public License as published by
6
- * the Free Software Foundation; either version 2 of the License, or
7
- * (at your option) any later version.
8
- *
9
- * This program is distributed in the hope that it will be useful,
10
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- * GNU General Public License for more details.
13
- *
14
- * You should have received a copy of the GNU General Public License
15
- * along with this program; if not, write to the Free Software
16
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
- *
184 */
195
206 #include <errno.h>
217 #include <inttypes.h>
228 #include <stdbool.h>
23
-#include "util.h"
9
+#include <stdlib.h>
2410 #include "debug.h"
2511 #include "dwarf-aux.h"
12
+#include "strbuf.h"
2613 #include "string2.h"
2714
2815 /**
....@@ -72,6 +59,51 @@
7259 return dwarf_formstring(&attr);
7360 }
7461
62
+/* Unlike dwarf_getsrc_die(), cu_getsrc_die() only returns statement line */
63
+static Dwarf_Line *cu_getsrc_die(Dwarf_Die *cu_die, Dwarf_Addr addr)
64
+{
65
+ Dwarf_Addr laddr;
66
+ Dwarf_Lines *lines;
67
+ Dwarf_Line *line;
68
+ size_t nlines, l, u, n;
69
+ bool flag;
70
+
71
+ if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0 ||
72
+ nlines == 0)
73
+ return NULL;
74
+
75
+ /* Lines are sorted by address, use binary search */
76
+ l = 0; u = nlines - 1;
77
+ while (l < u) {
78
+ n = u - (u - l) / 2;
79
+ line = dwarf_onesrcline(lines, n);
80
+ if (!line || dwarf_lineaddr(line, &laddr) != 0)
81
+ return NULL;
82
+ if (addr < laddr)
83
+ u = n - 1;
84
+ else
85
+ l = n;
86
+ }
87
+ /* Going backward to find the lowest line */
88
+ do {
89
+ line = dwarf_onesrcline(lines, --l);
90
+ if (!line || dwarf_lineaddr(line, &laddr) != 0)
91
+ return NULL;
92
+ } while (laddr == addr);
93
+ l++;
94
+ /* Going foward to find the statement line */
95
+ do {
96
+ line = dwarf_onesrcline(lines, l++);
97
+ if (!line || dwarf_lineaddr(line, &laddr) != 0 ||
98
+ dwarf_linebeginstatement(line, &flag) != 0)
99
+ return NULL;
100
+ if (laddr > addr)
101
+ return NULL;
102
+ } while (!flag);
103
+
104
+ return line;
105
+}
106
+
75107 /**
76108 * cu_find_lineinfo - Get a line number and file name for given address
77109 * @cu_die: a CU DIE
....@@ -85,17 +117,26 @@
85117 const char **fname, int *lineno)
86118 {
87119 Dwarf_Line *line;
88
- Dwarf_Addr laddr;
120
+ Dwarf_Die die_mem;
121
+ Dwarf_Addr faddr;
89122
90
- line = dwarf_getsrc_die(cu_die, (Dwarf_Addr)addr);
91
- if (line && dwarf_lineaddr(line, &laddr) == 0 &&
92
- addr == (unsigned long)laddr && dwarf_lineno(line, lineno) == 0) {
123
+ if (die_find_realfunc(cu_die, (Dwarf_Addr)addr, &die_mem)
124
+ && die_entrypc(&die_mem, &faddr) == 0 &&
125
+ faddr == addr) {
126
+ *fname = dwarf_decl_file(&die_mem);
127
+ dwarf_decl_line(&die_mem, lineno);
128
+ goto out;
129
+ }
130
+
131
+ line = cu_getsrc_die(cu_die, (Dwarf_Addr)addr);
132
+ if (line && dwarf_lineno(line, lineno) == 0) {
93133 *fname = dwarf_linesrc(line, NULL, NULL);
94134 if (!*fname)
95135 /* line number is useless without filename */
96136 *lineno = 0;
97137 }
98138
139
+out:
99140 return *lineno ?: -ENOENT;
100141 }
101142
....@@ -315,9 +356,25 @@
315356 bool die_is_func_def(Dwarf_Die *dw_die)
316357 {
317358 Dwarf_Attribute attr;
359
+ Dwarf_Addr addr = 0;
318360
319
- return (dwarf_tag(dw_die) == DW_TAG_subprogram &&
320
- dwarf_attr(dw_die, DW_AT_declaration, &attr) == NULL);
361
+ if (dwarf_tag(dw_die) != DW_TAG_subprogram)
362
+ return false;
363
+
364
+ if (dwarf_attr(dw_die, DW_AT_declaration, &attr))
365
+ return false;
366
+
367
+ /*
368
+ * DW_AT_declaration can be lost from function declaration
369
+ * by gcc's bug #97060.
370
+ * So we need to check this subprogram DIE has DW_AT_inline
371
+ * or an entry address.
372
+ */
373
+ if (!dwarf_attr(dw_die, DW_AT_inline, &attr) &&
374
+ die_entrypc(dw_die, &addr) < 0)
375
+ return false;
376
+
377
+ return true;
321378 }
322379
323380 /**
....@@ -918,9 +975,13 @@
918975 if ((tag == DW_TAG_formal_parameter ||
919976 tag == DW_TAG_variable) &&
920977 die_compare_name(die_mem, fvp->name) &&
921
- /* Does the DIE have location information or external instance? */
978
+ /*
979
+ * Does the DIE have location information or const value
980
+ * or external instance?
981
+ */
922982 (dwarf_attr(die_mem, DW_AT_external, &attr) ||
923
- dwarf_attr(die_mem, DW_AT_location, &attr)))
983
+ dwarf_attr(die_mem, DW_AT_location, &attr) ||
984
+ dwarf_attr(die_mem, DW_AT_const_value, &attr)))
924985 return DIE_FIND_CB_END;
925986 if (dwarf_haspc(die_mem, fvp->addr))
926987 return DIE_FIND_CB_CONTINUE;