Commit db0d2c6420eeb8fd669bac84d72f1ab828bbaa64
Committed by
Arnaldo Carvalho de Melo
1 parent
f182e3e13c
Exists in
master
and in
6 other branches
perf probe: Search concrete out-of-line instances
gcc 4.6 generates a concrete out-of-line instance when there is a function which is implicitly inlined somewhere but also has its own instance. The concrete out-of-line instance means that it has an abstract origin of the function which is referred by not only inlined-subroutines but also a concrete subprogram. Since current dwarf_func_inline_instances() can find only instances of inlined-subroutines, this introduces new die_walk_instances() to find both of subprogram and inlined-subroutines. e.g. without this, Available variables at sched_group_rt_period @<cpu_rt_period_read_uint+9> struct task_group* tg perf probe failed to find actual subprogram instance of sched_group_rt_period(). With this, Available variables at sched_group_rt_period @<cpu_rt_period_read_uint+9> struct task_group* tg @<sched_group_rt_period+0> struct task_group* tg Now it found the sched_group_rt_period() itself. Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Paul Mackerras <paulus@samba.org> Cc: Pekka Enberg <penberg@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: yrl.pp-manager.tt@hitachi.com Link: http://lkml.kernel.org/r/20110811110311.19900.63997.stgit@fedora15 Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Showing 3 changed files with 83 additions and 35 deletions Inline Diff
tools/perf/util/dwarf-aux.c
1 | /* | 1 | /* |
2 | * dwarf-aux.c : libdw auxiliary interfaces | 2 | * dwarf-aux.c : libdw auxiliary interfaces |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 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 | 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 | 6 | * the Free Software Foundation; either version 2 of the License, or |
7 | * (at your option) any later version. | 7 | * (at your option) any later version. |
8 | * | 8 | * |
9 | * This program is distributed in the hope that it will be useful, | 9 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
13 | * | 13 | * |
14 | * You should have received a copy of the GNU General Public License | 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 | 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. | 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
17 | * | 17 | * |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <stdbool.h> | 20 | #include <stdbool.h> |
21 | #include "util.h" | 21 | #include "util.h" |
22 | #include "debug.h" | 22 | #include "debug.h" |
23 | #include "dwarf-aux.h" | 23 | #include "dwarf-aux.h" |
24 | 24 | ||
25 | /** | 25 | /** |
26 | * cu_find_realpath - Find the realpath of the target file | 26 | * cu_find_realpath - Find the realpath of the target file |
27 | * @cu_die: A DIE(dwarf information entry) of CU(compilation Unit) | 27 | * @cu_die: A DIE(dwarf information entry) of CU(compilation Unit) |
28 | * @fname: The tail filename of the target file | 28 | * @fname: The tail filename of the target file |
29 | * | 29 | * |
30 | * Find the real(long) path of @fname in @cu_die. | 30 | * Find the real(long) path of @fname in @cu_die. |
31 | */ | 31 | */ |
32 | const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname) | 32 | const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname) |
33 | { | 33 | { |
34 | Dwarf_Files *files; | 34 | Dwarf_Files *files; |
35 | size_t nfiles, i; | 35 | size_t nfiles, i; |
36 | const char *src = NULL; | 36 | const char *src = NULL; |
37 | int ret; | 37 | int ret; |
38 | 38 | ||
39 | if (!fname) | 39 | if (!fname) |
40 | return NULL; | 40 | return NULL; |
41 | 41 | ||
42 | ret = dwarf_getsrcfiles(cu_die, &files, &nfiles); | 42 | ret = dwarf_getsrcfiles(cu_die, &files, &nfiles); |
43 | if (ret != 0) | 43 | if (ret != 0) |
44 | return NULL; | 44 | return NULL; |
45 | 45 | ||
46 | for (i = 0; i < nfiles; i++) { | 46 | for (i = 0; i < nfiles; i++) { |
47 | src = dwarf_filesrc(files, i, NULL, NULL); | 47 | src = dwarf_filesrc(files, i, NULL, NULL); |
48 | if (strtailcmp(src, fname) == 0) | 48 | if (strtailcmp(src, fname) == 0) |
49 | break; | 49 | break; |
50 | } | 50 | } |
51 | if (i == nfiles) | 51 | if (i == nfiles) |
52 | return NULL; | 52 | return NULL; |
53 | return src; | 53 | return src; |
54 | } | 54 | } |
55 | 55 | ||
56 | /** | 56 | /** |
57 | * cu_get_comp_dir - Get the path of compilation directory | 57 | * cu_get_comp_dir - Get the path of compilation directory |
58 | * @cu_die: a CU DIE | 58 | * @cu_die: a CU DIE |
59 | * | 59 | * |
60 | * Get the path of compilation directory of given @cu_die. | 60 | * Get the path of compilation directory of given @cu_die. |
61 | * Since this depends on DW_AT_comp_dir, older gcc will not | 61 | * Since this depends on DW_AT_comp_dir, older gcc will not |
62 | * embedded it. In that case, this returns NULL. | 62 | * embedded it. In that case, this returns NULL. |
63 | */ | 63 | */ |
64 | const char *cu_get_comp_dir(Dwarf_Die *cu_die) | 64 | const char *cu_get_comp_dir(Dwarf_Die *cu_die) |
65 | { | 65 | { |
66 | Dwarf_Attribute attr; | 66 | Dwarf_Attribute attr; |
67 | if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL) | 67 | if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL) |
68 | return NULL; | 68 | return NULL; |
69 | return dwarf_formstring(&attr); | 69 | return dwarf_formstring(&attr); |
70 | } | 70 | } |
71 | 71 | ||
72 | /** | 72 | /** |
73 | * cu_find_lineinfo - Get a line number and file name for given address | 73 | * cu_find_lineinfo - Get a line number and file name for given address |
74 | * @cu_die: a CU DIE | 74 | * @cu_die: a CU DIE |
75 | * @addr: An address | 75 | * @addr: An address |
76 | * @fname: a pointer which returns the file name string | 76 | * @fname: a pointer which returns the file name string |
77 | * @lineno: a pointer which returns the line number | 77 | * @lineno: a pointer which returns the line number |
78 | * | 78 | * |
79 | * Find a line number and file name for @addr in @cu_die. | 79 | * Find a line number and file name for @addr in @cu_die. |
80 | */ | 80 | */ |
81 | int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr, | 81 | int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr, |
82 | const char **fname, int *lineno) | 82 | const char **fname, int *lineno) |
83 | { | 83 | { |
84 | Dwarf_Line *line; | 84 | Dwarf_Line *line; |
85 | Dwarf_Addr laddr; | 85 | Dwarf_Addr laddr; |
86 | 86 | ||
87 | line = dwarf_getsrc_die(cu_die, (Dwarf_Addr)addr); | 87 | line = dwarf_getsrc_die(cu_die, (Dwarf_Addr)addr); |
88 | if (line && dwarf_lineaddr(line, &laddr) == 0 && | 88 | if (line && dwarf_lineaddr(line, &laddr) == 0 && |
89 | addr == (unsigned long)laddr && dwarf_lineno(line, lineno) == 0) { | 89 | addr == (unsigned long)laddr && dwarf_lineno(line, lineno) == 0) { |
90 | *fname = dwarf_linesrc(line, NULL, NULL); | 90 | *fname = dwarf_linesrc(line, NULL, NULL); |
91 | if (!*fname) | 91 | if (!*fname) |
92 | /* line number is useless without filename */ | 92 | /* line number is useless without filename */ |
93 | *lineno = 0; | 93 | *lineno = 0; |
94 | } | 94 | } |
95 | 95 | ||
96 | return *lineno ?: -ENOENT; | 96 | return *lineno ?: -ENOENT; |
97 | } | 97 | } |
98 | 98 | ||
99 | static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data); | 99 | static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data); |
100 | 100 | ||
101 | /** | 101 | /** |
102 | * cu_walk_functions_at - Walk on function DIEs at given address | 102 | * cu_walk_functions_at - Walk on function DIEs at given address |
103 | * @cu_die: A CU DIE | 103 | * @cu_die: A CU DIE |
104 | * @addr: An address | 104 | * @addr: An address |
105 | * @callback: A callback which called with found DIEs | 105 | * @callback: A callback which called with found DIEs |
106 | * @data: A user data | 106 | * @data: A user data |
107 | * | 107 | * |
108 | * Walk on function DIEs at given @addr in @cu_die. Passed DIEs | 108 | * Walk on function DIEs at given @addr in @cu_die. Passed DIEs |
109 | * should be subprogram or inlined-subroutines. | 109 | * should be subprogram or inlined-subroutines. |
110 | */ | 110 | */ |
111 | int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, | 111 | int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, |
112 | int (*callback)(Dwarf_Die *, void *), void *data) | 112 | int (*callback)(Dwarf_Die *, void *), void *data) |
113 | { | 113 | { |
114 | Dwarf_Die die_mem; | 114 | Dwarf_Die die_mem; |
115 | Dwarf_Die *sc_die; | 115 | Dwarf_Die *sc_die; |
116 | int ret = -ENOENT; | 116 | int ret = -ENOENT; |
117 | 117 | ||
118 | /* Inlined function could be recursive. Trace it until fail */ | 118 | /* Inlined function could be recursive. Trace it until fail */ |
119 | for (sc_die = die_find_realfunc(cu_die, addr, &die_mem); | 119 | for (sc_die = die_find_realfunc(cu_die, addr, &die_mem); |
120 | sc_die != NULL; | 120 | sc_die != NULL; |
121 | sc_die = die_find_child(sc_die, __die_find_inline_cb, &addr, | 121 | sc_die = die_find_child(sc_die, __die_find_inline_cb, &addr, |
122 | &die_mem)) { | 122 | &die_mem)) { |
123 | ret = callback(sc_die, data); | 123 | ret = callback(sc_die, data); |
124 | if (ret) | 124 | if (ret) |
125 | break; | 125 | break; |
126 | } | 126 | } |
127 | 127 | ||
128 | return ret; | 128 | return ret; |
129 | 129 | ||
130 | } | 130 | } |
131 | 131 | ||
132 | /** | 132 | /** |
133 | * die_compare_name - Compare diename and tname | 133 | * die_compare_name - Compare diename and tname |
134 | * @dw_die: a DIE | 134 | * @dw_die: a DIE |
135 | * @tname: a string of target name | 135 | * @tname: a string of target name |
136 | * | 136 | * |
137 | * Compare the name of @dw_die and @tname. Return false if @dw_die has no name. | 137 | * Compare the name of @dw_die and @tname. Return false if @dw_die has no name. |
138 | */ | 138 | */ |
139 | bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | 139 | bool die_compare_name(Dwarf_Die *dw_die, const char *tname) |
140 | { | 140 | { |
141 | const char *name; | 141 | const char *name; |
142 | name = dwarf_diename(dw_die); | 142 | name = dwarf_diename(dw_die); |
143 | return name ? (strcmp(tname, name) == 0) : false; | 143 | return name ? (strcmp(tname, name) == 0) : false; |
144 | } | 144 | } |
145 | 145 | ||
146 | /** | 146 | /** |
147 | * die_get_call_lineno - Get callsite line number of inline-function instance | 147 | * die_get_call_lineno - Get callsite line number of inline-function instance |
148 | * @in_die: a DIE of an inlined function instance | 148 | * @in_die: a DIE of an inlined function instance |
149 | * | 149 | * |
150 | * Get call-site line number of @in_die. This means from where the inline | 150 | * Get call-site line number of @in_die. This means from where the inline |
151 | * function is called. | 151 | * function is called. |
152 | */ | 152 | */ |
153 | int die_get_call_lineno(Dwarf_Die *in_die) | 153 | int die_get_call_lineno(Dwarf_Die *in_die) |
154 | { | 154 | { |
155 | Dwarf_Attribute attr; | 155 | Dwarf_Attribute attr; |
156 | Dwarf_Word ret; | 156 | Dwarf_Word ret; |
157 | 157 | ||
158 | if (!dwarf_attr(in_die, DW_AT_call_line, &attr)) | 158 | if (!dwarf_attr(in_die, DW_AT_call_line, &attr)) |
159 | return -ENOENT; | 159 | return -ENOENT; |
160 | 160 | ||
161 | dwarf_formudata(&attr, &ret); | 161 | dwarf_formudata(&attr, &ret); |
162 | return (int)ret; | 162 | return (int)ret; |
163 | } | 163 | } |
164 | 164 | ||
165 | /** | 165 | /** |
166 | * die_get_type - Get type DIE | 166 | * die_get_type - Get type DIE |
167 | * @vr_die: a DIE of a variable | 167 | * @vr_die: a DIE of a variable |
168 | * @die_mem: where to store a type DIE | 168 | * @die_mem: where to store a type DIE |
169 | * | 169 | * |
170 | * Get a DIE of the type of given variable (@vr_die), and store | 170 | * Get a DIE of the type of given variable (@vr_die), and store |
171 | * it to die_mem. Return NULL if fails to get a type DIE. | 171 | * it to die_mem. Return NULL if fails to get a type DIE. |
172 | */ | 172 | */ |
173 | Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) | 173 | Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) |
174 | { | 174 | { |
175 | Dwarf_Attribute attr; | 175 | Dwarf_Attribute attr; |
176 | 176 | ||
177 | if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) && | 177 | if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) && |
178 | dwarf_formref_die(&attr, die_mem)) | 178 | dwarf_formref_die(&attr, die_mem)) |
179 | return die_mem; | 179 | return die_mem; |
180 | else | 180 | else |
181 | return NULL; | 181 | return NULL; |
182 | } | 182 | } |
183 | 183 | ||
184 | /* Get a type die, but skip qualifiers */ | 184 | /* Get a type die, but skip qualifiers */ |
185 | static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) | 185 | static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) |
186 | { | 186 | { |
187 | int tag; | 187 | int tag; |
188 | 188 | ||
189 | do { | 189 | do { |
190 | vr_die = die_get_type(vr_die, die_mem); | 190 | vr_die = die_get_type(vr_die, die_mem); |
191 | if (!vr_die) | 191 | if (!vr_die) |
192 | break; | 192 | break; |
193 | tag = dwarf_tag(vr_die); | 193 | tag = dwarf_tag(vr_die); |
194 | } while (tag == DW_TAG_const_type || | 194 | } while (tag == DW_TAG_const_type || |
195 | tag == DW_TAG_restrict_type || | 195 | tag == DW_TAG_restrict_type || |
196 | tag == DW_TAG_volatile_type || | 196 | tag == DW_TAG_volatile_type || |
197 | tag == DW_TAG_shared_type); | 197 | tag == DW_TAG_shared_type); |
198 | 198 | ||
199 | return vr_die; | 199 | return vr_die; |
200 | } | 200 | } |
201 | 201 | ||
202 | /** | 202 | /** |
203 | * die_get_real_type - Get a type die, but skip qualifiers and typedef | 203 | * die_get_real_type - Get a type die, but skip qualifiers and typedef |
204 | * @vr_die: a DIE of a variable | 204 | * @vr_die: a DIE of a variable |
205 | * @die_mem: where to store a type DIE | 205 | * @die_mem: where to store a type DIE |
206 | * | 206 | * |
207 | * Get a DIE of the type of given variable (@vr_die), and store | 207 | * Get a DIE of the type of given variable (@vr_die), and store |
208 | * it to die_mem. Return NULL if fails to get a type DIE. | 208 | * it to die_mem. Return NULL if fails to get a type DIE. |
209 | * If the type is qualifiers (e.g. const) or typedef, this skips it | 209 | * If the type is qualifiers (e.g. const) or typedef, this skips it |
210 | * and tries to find real type (structure or basic types, e.g. int). | 210 | * and tries to find real type (structure or basic types, e.g. int). |
211 | */ | 211 | */ |
212 | Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) | 212 | Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) |
213 | { | 213 | { |
214 | do { | 214 | do { |
215 | vr_die = __die_get_real_type(vr_die, die_mem); | 215 | vr_die = __die_get_real_type(vr_die, die_mem); |
216 | } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef); | 216 | } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef); |
217 | 217 | ||
218 | return vr_die; | 218 | return vr_die; |
219 | } | 219 | } |
220 | 220 | ||
221 | /* Get attribute and translate it as a udata */ | 221 | /* Get attribute and translate it as a udata */ |
222 | static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name, | 222 | static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name, |
223 | Dwarf_Word *result) | 223 | Dwarf_Word *result) |
224 | { | 224 | { |
225 | Dwarf_Attribute attr; | 225 | Dwarf_Attribute attr; |
226 | 226 | ||
227 | if (dwarf_attr(tp_die, attr_name, &attr) == NULL || | 227 | if (dwarf_attr(tp_die, attr_name, &attr) == NULL || |
228 | dwarf_formudata(&attr, result) != 0) | 228 | dwarf_formudata(&attr, result) != 0) |
229 | return -ENOENT; | 229 | return -ENOENT; |
230 | 230 | ||
231 | return 0; | 231 | return 0; |
232 | } | 232 | } |
233 | 233 | ||
234 | /* Get attribute and translate it as a sdata */ | 234 | /* Get attribute and translate it as a sdata */ |
235 | static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name, | 235 | static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name, |
236 | Dwarf_Sword *result) | 236 | Dwarf_Sword *result) |
237 | { | 237 | { |
238 | Dwarf_Attribute attr; | 238 | Dwarf_Attribute attr; |
239 | 239 | ||
240 | if (dwarf_attr(tp_die, attr_name, &attr) == NULL || | 240 | if (dwarf_attr(tp_die, attr_name, &attr) == NULL || |
241 | dwarf_formsdata(&attr, result) != 0) | 241 | dwarf_formsdata(&attr, result) != 0) |
242 | return -ENOENT; | 242 | return -ENOENT; |
243 | 243 | ||
244 | return 0; | 244 | return 0; |
245 | } | 245 | } |
246 | 246 | ||
247 | /** | 247 | /** |
248 | * die_is_signed_type - Check whether a type DIE is signed or not | 248 | * die_is_signed_type - Check whether a type DIE is signed or not |
249 | * @tp_die: a DIE of a type | 249 | * @tp_die: a DIE of a type |
250 | * | 250 | * |
251 | * Get the encoding of @tp_die and return true if the encoding | 251 | * Get the encoding of @tp_die and return true if the encoding |
252 | * is signed. | 252 | * is signed. |
253 | */ | 253 | */ |
254 | bool die_is_signed_type(Dwarf_Die *tp_die) | 254 | bool die_is_signed_type(Dwarf_Die *tp_die) |
255 | { | 255 | { |
256 | Dwarf_Word ret; | 256 | Dwarf_Word ret; |
257 | 257 | ||
258 | if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret)) | 258 | if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret)) |
259 | return false; | 259 | return false; |
260 | 260 | ||
261 | return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || | 261 | return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || |
262 | ret == DW_ATE_signed_fixed); | 262 | ret == DW_ATE_signed_fixed); |
263 | } | 263 | } |
264 | 264 | ||
265 | /** | 265 | /** |
266 | * die_get_data_member_location - Get the data-member offset | 266 | * die_get_data_member_location - Get the data-member offset |
267 | * @mb_die: a DIE of a member of a data structure | 267 | * @mb_die: a DIE of a member of a data structure |
268 | * @offs: The offset of the member in the data structure | 268 | * @offs: The offset of the member in the data structure |
269 | * | 269 | * |
270 | * Get the offset of @mb_die in the data structure including @mb_die, and | 270 | * Get the offset of @mb_die in the data structure including @mb_die, and |
271 | * stores result offset to @offs. If any error occurs this returns errno. | 271 | * stores result offset to @offs. If any error occurs this returns errno. |
272 | */ | 272 | */ |
273 | int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs) | 273 | int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs) |
274 | { | 274 | { |
275 | Dwarf_Attribute attr; | 275 | Dwarf_Attribute attr; |
276 | Dwarf_Op *expr; | 276 | Dwarf_Op *expr; |
277 | size_t nexpr; | 277 | size_t nexpr; |
278 | int ret; | 278 | int ret; |
279 | 279 | ||
280 | if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL) | 280 | if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL) |
281 | return -ENOENT; | 281 | return -ENOENT; |
282 | 282 | ||
283 | if (dwarf_formudata(&attr, offs) != 0) { | 283 | if (dwarf_formudata(&attr, offs) != 0) { |
284 | /* DW_AT_data_member_location should be DW_OP_plus_uconst */ | 284 | /* DW_AT_data_member_location should be DW_OP_plus_uconst */ |
285 | ret = dwarf_getlocation(&attr, &expr, &nexpr); | 285 | ret = dwarf_getlocation(&attr, &expr, &nexpr); |
286 | if (ret < 0 || nexpr == 0) | 286 | if (ret < 0 || nexpr == 0) |
287 | return -ENOENT; | 287 | return -ENOENT; |
288 | 288 | ||
289 | if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) { | 289 | if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) { |
290 | pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n", | 290 | pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n", |
291 | expr[0].atom, nexpr); | 291 | expr[0].atom, nexpr); |
292 | return -ENOTSUP; | 292 | return -ENOTSUP; |
293 | } | 293 | } |
294 | *offs = (Dwarf_Word)expr[0].number; | 294 | *offs = (Dwarf_Word)expr[0].number; |
295 | } | 295 | } |
296 | return 0; | 296 | return 0; |
297 | } | 297 | } |
298 | 298 | ||
299 | /* Get the call file index number in CU DIE */ | 299 | /* Get the call file index number in CU DIE */ |
300 | static int die_get_call_fileno(Dwarf_Die *in_die) | 300 | static int die_get_call_fileno(Dwarf_Die *in_die) |
301 | { | 301 | { |
302 | Dwarf_Sword idx; | 302 | Dwarf_Sword idx; |
303 | 303 | ||
304 | if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0) | 304 | if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0) |
305 | return (int)idx; | 305 | return (int)idx; |
306 | else | 306 | else |
307 | return -ENOENT; | 307 | return -ENOENT; |
308 | } | 308 | } |
309 | 309 | ||
310 | /** | 310 | /** |
311 | * die_get_call_file - Get callsite file name of inlined function instance | 311 | * die_get_call_file - Get callsite file name of inlined function instance |
312 | * @in_die: a DIE of an inlined function instance | 312 | * @in_die: a DIE of an inlined function instance |
313 | * | 313 | * |
314 | * Get call-site file name of @in_die. This means from which file the inline | 314 | * Get call-site file name of @in_die. This means from which file the inline |
315 | * function is called. | 315 | * function is called. |
316 | */ | 316 | */ |
317 | const char *die_get_call_file(Dwarf_Die *in_die) | 317 | const char *die_get_call_file(Dwarf_Die *in_die) |
318 | { | 318 | { |
319 | Dwarf_Die cu_die; | 319 | Dwarf_Die cu_die; |
320 | Dwarf_Files *files; | 320 | Dwarf_Files *files; |
321 | int idx; | 321 | int idx; |
322 | 322 | ||
323 | idx = die_get_call_fileno(in_die); | 323 | idx = die_get_call_fileno(in_die); |
324 | if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) || | 324 | if (idx < 0 || !dwarf_diecu(in_die, &cu_die, NULL, NULL) || |
325 | dwarf_getsrcfiles(&cu_die, &files, NULL) != 0) | 325 | dwarf_getsrcfiles(&cu_die, &files, NULL) != 0) |
326 | return NULL; | 326 | return NULL; |
327 | 327 | ||
328 | return dwarf_filesrc(files, idx, NULL, NULL); | 328 | return dwarf_filesrc(files, idx, NULL, NULL); |
329 | } | 329 | } |
330 | 330 | ||
331 | 331 | ||
332 | /** | 332 | /** |
333 | * die_find_child - Generic DIE search function in DIE tree | 333 | * die_find_child - Generic DIE search function in DIE tree |
334 | * @rt_die: a root DIE | 334 | * @rt_die: a root DIE |
335 | * @callback: a callback function | 335 | * @callback: a callback function |
336 | * @data: a user data passed to the callback function | 336 | * @data: a user data passed to the callback function |
337 | * @die_mem: a buffer for result DIE | 337 | * @die_mem: a buffer for result DIE |
338 | * | 338 | * |
339 | * Trace DIE tree from @rt_die and call @callback for each child DIE. | 339 | * Trace DIE tree from @rt_die and call @callback for each child DIE. |
340 | * If @callback returns DIE_FIND_CB_END, this stores the DIE into | 340 | * If @callback returns DIE_FIND_CB_END, this stores the DIE into |
341 | * @die_mem and returns it. If @callback returns DIE_FIND_CB_CONTINUE, | 341 | * @die_mem and returns it. If @callback returns DIE_FIND_CB_CONTINUE, |
342 | * this continues to trace the tree. Optionally, @callback can return | 342 | * this continues to trace the tree. Optionally, @callback can return |
343 | * DIE_FIND_CB_CHILD and DIE_FIND_CB_SIBLING, those means trace only | 343 | * DIE_FIND_CB_CHILD and DIE_FIND_CB_SIBLING, those means trace only |
344 | * the children and trace only the siblings respectively. | 344 | * the children and trace only the siblings respectively. |
345 | * Returns NULL if @callback can't find any appropriate DIE. | 345 | * Returns NULL if @callback can't find any appropriate DIE. |
346 | */ | 346 | */ |
347 | Dwarf_Die *die_find_child(Dwarf_Die *rt_die, | 347 | Dwarf_Die *die_find_child(Dwarf_Die *rt_die, |
348 | int (*callback)(Dwarf_Die *, void *), | 348 | int (*callback)(Dwarf_Die *, void *), |
349 | void *data, Dwarf_Die *die_mem) | 349 | void *data, Dwarf_Die *die_mem) |
350 | { | 350 | { |
351 | Dwarf_Die child_die; | 351 | Dwarf_Die child_die; |
352 | int ret; | 352 | int ret; |
353 | 353 | ||
354 | ret = dwarf_child(rt_die, die_mem); | 354 | ret = dwarf_child(rt_die, die_mem); |
355 | if (ret != 0) | 355 | if (ret != 0) |
356 | return NULL; | 356 | return NULL; |
357 | 357 | ||
358 | do { | 358 | do { |
359 | ret = callback(die_mem, data); | 359 | ret = callback(die_mem, data); |
360 | if (ret == DIE_FIND_CB_END) | 360 | if (ret == DIE_FIND_CB_END) |
361 | return die_mem; | 361 | return die_mem; |
362 | 362 | ||
363 | if ((ret & DIE_FIND_CB_CHILD) && | 363 | if ((ret & DIE_FIND_CB_CHILD) && |
364 | die_find_child(die_mem, callback, data, &child_die)) { | 364 | die_find_child(die_mem, callback, data, &child_die)) { |
365 | memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); | 365 | memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); |
366 | return die_mem; | 366 | return die_mem; |
367 | } | 367 | } |
368 | } while ((ret & DIE_FIND_CB_SIBLING) && | 368 | } while ((ret & DIE_FIND_CB_SIBLING) && |
369 | dwarf_siblingof(die_mem, die_mem) == 0); | 369 | dwarf_siblingof(die_mem, die_mem) == 0); |
370 | 370 | ||
371 | return NULL; | 371 | return NULL; |
372 | } | 372 | } |
373 | 373 | ||
374 | struct __addr_die_search_param { | 374 | struct __addr_die_search_param { |
375 | Dwarf_Addr addr; | 375 | Dwarf_Addr addr; |
376 | Dwarf_Die *die_mem; | 376 | Dwarf_Die *die_mem; |
377 | }; | 377 | }; |
378 | 378 | ||
379 | /* die_find callback for non-inlined function search */ | 379 | /* die_find callback for non-inlined function search */ |
380 | static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) | 380 | static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) |
381 | { | 381 | { |
382 | struct __addr_die_search_param *ad = data; | 382 | struct __addr_die_search_param *ad = data; |
383 | 383 | ||
384 | if (dwarf_tag(fn_die) == DW_TAG_subprogram && | 384 | if (dwarf_tag(fn_die) == DW_TAG_subprogram && |
385 | dwarf_haspc(fn_die, ad->addr)) { | 385 | dwarf_haspc(fn_die, ad->addr)) { |
386 | memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); | 386 | memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); |
387 | return DWARF_CB_ABORT; | 387 | return DWARF_CB_ABORT; |
388 | } | 388 | } |
389 | return DWARF_CB_OK; | 389 | return DWARF_CB_OK; |
390 | } | 390 | } |
391 | 391 | ||
392 | /** | 392 | /** |
393 | * die_find_realfunc - Search a non-inlined function at given address | 393 | * die_find_realfunc - Search a non-inlined function at given address |
394 | * @cu_die: a CU DIE which including @addr | 394 | * @cu_die: a CU DIE which including @addr |
395 | * @addr: target address | 395 | * @addr: target address |
396 | * @die_mem: a buffer for result DIE | 396 | * @die_mem: a buffer for result DIE |
397 | * | 397 | * |
398 | * Search a non-inlined function DIE which includes @addr. Stores the | 398 | * Search a non-inlined function DIE which includes @addr. Stores the |
399 | * DIE to @die_mem and returns it if found. Returns NULl if failed. | 399 | * DIE to @die_mem and returns it if found. Returns NULl if failed. |
400 | */ | 400 | */ |
401 | Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, | 401 | Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, |
402 | Dwarf_Die *die_mem) | 402 | Dwarf_Die *die_mem) |
403 | { | 403 | { |
404 | struct __addr_die_search_param ad; | 404 | struct __addr_die_search_param ad; |
405 | ad.addr = addr; | 405 | ad.addr = addr; |
406 | ad.die_mem = die_mem; | 406 | ad.die_mem = die_mem; |
407 | /* dwarf_getscopes can't find subprogram. */ | 407 | /* dwarf_getscopes can't find subprogram. */ |
408 | if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0)) | 408 | if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0)) |
409 | return NULL; | 409 | return NULL; |
410 | else | 410 | else |
411 | return die_mem; | 411 | return die_mem; |
412 | } | 412 | } |
413 | 413 | ||
414 | /* die_find callback for inline function search */ | 414 | /* die_find callback for inline function search */ |
415 | static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) | 415 | static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) |
416 | { | 416 | { |
417 | Dwarf_Addr *addr = data; | 417 | Dwarf_Addr *addr = data; |
418 | 418 | ||
419 | if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && | 419 | if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && |
420 | dwarf_haspc(die_mem, *addr)) | 420 | dwarf_haspc(die_mem, *addr)) |
421 | return DIE_FIND_CB_END; | 421 | return DIE_FIND_CB_END; |
422 | 422 | ||
423 | return DIE_FIND_CB_CONTINUE; | 423 | return DIE_FIND_CB_CONTINUE; |
424 | } | 424 | } |
425 | 425 | ||
426 | /** | 426 | /** |
427 | * die_find_inlinefunc - Search an inlined function at given address | 427 | * die_find_inlinefunc - Search an inlined function at given address |
428 | * @cu_die: a CU DIE which including @addr | 428 | * @cu_die: a CU DIE which including @addr |
429 | * @addr: target address | 429 | * @addr: target address |
430 | * @die_mem: a buffer for result DIE | 430 | * @die_mem: a buffer for result DIE |
431 | * | 431 | * |
432 | * Search an inlined function DIE which includes @addr. Stores the | 432 | * Search an inlined function DIE which includes @addr. Stores the |
433 | * DIE to @die_mem and returns it if found. Returns NULl if failed. | 433 | * DIE to @die_mem and returns it if found. Returns NULl if failed. |
434 | * If several inlined functions are expanded recursively, this trace | 434 | * If several inlined functions are expanded recursively, this trace |
435 | * it and returns deepest one. | 435 | * it and returns deepest one. |
436 | */ | 436 | */ |
437 | Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 437 | Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
438 | Dwarf_Die *die_mem) | 438 | Dwarf_Die *die_mem) |
439 | { | 439 | { |
440 | Dwarf_Die tmp_die; | 440 | Dwarf_Die tmp_die; |
441 | 441 | ||
442 | sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die); | 442 | sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die); |
443 | if (!sp_die) | 443 | if (!sp_die) |
444 | return NULL; | 444 | return NULL; |
445 | 445 | ||
446 | /* Inlined function could be recursive. Trace it until fail */ | 446 | /* Inlined function could be recursive. Trace it until fail */ |
447 | while (sp_die) { | 447 | while (sp_die) { |
448 | memcpy(die_mem, sp_die, sizeof(Dwarf_Die)); | 448 | memcpy(die_mem, sp_die, sizeof(Dwarf_Die)); |
449 | sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, | 449 | sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, |
450 | &tmp_die); | 450 | &tmp_die); |
451 | } | 451 | } |
452 | 452 | ||
453 | return die_mem; | 453 | return die_mem; |
454 | } | 454 | } |
455 | 455 | ||
456 | struct __instance_walk_param { | ||
457 | void *addr; | ||
458 | int (*callback)(Dwarf_Die *, void *); | ||
459 | void *data; | ||
460 | int retval; | ||
461 | }; | ||
462 | |||
463 | static int __die_walk_instances_cb(Dwarf_Die *inst, void *data) | ||
464 | { | ||
465 | struct __instance_walk_param *iwp = data; | ||
466 | Dwarf_Attribute attr_mem; | ||
467 | Dwarf_Die origin_mem; | ||
468 | Dwarf_Attribute *attr; | ||
469 | Dwarf_Die *origin; | ||
470 | |||
471 | attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem); | ||
472 | if (attr == NULL) | ||
473 | return DIE_FIND_CB_CONTINUE; | ||
474 | |||
475 | origin = dwarf_formref_die(attr, &origin_mem); | ||
476 | if (origin == NULL || origin->addr != iwp->addr) | ||
477 | return DIE_FIND_CB_CONTINUE; | ||
478 | |||
479 | iwp->retval = iwp->callback(inst, iwp->data); | ||
480 | |||
481 | return (iwp->retval) ? DIE_FIND_CB_END : DIE_FIND_CB_CONTINUE; | ||
482 | } | ||
483 | |||
484 | /** | ||
485 | * die_walk_instances - Walk on instances of given DIE | ||
486 | * @or_die: an abstract original DIE | ||
487 | * @callback: a callback function which is called with instance DIE | ||
488 | * @data: user data | ||
489 | * | ||
490 | * Walk on the instances of give @in_die. @in_die must be an inlined function | ||
491 | * declartion. This returns the return value of @callback if it returns | ||
492 | * non-zero value, or -ENOENT if there is no instance. | ||
493 | */ | ||
494 | int die_walk_instances(Dwarf_Die *or_die, int (*callback)(Dwarf_Die *, void *), | ||
495 | void *data) | ||
496 | { | ||
497 | Dwarf_Die cu_die; | ||
498 | Dwarf_Die die_mem; | ||
499 | struct __instance_walk_param iwp = { | ||
500 | .addr = or_die->addr, | ||
501 | .callback = callback, | ||
502 | .data = data, | ||
503 | .retval = -ENOENT, | ||
504 | }; | ||
505 | |||
506 | if (dwarf_diecu(or_die, &cu_die, NULL, NULL) == NULL) | ||
507 | return -ENOENT; | ||
508 | |||
509 | die_find_child(&cu_die, __die_walk_instances_cb, &iwp, &die_mem); | ||
510 | |||
511 | return iwp.retval; | ||
512 | } | ||
513 | |||
456 | /* Line walker internal parameters */ | 514 | /* Line walker internal parameters */ |
457 | struct __line_walk_param { | 515 | struct __line_walk_param { |
458 | bool recursive; | 516 | bool recursive; |
459 | line_walk_callback_t callback; | 517 | line_walk_callback_t callback; |
460 | void *data; | 518 | void *data; |
461 | int retval; | 519 | int retval; |
462 | }; | 520 | }; |
463 | 521 | ||
464 | static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) | 522 | static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) |
465 | { | 523 | { |
466 | struct __line_walk_param *lw = data; | 524 | struct __line_walk_param *lw = data; |
467 | Dwarf_Addr addr = 0; | 525 | Dwarf_Addr addr = 0; |
468 | const char *fname; | 526 | const char *fname; |
469 | int lineno; | 527 | int lineno; |
470 | 528 | ||
471 | if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { | 529 | if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { |
472 | fname = die_get_call_file(in_die); | 530 | fname = die_get_call_file(in_die); |
473 | lineno = die_get_call_lineno(in_die); | 531 | lineno = die_get_call_lineno(in_die); |
474 | if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { | 532 | if (fname && lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { |
475 | lw->retval = lw->callback(fname, lineno, addr, lw->data); | 533 | lw->retval = lw->callback(fname, lineno, addr, lw->data); |
476 | if (lw->retval != 0) | 534 | if (lw->retval != 0) |
477 | return DIE_FIND_CB_END; | 535 | return DIE_FIND_CB_END; |
478 | } | 536 | } |
479 | } | 537 | } |
480 | if (!lw->recursive) | 538 | if (!lw->recursive) |
481 | /* Don't need to search recursively */ | 539 | /* Don't need to search recursively */ |
482 | return DIE_FIND_CB_SIBLING; | 540 | return DIE_FIND_CB_SIBLING; |
483 | 541 | ||
484 | if (addr) { | 542 | if (addr) { |
485 | fname = dwarf_decl_file(in_die); | 543 | fname = dwarf_decl_file(in_die); |
486 | if (fname && dwarf_decl_line(in_die, &lineno) == 0) { | 544 | if (fname && dwarf_decl_line(in_die, &lineno) == 0) { |
487 | lw->retval = lw->callback(fname, lineno, addr, lw->data); | 545 | lw->retval = lw->callback(fname, lineno, addr, lw->data); |
488 | if (lw->retval != 0) | 546 | if (lw->retval != 0) |
489 | return DIE_FIND_CB_END; | 547 | return DIE_FIND_CB_END; |
490 | } | 548 | } |
491 | } | 549 | } |
492 | 550 | ||
493 | /* Continue to search nested inlined function call-sites */ | 551 | /* Continue to search nested inlined function call-sites */ |
494 | return DIE_FIND_CB_CONTINUE; | 552 | return DIE_FIND_CB_CONTINUE; |
495 | } | 553 | } |
496 | 554 | ||
497 | /* Walk on lines of blocks included in given DIE */ | 555 | /* Walk on lines of blocks included in given DIE */ |
498 | static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive, | 556 | static int __die_walk_funclines(Dwarf_Die *sp_die, bool recursive, |
499 | line_walk_callback_t callback, void *data) | 557 | line_walk_callback_t callback, void *data) |
500 | { | 558 | { |
501 | struct __line_walk_param lw = { | 559 | struct __line_walk_param lw = { |
502 | .recursive = recursive, | 560 | .recursive = recursive, |
503 | .callback = callback, | 561 | .callback = callback, |
504 | .data = data, | 562 | .data = data, |
505 | .retval = 0, | 563 | .retval = 0, |
506 | }; | 564 | }; |
507 | Dwarf_Die die_mem; | 565 | Dwarf_Die die_mem; |
508 | Dwarf_Addr addr; | 566 | Dwarf_Addr addr; |
509 | const char *fname; | 567 | const char *fname; |
510 | int lineno; | 568 | int lineno; |
511 | 569 | ||
512 | /* Handle function declaration line */ | 570 | /* Handle function declaration line */ |
513 | fname = dwarf_decl_file(sp_die); | 571 | fname = dwarf_decl_file(sp_die); |
514 | if (fname && dwarf_decl_line(sp_die, &lineno) == 0 && | 572 | if (fname && dwarf_decl_line(sp_die, &lineno) == 0 && |
515 | dwarf_entrypc(sp_die, &addr) == 0) { | 573 | dwarf_entrypc(sp_die, &addr) == 0) { |
516 | lw.retval = callback(fname, lineno, addr, data); | 574 | lw.retval = callback(fname, lineno, addr, data); |
517 | if (lw.retval != 0) | 575 | if (lw.retval != 0) |
518 | goto done; | 576 | goto done; |
519 | } | 577 | } |
520 | die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem); | 578 | die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem); |
521 | done: | 579 | done: |
522 | return lw.retval; | 580 | return lw.retval; |
523 | } | 581 | } |
524 | 582 | ||
525 | static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) | 583 | static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) |
526 | { | 584 | { |
527 | struct __line_walk_param *lw = data; | 585 | struct __line_walk_param *lw = data; |
528 | 586 | ||
529 | lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data); | 587 | lw->retval = __die_walk_funclines(sp_die, true, lw->callback, lw->data); |
530 | if (lw->retval != 0) | 588 | if (lw->retval != 0) |
531 | return DWARF_CB_ABORT; | 589 | return DWARF_CB_ABORT; |
532 | 590 | ||
533 | return DWARF_CB_OK; | 591 | return DWARF_CB_OK; |
534 | } | 592 | } |
535 | 593 | ||
536 | /** | 594 | /** |
537 | * die_walk_lines - Walk on lines inside given DIE | 595 | * die_walk_lines - Walk on lines inside given DIE |
538 | * @rt_die: a root DIE (CU, subprogram or inlined_subroutine) | 596 | * @rt_die: a root DIE (CU, subprogram or inlined_subroutine) |
539 | * @callback: callback routine | 597 | * @callback: callback routine |
540 | * @data: user data | 598 | * @data: user data |
541 | * | 599 | * |
542 | * Walk on all lines inside given @rt_die and call @callback on each line. | 600 | * Walk on all lines inside given @rt_die and call @callback on each line. |
543 | * If the @rt_die is a function, walk only on the lines inside the function, | 601 | * If the @rt_die is a function, walk only on the lines inside the function, |
544 | * otherwise @rt_die must be a CU DIE. | 602 | * otherwise @rt_die must be a CU DIE. |
545 | * Note that this walks not only dwarf line list, but also function entries | 603 | * Note that this walks not only dwarf line list, but also function entries |
546 | * and inline call-site. | 604 | * and inline call-site. |
547 | */ | 605 | */ |
548 | int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) | 606 | int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data) |
549 | { | 607 | { |
550 | Dwarf_Lines *lines; | 608 | Dwarf_Lines *lines; |
551 | Dwarf_Line *line; | 609 | Dwarf_Line *line; |
552 | Dwarf_Addr addr; | 610 | Dwarf_Addr addr; |
553 | const char *fname; | 611 | const char *fname; |
554 | int lineno, ret = 0; | 612 | int lineno, ret = 0; |
555 | Dwarf_Die die_mem, *cu_die; | 613 | Dwarf_Die die_mem, *cu_die; |
556 | size_t nlines, i; | 614 | size_t nlines, i; |
557 | 615 | ||
558 | /* Get the CU die */ | 616 | /* Get the CU die */ |
559 | if (dwarf_tag(rt_die) != DW_TAG_compile_unit) | 617 | if (dwarf_tag(rt_die) != DW_TAG_compile_unit) |
560 | cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL); | 618 | cu_die = dwarf_diecu(rt_die, &die_mem, NULL, NULL); |
561 | else | 619 | else |
562 | cu_die = rt_die; | 620 | cu_die = rt_die; |
563 | if (!cu_die) { | 621 | if (!cu_die) { |
564 | pr_debug2("Failed to get CU from given DIE.\n"); | 622 | pr_debug2("Failed to get CU from given DIE.\n"); |
565 | return -EINVAL; | 623 | return -EINVAL; |
566 | } | 624 | } |
567 | 625 | ||
568 | /* Get lines list in the CU */ | 626 | /* Get lines list in the CU */ |
569 | if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) { | 627 | if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) { |
570 | pr_debug2("Failed to get source lines on this CU.\n"); | 628 | pr_debug2("Failed to get source lines on this CU.\n"); |
571 | return -ENOENT; | 629 | return -ENOENT; |
572 | } | 630 | } |
573 | pr_debug2("Get %zd lines from this CU\n", nlines); | 631 | pr_debug2("Get %zd lines from this CU\n", nlines); |
574 | 632 | ||
575 | /* Walk on the lines on lines list */ | 633 | /* Walk on the lines on lines list */ |
576 | for (i = 0; i < nlines; i++) { | 634 | for (i = 0; i < nlines; i++) { |
577 | line = dwarf_onesrcline(lines, i); | 635 | line = dwarf_onesrcline(lines, i); |
578 | if (line == NULL || | 636 | if (line == NULL || |
579 | dwarf_lineno(line, &lineno) != 0 || | 637 | dwarf_lineno(line, &lineno) != 0 || |
580 | dwarf_lineaddr(line, &addr) != 0) { | 638 | dwarf_lineaddr(line, &addr) != 0) { |
581 | pr_debug2("Failed to get line info. " | 639 | pr_debug2("Failed to get line info. " |
582 | "Possible error in debuginfo.\n"); | 640 | "Possible error in debuginfo.\n"); |
583 | continue; | 641 | continue; |
584 | } | 642 | } |
585 | /* Filter lines based on address */ | 643 | /* Filter lines based on address */ |
586 | if (rt_die != cu_die) | 644 | if (rt_die != cu_die) |
587 | /* | 645 | /* |
588 | * Address filtering | 646 | * Address filtering |
589 | * The line is included in given function, and | 647 | * The line is included in given function, and |
590 | * no inline block includes it. | 648 | * no inline block includes it. |
591 | */ | 649 | */ |
592 | if (!dwarf_haspc(rt_die, addr) || | 650 | if (!dwarf_haspc(rt_die, addr) || |
593 | die_find_inlinefunc(rt_die, addr, &die_mem)) | 651 | die_find_inlinefunc(rt_die, addr, &die_mem)) |
594 | continue; | 652 | continue; |
595 | /* Get source line */ | 653 | /* Get source line */ |
596 | fname = dwarf_linesrc(line, NULL, NULL); | 654 | fname = dwarf_linesrc(line, NULL, NULL); |
597 | 655 | ||
598 | ret = callback(fname, lineno, addr, data); | 656 | ret = callback(fname, lineno, addr, data); |
599 | if (ret != 0) | 657 | if (ret != 0) |
600 | return ret; | 658 | return ret; |
601 | } | 659 | } |
602 | 660 | ||
603 | /* | 661 | /* |
604 | * Dwarf lines doesn't include function declarations and inlined | 662 | * Dwarf lines doesn't include function declarations and inlined |
605 | * subroutines. We have to check functions list or given function. | 663 | * subroutines. We have to check functions list or given function. |
606 | */ | 664 | */ |
607 | if (rt_die != cu_die) | 665 | if (rt_die != cu_die) |
608 | /* | 666 | /* |
609 | * Don't need walk functions recursively, because nested | 667 | * Don't need walk functions recursively, because nested |
610 | * inlined functions don't have lines of the specified DIE. | 668 | * inlined functions don't have lines of the specified DIE. |
611 | */ | 669 | */ |
612 | ret = __die_walk_funclines(rt_die, false, callback, data); | 670 | ret = __die_walk_funclines(rt_die, false, callback, data); |
613 | else { | 671 | else { |
614 | struct __line_walk_param param = { | 672 | struct __line_walk_param param = { |
615 | .callback = callback, | 673 | .callback = callback, |
616 | .data = data, | 674 | .data = data, |
617 | .retval = 0, | 675 | .retval = 0, |
618 | }; | 676 | }; |
619 | dwarf_getfuncs(cu_die, __die_walk_culines_cb, ¶m, 0); | 677 | dwarf_getfuncs(cu_die, __die_walk_culines_cb, ¶m, 0); |
620 | ret = param.retval; | 678 | ret = param.retval; |
621 | } | 679 | } |
622 | 680 | ||
623 | return ret; | 681 | return ret; |
624 | } | 682 | } |
625 | 683 | ||
626 | struct __find_variable_param { | 684 | struct __find_variable_param { |
627 | const char *name; | 685 | const char *name; |
628 | Dwarf_Addr addr; | 686 | Dwarf_Addr addr; |
629 | }; | 687 | }; |
630 | 688 | ||
631 | static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) | 689 | static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) |
632 | { | 690 | { |
633 | struct __find_variable_param *fvp = data; | 691 | struct __find_variable_param *fvp = data; |
634 | int tag; | 692 | int tag; |
635 | 693 | ||
636 | tag = dwarf_tag(die_mem); | 694 | tag = dwarf_tag(die_mem); |
637 | if ((tag == DW_TAG_formal_parameter || | 695 | if ((tag == DW_TAG_formal_parameter || |
638 | tag == DW_TAG_variable) && | 696 | tag == DW_TAG_variable) && |
639 | die_compare_name(die_mem, fvp->name)) | 697 | die_compare_name(die_mem, fvp->name)) |
640 | return DIE_FIND_CB_END; | 698 | return DIE_FIND_CB_END; |
641 | 699 | ||
642 | if (dwarf_haspc(die_mem, fvp->addr)) | 700 | if (dwarf_haspc(die_mem, fvp->addr)) |
643 | return DIE_FIND_CB_CONTINUE; | 701 | return DIE_FIND_CB_CONTINUE; |
644 | else | 702 | else |
645 | return DIE_FIND_CB_SIBLING; | 703 | return DIE_FIND_CB_SIBLING; |
646 | } | 704 | } |
647 | 705 | ||
648 | /** | 706 | /** |
649 | * die_find_variable_at - Find a given name variable at given address | 707 | * die_find_variable_at - Find a given name variable at given address |
650 | * @sp_die: a function DIE | 708 | * @sp_die: a function DIE |
651 | * @name: variable name | 709 | * @name: variable name |
652 | * @addr: address | 710 | * @addr: address |
653 | * @die_mem: a buffer for result DIE | 711 | * @die_mem: a buffer for result DIE |
654 | * | 712 | * |
655 | * Find a variable DIE called @name at @addr in @sp_die. | 713 | * Find a variable DIE called @name at @addr in @sp_die. |
656 | */ | 714 | */ |
657 | Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name, | 715 | Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name, |
658 | Dwarf_Addr addr, Dwarf_Die *die_mem) | 716 | Dwarf_Addr addr, Dwarf_Die *die_mem) |
659 | { | 717 | { |
660 | struct __find_variable_param fvp = { .name = name, .addr = addr}; | 718 | struct __find_variable_param fvp = { .name = name, .addr = addr}; |
661 | 719 | ||
662 | return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp, | 720 | return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp, |
663 | die_mem); | 721 | die_mem); |
664 | } | 722 | } |
665 | 723 | ||
666 | static int __die_find_member_cb(Dwarf_Die *die_mem, void *data) | 724 | static int __die_find_member_cb(Dwarf_Die *die_mem, void *data) |
667 | { | 725 | { |
668 | const char *name = data; | 726 | const char *name = data; |
669 | 727 | ||
670 | if ((dwarf_tag(die_mem) == DW_TAG_member) && | 728 | if ((dwarf_tag(die_mem) == DW_TAG_member) && |
671 | die_compare_name(die_mem, name)) | 729 | die_compare_name(die_mem, name)) |
672 | return DIE_FIND_CB_END; | 730 | return DIE_FIND_CB_END; |
673 | 731 | ||
674 | return DIE_FIND_CB_SIBLING; | 732 | return DIE_FIND_CB_SIBLING; |
675 | } | 733 | } |
676 | 734 | ||
677 | /** | 735 | /** |
678 | * die_find_member - Find a given name member in a data structure | 736 | * die_find_member - Find a given name member in a data structure |
679 | * @st_die: a data structure type DIE | 737 | * @st_die: a data structure type DIE |
680 | * @name: member name | 738 | * @name: member name |
681 | * @die_mem: a buffer for result DIE | 739 | * @die_mem: a buffer for result DIE |
682 | * | 740 | * |
683 | * Find a member DIE called @name in @st_die. | 741 | * Find a member DIE called @name in @st_die. |
684 | */ | 742 | */ |
685 | Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, | 743 | Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, |
686 | Dwarf_Die *die_mem) | 744 | Dwarf_Die *die_mem) |
687 | { | 745 | { |
688 | return die_find_child(st_die, __die_find_member_cb, (void *)name, | 746 | return die_find_child(st_die, __die_find_member_cb, (void *)name, |
689 | die_mem); | 747 | die_mem); |
690 | } | 748 | } |
691 | 749 | ||
692 | /** | 750 | /** |
693 | * die_get_typename - Get the name of given variable DIE | 751 | * die_get_typename - Get the name of given variable DIE |
694 | * @vr_die: a variable DIE | 752 | * @vr_die: a variable DIE |
695 | * @buf: a buffer for result type name | 753 | * @buf: a buffer for result type name |
696 | * @len: a max-length of @buf | 754 | * @len: a max-length of @buf |
697 | * | 755 | * |
698 | * Get the name of @vr_die and stores it to @buf. Return the actual length | 756 | * Get the name of @vr_die and stores it to @buf. Return the actual length |
699 | * of type name if succeeded. Return -E2BIG if @len is not enough long, and | 757 | * of type name if succeeded. Return -E2BIG if @len is not enough long, and |
700 | * Return -ENOENT if failed to find type name. | 758 | * Return -ENOENT if failed to find type name. |
701 | * Note that the result will stores typedef name if possible, and stores | 759 | * Note that the result will stores typedef name if possible, and stores |
702 | * "*(function_type)" if the type is a function pointer. | 760 | * "*(function_type)" if the type is a function pointer. |
703 | */ | 761 | */ |
704 | int die_get_typename(Dwarf_Die *vr_die, char *buf, int len) | 762 | int die_get_typename(Dwarf_Die *vr_die, char *buf, int len) |
705 | { | 763 | { |
706 | Dwarf_Die type; | 764 | Dwarf_Die type; |
707 | int tag, ret, ret2; | 765 | int tag, ret, ret2; |
708 | const char *tmp = ""; | 766 | const char *tmp = ""; |
709 | 767 | ||
710 | if (__die_get_real_type(vr_die, &type) == NULL) | 768 | if (__die_get_real_type(vr_die, &type) == NULL) |
711 | return -ENOENT; | 769 | return -ENOENT; |
712 | 770 | ||
713 | tag = dwarf_tag(&type); | 771 | tag = dwarf_tag(&type); |
714 | if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type) | 772 | if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type) |
715 | tmp = "*"; | 773 | tmp = "*"; |
716 | else if (tag == DW_TAG_subroutine_type) { | 774 | else if (tag == DW_TAG_subroutine_type) { |
717 | /* Function pointer */ | 775 | /* Function pointer */ |
718 | ret = snprintf(buf, len, "(function_type)"); | 776 | ret = snprintf(buf, len, "(function_type)"); |
719 | return (ret >= len) ? -E2BIG : ret; | 777 | return (ret >= len) ? -E2BIG : ret; |
720 | } else { | 778 | } else { |
721 | if (!dwarf_diename(&type)) | 779 | if (!dwarf_diename(&type)) |
722 | return -ENOENT; | 780 | return -ENOENT; |
723 | if (tag == DW_TAG_union_type) | 781 | if (tag == DW_TAG_union_type) |
724 | tmp = "union "; | 782 | tmp = "union "; |
725 | else if (tag == DW_TAG_structure_type) | 783 | else if (tag == DW_TAG_structure_type) |
726 | tmp = "struct "; | 784 | tmp = "struct "; |
727 | /* Write a base name */ | 785 | /* Write a base name */ |
728 | ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type)); | 786 | ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type)); |
729 | return (ret >= len) ? -E2BIG : ret; | 787 | return (ret >= len) ? -E2BIG : ret; |
730 | } | 788 | } |
731 | ret = die_get_typename(&type, buf, len); | 789 | ret = die_get_typename(&type, buf, len); |
732 | if (ret > 0) { | 790 | if (ret > 0) { |
733 | ret2 = snprintf(buf + ret, len - ret, "%s", tmp); | 791 | ret2 = snprintf(buf + ret, len - ret, "%s", tmp); |
734 | ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret; | 792 | ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret; |
735 | } | 793 | } |
736 | return ret; | 794 | return ret; |
737 | } | 795 | } |
738 | 796 | ||
739 | /** | 797 | /** |
740 | * die_get_varname - Get the name and type of given variable DIE | 798 | * die_get_varname - Get the name and type of given variable DIE |
741 | * @vr_die: a variable DIE | 799 | * @vr_die: a variable DIE |
742 | * @buf: a buffer for type and variable name | 800 | * @buf: a buffer for type and variable name |
743 | * @len: the max-length of @buf | 801 | * @len: the max-length of @buf |
744 | * | 802 | * |
745 | * Get the name and type of @vr_die and stores it in @buf as "type\tname". | 803 | * Get the name and type of @vr_die and stores it in @buf as "type\tname". |
746 | */ | 804 | */ |
747 | int die_get_varname(Dwarf_Die *vr_die, char *buf, int len) | 805 | int die_get_varname(Dwarf_Die *vr_die, char *buf, int len) |
748 | { | 806 | { |
749 | int ret, ret2; | 807 | int ret, ret2; |
750 | 808 | ||
751 | ret = die_get_typename(vr_die, buf, len); | 809 | ret = die_get_typename(vr_die, buf, len); |
752 | if (ret < 0) { | 810 | if (ret < 0) { |
753 | pr_debug("Failed to get type, make it unknown.\n"); | 811 | pr_debug("Failed to get type, make it unknown.\n"); |
754 | ret = snprintf(buf, len, "(unknown_type)"); | 812 | ret = snprintf(buf, len, "(unknown_type)"); |
755 | } | 813 | } |
756 | if (ret > 0) { | 814 | if (ret > 0) { |
757 | ret2 = snprintf(buf + ret, len - ret, "\t%s", | 815 | ret2 = snprintf(buf + ret, len - ret, "\t%s", |
758 | dwarf_diename(vr_die)); | 816 | dwarf_diename(vr_die)); |
759 | ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret; | 817 | ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret; |
760 | } | 818 | } |
761 | return ret; | 819 | return ret; |
762 | } | 820 | } |
763 | 821 | ||
764 | 822 |
tools/perf/util/dwarf-aux.h
1 | #ifndef _DWARF_AUX_H | 1 | #ifndef _DWARF_AUX_H |
2 | #define _DWARF_AUX_H | 2 | #define _DWARF_AUX_H |
3 | /* | 3 | /* |
4 | * dwarf-aux.h : libdw auxiliary interfaces | 4 | * dwarf-aux.h : libdw auxiliary interfaces |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or | 8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
15 | * | 15 | * |
16 | * You should have received a copy of the GNU General Public License | 16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <dwarf.h> | 22 | #include <dwarf.h> |
23 | #include <elfutils/libdw.h> | 23 | #include <elfutils/libdw.h> |
24 | #include <elfutils/libdwfl.h> | 24 | #include <elfutils/libdwfl.h> |
25 | #include <elfutils/version.h> | 25 | #include <elfutils/version.h> |
26 | 26 | ||
27 | /* Find the realpath of the target file */ | 27 | /* Find the realpath of the target file */ |
28 | extern const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname); | 28 | extern const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname); |
29 | 29 | ||
30 | /* Get DW_AT_comp_dir (should be NULL with older gcc) */ | 30 | /* Get DW_AT_comp_dir (should be NULL with older gcc) */ |
31 | extern const char *cu_get_comp_dir(Dwarf_Die *cu_die); | 31 | extern const char *cu_get_comp_dir(Dwarf_Die *cu_die); |
32 | 32 | ||
33 | /* Get a line number and file name for given address */ | 33 | /* Get a line number and file name for given address */ |
34 | extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, | 34 | extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, |
35 | const char **fname, int *lineno); | 35 | const char **fname, int *lineno); |
36 | 36 | ||
37 | /* Walk on funcitons at given address */ | 37 | /* Walk on funcitons at given address */ |
38 | extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, | 38 | extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, |
39 | int (*callback)(Dwarf_Die *, void *), void *data); | 39 | int (*callback)(Dwarf_Die *, void *), void *data); |
40 | 40 | ||
41 | /* Compare diename and tname */ | 41 | /* Compare diename and tname */ |
42 | extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); | 42 | extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); |
43 | 43 | ||
44 | /* Get callsite line number of inline-function instance */ | 44 | /* Get callsite line number of inline-function instance */ |
45 | extern int die_get_call_lineno(Dwarf_Die *in_die); | 45 | extern int die_get_call_lineno(Dwarf_Die *in_die); |
46 | 46 | ||
47 | /* Get callsite file name of inlined function instance */ | 47 | /* Get callsite file name of inlined function instance */ |
48 | extern const char *die_get_call_file(Dwarf_Die *in_die); | 48 | extern const char *die_get_call_file(Dwarf_Die *in_die); |
49 | 49 | ||
50 | /* Get type die */ | 50 | /* Get type die */ |
51 | extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); | 51 | extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); |
52 | 52 | ||
53 | /* Get a type die, but skip qualifiers and typedef */ | 53 | /* Get a type die, but skip qualifiers and typedef */ |
54 | extern Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); | 54 | extern Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); |
55 | 55 | ||
56 | /* Check whether the DIE is signed or not */ | 56 | /* Check whether the DIE is signed or not */ |
57 | extern bool die_is_signed_type(Dwarf_Die *tp_die); | 57 | extern bool die_is_signed_type(Dwarf_Die *tp_die); |
58 | 58 | ||
59 | /* Get data_member_location offset */ | 59 | /* Get data_member_location offset */ |
60 | extern int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs); | 60 | extern int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs); |
61 | 61 | ||
62 | /* Return values for die_find_child() callbacks */ | 62 | /* Return values for die_find_child() callbacks */ |
63 | enum { | 63 | enum { |
64 | DIE_FIND_CB_END = 0, /* End of Search */ | 64 | DIE_FIND_CB_END = 0, /* End of Search */ |
65 | DIE_FIND_CB_CHILD = 1, /* Search only children */ | 65 | DIE_FIND_CB_CHILD = 1, /* Search only children */ |
66 | DIE_FIND_CB_SIBLING = 2, /* Search only siblings */ | 66 | DIE_FIND_CB_SIBLING = 2, /* Search only siblings */ |
67 | DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */ | 67 | DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */ |
68 | }; | 68 | }; |
69 | 69 | ||
70 | /* Search child DIEs */ | 70 | /* Search child DIEs */ |
71 | extern Dwarf_Die *die_find_child(Dwarf_Die *rt_die, | 71 | extern Dwarf_Die *die_find_child(Dwarf_Die *rt_die, |
72 | int (*callback)(Dwarf_Die *, void *), | 72 | int (*callback)(Dwarf_Die *, void *), |
73 | void *data, Dwarf_Die *die_mem); | 73 | void *data, Dwarf_Die *die_mem); |
74 | 74 | ||
75 | /* Search a non-inlined function including given address */ | 75 | /* Search a non-inlined function including given address */ |
76 | extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, | 76 | extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, |
77 | Dwarf_Die *die_mem); | 77 | Dwarf_Die *die_mem); |
78 | 78 | ||
79 | /* Search an inlined function including given address */ | 79 | /* Search an inlined function including given address */ |
80 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 80 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
81 | Dwarf_Die *die_mem); | 81 | Dwarf_Die *die_mem); |
82 | 82 | ||
83 | /* Walk on the instances of given DIE */ | ||
84 | extern int die_walk_instances(Dwarf_Die *in_die, | ||
85 | int (*callback)(Dwarf_Die *, void *), void *data); | ||
86 | |||
83 | /* Walker on lines (Note: line number will not be sorted) */ | 87 | /* Walker on lines (Note: line number will not be sorted) */ |
84 | typedef int (* line_walk_callback_t) (const char *fname, int lineno, | 88 | typedef int (* line_walk_callback_t) (const char *fname, int lineno, |
85 | Dwarf_Addr addr, void *data); | 89 | Dwarf_Addr addr, void *data); |
86 | 90 | ||
87 | /* | 91 | /* |
88 | * Walk on lines inside given DIE. If the DIE is a subprogram, walk only on | 92 | * Walk on lines inside given DIE. If the DIE is a subprogram, walk only on |
89 | * the lines inside the subprogram, otherwise the DIE must be a CU DIE. | 93 | * the lines inside the subprogram, otherwise the DIE must be a CU DIE. |
90 | */ | 94 | */ |
91 | extern int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, | 95 | extern int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, |
92 | void *data); | 96 | void *data); |
93 | 97 | ||
94 | /* Find a variable called 'name' at given address */ | 98 | /* Find a variable called 'name' at given address */ |
95 | extern Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name, | 99 | extern Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name, |
96 | Dwarf_Addr addr, Dwarf_Die *die_mem); | 100 | Dwarf_Addr addr, Dwarf_Die *die_mem); |
97 | 101 | ||
98 | /* Find a member called 'name' */ | 102 | /* Find a member called 'name' */ |
99 | extern Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, | 103 | extern Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, |
100 | Dwarf_Die *die_mem); | 104 | Dwarf_Die *die_mem); |
101 | 105 | ||
102 | /* Get the name of given variable DIE */ | 106 | /* Get the name of given variable DIE */ |
103 | extern int die_get_typename(Dwarf_Die *vr_die, char *buf, int len); | 107 | extern int die_get_typename(Dwarf_Die *vr_die, char *buf, int len); |
104 | 108 | ||
105 | /* Get the name and type of given variable DIE, stored as "type\tname" */ | 109 | /* Get the name and type of given variable DIE, stored as "type\tname" */ |
106 | extern int die_get_varname(Dwarf_Die *vr_die, char *buf, int len); | 110 | extern int die_get_varname(Dwarf_Die *vr_die, char *buf, int len); |
107 | #endif | 111 | #endif |
108 | 112 |
tools/perf/util/probe-finder.c
1 | /* | 1 | /* |
2 | * probe-finder.c : C expression to kprobe event converter | 2 | * probe-finder.c : C expression to kprobe event converter |
3 | * | 3 | * |
4 | * Written by Masami Hiramatsu <mhiramat@redhat.com> | 4 | * Written by Masami Hiramatsu <mhiramat@redhat.com> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or | 8 | * the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. | 9 | * (at your option) any later version. |
10 | * | 10 | * |
11 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. | 14 | * GNU General Public License for more details. |
15 | * | 15 | * |
16 | * You should have received a copy of the GNU General Public License | 16 | * You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software | 17 | * along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <sys/utsname.h> | 22 | #include <sys/utsname.h> |
23 | #include <sys/types.h> | 23 | #include <sys/types.h> |
24 | #include <sys/stat.h> | 24 | #include <sys/stat.h> |
25 | #include <fcntl.h> | 25 | #include <fcntl.h> |
26 | #include <errno.h> | 26 | #include <errno.h> |
27 | #include <stdio.h> | 27 | #include <stdio.h> |
28 | #include <unistd.h> | 28 | #include <unistd.h> |
29 | #include <getopt.h> | 29 | #include <getopt.h> |
30 | #include <stdlib.h> | 30 | #include <stdlib.h> |
31 | #include <string.h> | 31 | #include <string.h> |
32 | #include <stdarg.h> | 32 | #include <stdarg.h> |
33 | #include <ctype.h> | 33 | #include <ctype.h> |
34 | #include <dwarf-regs.h> | 34 | #include <dwarf-regs.h> |
35 | 35 | ||
36 | #include <linux/bitops.h> | 36 | #include <linux/bitops.h> |
37 | #include "event.h" | 37 | #include "event.h" |
38 | #include "debug.h" | 38 | #include "debug.h" |
39 | #include "util.h" | 39 | #include "util.h" |
40 | #include "symbol.h" | 40 | #include "symbol.h" |
41 | #include "probe-finder.h" | 41 | #include "probe-finder.h" |
42 | 42 | ||
43 | /* Kprobe tracer basic type is up to u64 */ | 43 | /* Kprobe tracer basic type is up to u64 */ |
44 | #define MAX_BASIC_TYPE_BITS 64 | 44 | #define MAX_BASIC_TYPE_BITS 64 |
45 | 45 | ||
46 | /* Line number list operations */ | 46 | /* Line number list operations */ |
47 | 47 | ||
48 | /* Add a line to line number list */ | 48 | /* Add a line to line number list */ |
49 | static int line_list__add_line(struct list_head *head, int line) | 49 | static int line_list__add_line(struct list_head *head, int line) |
50 | { | 50 | { |
51 | struct line_node *ln; | 51 | struct line_node *ln; |
52 | struct list_head *p; | 52 | struct list_head *p; |
53 | 53 | ||
54 | /* Reverse search, because new line will be the last one */ | 54 | /* Reverse search, because new line will be the last one */ |
55 | list_for_each_entry_reverse(ln, head, list) { | 55 | list_for_each_entry_reverse(ln, head, list) { |
56 | if (ln->line < line) { | 56 | if (ln->line < line) { |
57 | p = &ln->list; | 57 | p = &ln->list; |
58 | goto found; | 58 | goto found; |
59 | } else if (ln->line == line) /* Already exist */ | 59 | } else if (ln->line == line) /* Already exist */ |
60 | return 1; | 60 | return 1; |
61 | } | 61 | } |
62 | /* List is empty, or the smallest entry */ | 62 | /* List is empty, or the smallest entry */ |
63 | p = head; | 63 | p = head; |
64 | found: | 64 | found: |
65 | pr_debug("line list: add a line %u\n", line); | 65 | pr_debug("line list: add a line %u\n", line); |
66 | ln = zalloc(sizeof(struct line_node)); | 66 | ln = zalloc(sizeof(struct line_node)); |
67 | if (ln == NULL) | 67 | if (ln == NULL) |
68 | return -ENOMEM; | 68 | return -ENOMEM; |
69 | ln->line = line; | 69 | ln->line = line; |
70 | INIT_LIST_HEAD(&ln->list); | 70 | INIT_LIST_HEAD(&ln->list); |
71 | list_add(&ln->list, p); | 71 | list_add(&ln->list, p); |
72 | return 0; | 72 | return 0; |
73 | } | 73 | } |
74 | 74 | ||
75 | /* Check if the line in line number list */ | 75 | /* Check if the line in line number list */ |
76 | static int line_list__has_line(struct list_head *head, int line) | 76 | static int line_list__has_line(struct list_head *head, int line) |
77 | { | 77 | { |
78 | struct line_node *ln; | 78 | struct line_node *ln; |
79 | 79 | ||
80 | /* Reverse search, because new line will be the last one */ | 80 | /* Reverse search, because new line will be the last one */ |
81 | list_for_each_entry(ln, head, list) | 81 | list_for_each_entry(ln, head, list) |
82 | if (ln->line == line) | 82 | if (ln->line == line) |
83 | return 1; | 83 | return 1; |
84 | 84 | ||
85 | return 0; | 85 | return 0; |
86 | } | 86 | } |
87 | 87 | ||
88 | /* Init line number list */ | 88 | /* Init line number list */ |
89 | static void line_list__init(struct list_head *head) | 89 | static void line_list__init(struct list_head *head) |
90 | { | 90 | { |
91 | INIT_LIST_HEAD(head); | 91 | INIT_LIST_HEAD(head); |
92 | } | 92 | } |
93 | 93 | ||
94 | /* Free line number list */ | 94 | /* Free line number list */ |
95 | static void line_list__free(struct list_head *head) | 95 | static void line_list__free(struct list_head *head) |
96 | { | 96 | { |
97 | struct line_node *ln; | 97 | struct line_node *ln; |
98 | while (!list_empty(head)) { | 98 | while (!list_empty(head)) { |
99 | ln = list_first_entry(head, struct line_node, list); | 99 | ln = list_first_entry(head, struct line_node, list); |
100 | list_del(&ln->list); | 100 | list_del(&ln->list); |
101 | free(ln); | 101 | free(ln); |
102 | } | 102 | } |
103 | } | 103 | } |
104 | 104 | ||
105 | /* Dwarf FL wrappers */ | 105 | /* Dwarf FL wrappers */ |
106 | static char *debuginfo_path; /* Currently dummy */ | 106 | static char *debuginfo_path; /* Currently dummy */ |
107 | 107 | ||
108 | static const Dwfl_Callbacks offline_callbacks = { | 108 | static const Dwfl_Callbacks offline_callbacks = { |
109 | .find_debuginfo = dwfl_standard_find_debuginfo, | 109 | .find_debuginfo = dwfl_standard_find_debuginfo, |
110 | .debuginfo_path = &debuginfo_path, | 110 | .debuginfo_path = &debuginfo_path, |
111 | 111 | ||
112 | .section_address = dwfl_offline_section_address, | 112 | .section_address = dwfl_offline_section_address, |
113 | 113 | ||
114 | /* We use this table for core files too. */ | 114 | /* We use this table for core files too. */ |
115 | .find_elf = dwfl_build_id_find_elf, | 115 | .find_elf = dwfl_build_id_find_elf, |
116 | }; | 116 | }; |
117 | 117 | ||
118 | /* Get a Dwarf from offline image */ | 118 | /* Get a Dwarf from offline image */ |
119 | static int debuginfo__init_offline_dwarf(struct debuginfo *self, | 119 | static int debuginfo__init_offline_dwarf(struct debuginfo *self, |
120 | const char *path) | 120 | const char *path) |
121 | { | 121 | { |
122 | Dwfl_Module *mod; | 122 | Dwfl_Module *mod; |
123 | int fd; | 123 | int fd; |
124 | 124 | ||
125 | fd = open(path, O_RDONLY); | 125 | fd = open(path, O_RDONLY); |
126 | if (fd < 0) | 126 | if (fd < 0) |
127 | return fd; | 127 | return fd; |
128 | 128 | ||
129 | self->dwfl = dwfl_begin(&offline_callbacks); | 129 | self->dwfl = dwfl_begin(&offline_callbacks); |
130 | if (!self->dwfl) | 130 | if (!self->dwfl) |
131 | goto error; | 131 | goto error; |
132 | 132 | ||
133 | mod = dwfl_report_offline(self->dwfl, "", "", fd); | 133 | mod = dwfl_report_offline(self->dwfl, "", "", fd); |
134 | if (!mod) | 134 | if (!mod) |
135 | goto error; | 135 | goto error; |
136 | 136 | ||
137 | self->dbg = dwfl_module_getdwarf(mod, &self->bias); | 137 | self->dbg = dwfl_module_getdwarf(mod, &self->bias); |
138 | if (!self->dbg) | 138 | if (!self->dbg) |
139 | goto error; | 139 | goto error; |
140 | 140 | ||
141 | return 0; | 141 | return 0; |
142 | error: | 142 | error: |
143 | if (self->dwfl) | 143 | if (self->dwfl) |
144 | dwfl_end(self->dwfl); | 144 | dwfl_end(self->dwfl); |
145 | else | 145 | else |
146 | close(fd); | 146 | close(fd); |
147 | memset(self, 0, sizeof(*self)); | 147 | memset(self, 0, sizeof(*self)); |
148 | 148 | ||
149 | return -ENOENT; | 149 | return -ENOENT; |
150 | } | 150 | } |
151 | 151 | ||
152 | #if _ELFUTILS_PREREQ(0, 148) | 152 | #if _ELFUTILS_PREREQ(0, 148) |
153 | /* This method is buggy if elfutils is older than 0.148 */ | 153 | /* This method is buggy if elfutils is older than 0.148 */ |
154 | static int __linux_kernel_find_elf(Dwfl_Module *mod, | 154 | static int __linux_kernel_find_elf(Dwfl_Module *mod, |
155 | void **userdata, | 155 | void **userdata, |
156 | const char *module_name, | 156 | const char *module_name, |
157 | Dwarf_Addr base, | 157 | Dwarf_Addr base, |
158 | char **file_name, Elf **elfp) | 158 | char **file_name, Elf **elfp) |
159 | { | 159 | { |
160 | int fd; | 160 | int fd; |
161 | const char *path = kernel_get_module_path(module_name); | 161 | const char *path = kernel_get_module_path(module_name); |
162 | 162 | ||
163 | pr_debug2("Use file %s for %s\n", path, module_name); | 163 | pr_debug2("Use file %s for %s\n", path, module_name); |
164 | if (path) { | 164 | if (path) { |
165 | fd = open(path, O_RDONLY); | 165 | fd = open(path, O_RDONLY); |
166 | if (fd >= 0) { | 166 | if (fd >= 0) { |
167 | *file_name = strdup(path); | 167 | *file_name = strdup(path); |
168 | return fd; | 168 | return fd; |
169 | } | 169 | } |
170 | } | 170 | } |
171 | /* If failed, try to call standard method */ | 171 | /* If failed, try to call standard method */ |
172 | return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base, | 172 | return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base, |
173 | file_name, elfp); | 173 | file_name, elfp); |
174 | } | 174 | } |
175 | 175 | ||
176 | static const Dwfl_Callbacks kernel_callbacks = { | 176 | static const Dwfl_Callbacks kernel_callbacks = { |
177 | .find_debuginfo = dwfl_standard_find_debuginfo, | 177 | .find_debuginfo = dwfl_standard_find_debuginfo, |
178 | .debuginfo_path = &debuginfo_path, | 178 | .debuginfo_path = &debuginfo_path, |
179 | 179 | ||
180 | .find_elf = __linux_kernel_find_elf, | 180 | .find_elf = __linux_kernel_find_elf, |
181 | .section_address = dwfl_linux_kernel_module_section_address, | 181 | .section_address = dwfl_linux_kernel_module_section_address, |
182 | }; | 182 | }; |
183 | 183 | ||
184 | /* Get a Dwarf from live kernel image */ | 184 | /* Get a Dwarf from live kernel image */ |
185 | static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, | 185 | static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, |
186 | Dwarf_Addr addr) | 186 | Dwarf_Addr addr) |
187 | { | 187 | { |
188 | self->dwfl = dwfl_begin(&kernel_callbacks); | 188 | self->dwfl = dwfl_begin(&kernel_callbacks); |
189 | if (!self->dwfl) | 189 | if (!self->dwfl) |
190 | return -EINVAL; | 190 | return -EINVAL; |
191 | 191 | ||
192 | /* Load the kernel dwarves: Don't care the result here */ | 192 | /* Load the kernel dwarves: Don't care the result here */ |
193 | dwfl_linux_kernel_report_kernel(self->dwfl); | 193 | dwfl_linux_kernel_report_kernel(self->dwfl); |
194 | dwfl_linux_kernel_report_modules(self->dwfl); | 194 | dwfl_linux_kernel_report_modules(self->dwfl); |
195 | 195 | ||
196 | self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias); | 196 | self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias); |
197 | /* Here, check whether we could get a real dwarf */ | 197 | /* Here, check whether we could get a real dwarf */ |
198 | if (!self->dbg) { | 198 | if (!self->dbg) { |
199 | pr_debug("Failed to find kernel dwarf at %lx\n", | 199 | pr_debug("Failed to find kernel dwarf at %lx\n", |
200 | (unsigned long)addr); | 200 | (unsigned long)addr); |
201 | dwfl_end(self->dwfl); | 201 | dwfl_end(self->dwfl); |
202 | memset(self, 0, sizeof(*self)); | 202 | memset(self, 0, sizeof(*self)); |
203 | return -ENOENT; | 203 | return -ENOENT; |
204 | } | 204 | } |
205 | 205 | ||
206 | return 0; | 206 | return 0; |
207 | } | 207 | } |
208 | #else | 208 | #else |
209 | /* With older elfutils, this just support kernel module... */ | 209 | /* With older elfutils, this just support kernel module... */ |
210 | static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, | 210 | static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, |
211 | Dwarf_Addr addr __used) | 211 | Dwarf_Addr addr __used) |
212 | { | 212 | { |
213 | const char *path = kernel_get_module_path("kernel"); | 213 | const char *path = kernel_get_module_path("kernel"); |
214 | 214 | ||
215 | if (!path) { | 215 | if (!path) { |
216 | pr_err("Failed to find vmlinux path\n"); | 216 | pr_err("Failed to find vmlinux path\n"); |
217 | return -ENOENT; | 217 | return -ENOENT; |
218 | } | 218 | } |
219 | 219 | ||
220 | pr_debug2("Use file %s for debuginfo\n", path); | 220 | pr_debug2("Use file %s for debuginfo\n", path); |
221 | return debuginfo__init_offline_dwarf(self, path); | 221 | return debuginfo__init_offline_dwarf(self, path); |
222 | } | 222 | } |
223 | #endif | 223 | #endif |
224 | 224 | ||
225 | struct debuginfo *debuginfo__new(const char *path) | 225 | struct debuginfo *debuginfo__new(const char *path) |
226 | { | 226 | { |
227 | struct debuginfo *self = zalloc(sizeof(struct debuginfo)); | 227 | struct debuginfo *self = zalloc(sizeof(struct debuginfo)); |
228 | if (!self) | 228 | if (!self) |
229 | return NULL; | 229 | return NULL; |
230 | 230 | ||
231 | if (debuginfo__init_offline_dwarf(self, path) < 0) { | 231 | if (debuginfo__init_offline_dwarf(self, path) < 0) { |
232 | free(self); | 232 | free(self); |
233 | self = NULL; | 233 | self = NULL; |
234 | } | 234 | } |
235 | 235 | ||
236 | return self; | 236 | return self; |
237 | } | 237 | } |
238 | 238 | ||
239 | struct debuginfo *debuginfo__new_online_kernel(unsigned long addr) | 239 | struct debuginfo *debuginfo__new_online_kernel(unsigned long addr) |
240 | { | 240 | { |
241 | struct debuginfo *self = zalloc(sizeof(struct debuginfo)); | 241 | struct debuginfo *self = zalloc(sizeof(struct debuginfo)); |
242 | if (!self) | 242 | if (!self) |
243 | return NULL; | 243 | return NULL; |
244 | 244 | ||
245 | if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) { | 245 | if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) { |
246 | free(self); | 246 | free(self); |
247 | self = NULL; | 247 | self = NULL; |
248 | } | 248 | } |
249 | 249 | ||
250 | return self; | 250 | return self; |
251 | } | 251 | } |
252 | 252 | ||
253 | void debuginfo__delete(struct debuginfo *self) | 253 | void debuginfo__delete(struct debuginfo *self) |
254 | { | 254 | { |
255 | if (self) { | 255 | if (self) { |
256 | if (self->dwfl) | 256 | if (self->dwfl) |
257 | dwfl_end(self->dwfl); | 257 | dwfl_end(self->dwfl); |
258 | free(self); | 258 | free(self); |
259 | } | 259 | } |
260 | } | 260 | } |
261 | 261 | ||
262 | /* | 262 | /* |
263 | * Probe finder related functions | 263 | * Probe finder related functions |
264 | */ | 264 | */ |
265 | 265 | ||
266 | static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) | 266 | static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) |
267 | { | 267 | { |
268 | struct probe_trace_arg_ref *ref; | 268 | struct probe_trace_arg_ref *ref; |
269 | ref = zalloc(sizeof(struct probe_trace_arg_ref)); | 269 | ref = zalloc(sizeof(struct probe_trace_arg_ref)); |
270 | if (ref != NULL) | 270 | if (ref != NULL) |
271 | ref->offset = offs; | 271 | ref->offset = offs; |
272 | return ref; | 272 | return ref; |
273 | } | 273 | } |
274 | 274 | ||
275 | /* | 275 | /* |
276 | * Convert a location into trace_arg. | 276 | * Convert a location into trace_arg. |
277 | * If tvar == NULL, this just checks variable can be converted. | 277 | * If tvar == NULL, this just checks variable can be converted. |
278 | */ | 278 | */ |
279 | static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, | 279 | static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, |
280 | Dwarf_Op *fb_ops, | 280 | Dwarf_Op *fb_ops, |
281 | struct probe_trace_arg *tvar) | 281 | struct probe_trace_arg *tvar) |
282 | { | 282 | { |
283 | Dwarf_Attribute attr; | 283 | Dwarf_Attribute attr; |
284 | Dwarf_Op *op; | 284 | Dwarf_Op *op; |
285 | size_t nops; | 285 | size_t nops; |
286 | unsigned int regn; | 286 | unsigned int regn; |
287 | Dwarf_Word offs = 0; | 287 | Dwarf_Word offs = 0; |
288 | bool ref = false; | 288 | bool ref = false; |
289 | const char *regs; | 289 | const char *regs; |
290 | int ret; | 290 | int ret; |
291 | 291 | ||
292 | if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) | 292 | if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) |
293 | goto static_var; | 293 | goto static_var; |
294 | 294 | ||
295 | /* TODO: handle more than 1 exprs */ | 295 | /* TODO: handle more than 1 exprs */ |
296 | if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || | 296 | if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || |
297 | dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 || | 297 | dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 || |
298 | nops == 0) { | 298 | nops == 0) { |
299 | /* TODO: Support const_value */ | 299 | /* TODO: Support const_value */ |
300 | return -ENOENT; | 300 | return -ENOENT; |
301 | } | 301 | } |
302 | 302 | ||
303 | if (op->atom == DW_OP_addr) { | 303 | if (op->atom == DW_OP_addr) { |
304 | static_var: | 304 | static_var: |
305 | if (!tvar) | 305 | if (!tvar) |
306 | return 0; | 306 | return 0; |
307 | /* Static variables on memory (not stack), make @varname */ | 307 | /* Static variables on memory (not stack), make @varname */ |
308 | ret = strlen(dwarf_diename(vr_die)); | 308 | ret = strlen(dwarf_diename(vr_die)); |
309 | tvar->value = zalloc(ret + 2); | 309 | tvar->value = zalloc(ret + 2); |
310 | if (tvar->value == NULL) | 310 | if (tvar->value == NULL) |
311 | return -ENOMEM; | 311 | return -ENOMEM; |
312 | snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); | 312 | snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die)); |
313 | tvar->ref = alloc_trace_arg_ref((long)offs); | 313 | tvar->ref = alloc_trace_arg_ref((long)offs); |
314 | if (tvar->ref == NULL) | 314 | if (tvar->ref == NULL) |
315 | return -ENOMEM; | 315 | return -ENOMEM; |
316 | return 0; | 316 | return 0; |
317 | } | 317 | } |
318 | 318 | ||
319 | /* If this is based on frame buffer, set the offset */ | 319 | /* If this is based on frame buffer, set the offset */ |
320 | if (op->atom == DW_OP_fbreg) { | 320 | if (op->atom == DW_OP_fbreg) { |
321 | if (fb_ops == NULL) | 321 | if (fb_ops == NULL) |
322 | return -ENOTSUP; | 322 | return -ENOTSUP; |
323 | ref = true; | 323 | ref = true; |
324 | offs = op->number; | 324 | offs = op->number; |
325 | op = &fb_ops[0]; | 325 | op = &fb_ops[0]; |
326 | } | 326 | } |
327 | 327 | ||
328 | if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { | 328 | if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { |
329 | regn = op->atom - DW_OP_breg0; | 329 | regn = op->atom - DW_OP_breg0; |
330 | offs += op->number; | 330 | offs += op->number; |
331 | ref = true; | 331 | ref = true; |
332 | } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { | 332 | } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { |
333 | regn = op->atom - DW_OP_reg0; | 333 | regn = op->atom - DW_OP_reg0; |
334 | } else if (op->atom == DW_OP_bregx) { | 334 | } else if (op->atom == DW_OP_bregx) { |
335 | regn = op->number; | 335 | regn = op->number; |
336 | offs += op->number2; | 336 | offs += op->number2; |
337 | ref = true; | 337 | ref = true; |
338 | } else if (op->atom == DW_OP_regx) { | 338 | } else if (op->atom == DW_OP_regx) { |
339 | regn = op->number; | 339 | regn = op->number; |
340 | } else { | 340 | } else { |
341 | pr_debug("DW_OP %x is not supported.\n", op->atom); | 341 | pr_debug("DW_OP %x is not supported.\n", op->atom); |
342 | return -ENOTSUP; | 342 | return -ENOTSUP; |
343 | } | 343 | } |
344 | 344 | ||
345 | if (!tvar) | 345 | if (!tvar) |
346 | return 0; | 346 | return 0; |
347 | 347 | ||
348 | regs = get_arch_regstr(regn); | 348 | regs = get_arch_regstr(regn); |
349 | if (!regs) { | 349 | if (!regs) { |
350 | /* This should be a bug in DWARF or this tool */ | 350 | /* This should be a bug in DWARF or this tool */ |
351 | pr_warning("Mapping for the register number %u " | 351 | pr_warning("Mapping for the register number %u " |
352 | "missing on this architecture.\n", regn); | 352 | "missing on this architecture.\n", regn); |
353 | return -ERANGE; | 353 | return -ERANGE; |
354 | } | 354 | } |
355 | 355 | ||
356 | tvar->value = strdup(regs); | 356 | tvar->value = strdup(regs); |
357 | if (tvar->value == NULL) | 357 | if (tvar->value == NULL) |
358 | return -ENOMEM; | 358 | return -ENOMEM; |
359 | 359 | ||
360 | if (ref) { | 360 | if (ref) { |
361 | tvar->ref = alloc_trace_arg_ref((long)offs); | 361 | tvar->ref = alloc_trace_arg_ref((long)offs); |
362 | if (tvar->ref == NULL) | 362 | if (tvar->ref == NULL) |
363 | return -ENOMEM; | 363 | return -ENOMEM; |
364 | } | 364 | } |
365 | return 0; | 365 | return 0; |
366 | } | 366 | } |
367 | 367 | ||
368 | #define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long)) | 368 | #define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long)) |
369 | 369 | ||
370 | static int convert_variable_type(Dwarf_Die *vr_die, | 370 | static int convert_variable_type(Dwarf_Die *vr_die, |
371 | struct probe_trace_arg *tvar, | 371 | struct probe_trace_arg *tvar, |
372 | const char *cast) | 372 | const char *cast) |
373 | { | 373 | { |
374 | struct probe_trace_arg_ref **ref_ptr = &tvar->ref; | 374 | struct probe_trace_arg_ref **ref_ptr = &tvar->ref; |
375 | Dwarf_Die type; | 375 | Dwarf_Die type; |
376 | char buf[16]; | 376 | char buf[16]; |
377 | int bsize, boffs, total; | 377 | int bsize, boffs, total; |
378 | int ret; | 378 | int ret; |
379 | 379 | ||
380 | /* TODO: check all types */ | 380 | /* TODO: check all types */ |
381 | if (cast && strcmp(cast, "string") != 0) { | 381 | if (cast && strcmp(cast, "string") != 0) { |
382 | /* Non string type is OK */ | 382 | /* Non string type is OK */ |
383 | tvar->type = strdup(cast); | 383 | tvar->type = strdup(cast); |
384 | return (tvar->type == NULL) ? -ENOMEM : 0; | 384 | return (tvar->type == NULL) ? -ENOMEM : 0; |
385 | } | 385 | } |
386 | 386 | ||
387 | bsize = dwarf_bitsize(vr_die); | 387 | bsize = dwarf_bitsize(vr_die); |
388 | if (bsize > 0) { | 388 | if (bsize > 0) { |
389 | /* This is a bitfield */ | 389 | /* This is a bitfield */ |
390 | boffs = dwarf_bitoffset(vr_die); | 390 | boffs = dwarf_bitoffset(vr_die); |
391 | total = dwarf_bytesize(vr_die); | 391 | total = dwarf_bytesize(vr_die); |
392 | if (boffs < 0 || total < 0) | 392 | if (boffs < 0 || total < 0) |
393 | return -ENOENT; | 393 | return -ENOENT; |
394 | ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs, | 394 | ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs, |
395 | BYTES_TO_BITS(total)); | 395 | BYTES_TO_BITS(total)); |
396 | goto formatted; | 396 | goto formatted; |
397 | } | 397 | } |
398 | 398 | ||
399 | if (die_get_real_type(vr_die, &type) == NULL) { | 399 | if (die_get_real_type(vr_die, &type) == NULL) { |
400 | pr_warning("Failed to get a type information of %s.\n", | 400 | pr_warning("Failed to get a type information of %s.\n", |
401 | dwarf_diename(vr_die)); | 401 | dwarf_diename(vr_die)); |
402 | return -ENOENT; | 402 | return -ENOENT; |
403 | } | 403 | } |
404 | 404 | ||
405 | pr_debug("%s type is %s.\n", | 405 | pr_debug("%s type is %s.\n", |
406 | dwarf_diename(vr_die), dwarf_diename(&type)); | 406 | dwarf_diename(vr_die), dwarf_diename(&type)); |
407 | 407 | ||
408 | if (cast && strcmp(cast, "string") == 0) { /* String type */ | 408 | if (cast && strcmp(cast, "string") == 0) { /* String type */ |
409 | ret = dwarf_tag(&type); | 409 | ret = dwarf_tag(&type); |
410 | if (ret != DW_TAG_pointer_type && | 410 | if (ret != DW_TAG_pointer_type && |
411 | ret != DW_TAG_array_type) { | 411 | ret != DW_TAG_array_type) { |
412 | pr_warning("Failed to cast into string: " | 412 | pr_warning("Failed to cast into string: " |
413 | "%s(%s) is not a pointer nor array.\n", | 413 | "%s(%s) is not a pointer nor array.\n", |
414 | dwarf_diename(vr_die), dwarf_diename(&type)); | 414 | dwarf_diename(vr_die), dwarf_diename(&type)); |
415 | return -EINVAL; | 415 | return -EINVAL; |
416 | } | 416 | } |
417 | if (ret == DW_TAG_pointer_type) { | 417 | if (ret == DW_TAG_pointer_type) { |
418 | if (die_get_real_type(&type, &type) == NULL) { | 418 | if (die_get_real_type(&type, &type) == NULL) { |
419 | pr_warning("Failed to get a type" | 419 | pr_warning("Failed to get a type" |
420 | " information.\n"); | 420 | " information.\n"); |
421 | return -ENOENT; | 421 | return -ENOENT; |
422 | } | 422 | } |
423 | while (*ref_ptr) | 423 | while (*ref_ptr) |
424 | ref_ptr = &(*ref_ptr)->next; | 424 | ref_ptr = &(*ref_ptr)->next; |
425 | /* Add new reference with offset +0 */ | 425 | /* Add new reference with offset +0 */ |
426 | *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); | 426 | *ref_ptr = zalloc(sizeof(struct probe_trace_arg_ref)); |
427 | if (*ref_ptr == NULL) { | 427 | if (*ref_ptr == NULL) { |
428 | pr_warning("Out of memory error\n"); | 428 | pr_warning("Out of memory error\n"); |
429 | return -ENOMEM; | 429 | return -ENOMEM; |
430 | } | 430 | } |
431 | } | 431 | } |
432 | if (!die_compare_name(&type, "char") && | 432 | if (!die_compare_name(&type, "char") && |
433 | !die_compare_name(&type, "unsigned char")) { | 433 | !die_compare_name(&type, "unsigned char")) { |
434 | pr_warning("Failed to cast into string: " | 434 | pr_warning("Failed to cast into string: " |
435 | "%s is not (unsigned) char *.\n", | 435 | "%s is not (unsigned) char *.\n", |
436 | dwarf_diename(vr_die)); | 436 | dwarf_diename(vr_die)); |
437 | return -EINVAL; | 437 | return -EINVAL; |
438 | } | 438 | } |
439 | tvar->type = strdup(cast); | 439 | tvar->type = strdup(cast); |
440 | return (tvar->type == NULL) ? -ENOMEM : 0; | 440 | return (tvar->type == NULL) ? -ENOMEM : 0; |
441 | } | 441 | } |
442 | 442 | ||
443 | ret = dwarf_bytesize(&type); | 443 | ret = dwarf_bytesize(&type); |
444 | if (ret <= 0) | 444 | if (ret <= 0) |
445 | /* No size ... try to use default type */ | 445 | /* No size ... try to use default type */ |
446 | return 0; | 446 | return 0; |
447 | ret = BYTES_TO_BITS(ret); | 447 | ret = BYTES_TO_BITS(ret); |
448 | 448 | ||
449 | /* Check the bitwidth */ | 449 | /* Check the bitwidth */ |
450 | if (ret > MAX_BASIC_TYPE_BITS) { | 450 | if (ret > MAX_BASIC_TYPE_BITS) { |
451 | pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n", | 451 | pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n", |
452 | dwarf_diename(&type), MAX_BASIC_TYPE_BITS); | 452 | dwarf_diename(&type), MAX_BASIC_TYPE_BITS); |
453 | ret = MAX_BASIC_TYPE_BITS; | 453 | ret = MAX_BASIC_TYPE_BITS; |
454 | } | 454 | } |
455 | ret = snprintf(buf, 16, "%c%d", | 455 | ret = snprintf(buf, 16, "%c%d", |
456 | die_is_signed_type(&type) ? 's' : 'u', ret); | 456 | die_is_signed_type(&type) ? 's' : 'u', ret); |
457 | 457 | ||
458 | formatted: | 458 | formatted: |
459 | if (ret < 0 || ret >= 16) { | 459 | if (ret < 0 || ret >= 16) { |
460 | if (ret >= 16) | 460 | if (ret >= 16) |
461 | ret = -E2BIG; | 461 | ret = -E2BIG; |
462 | pr_warning("Failed to convert variable type: %s\n", | 462 | pr_warning("Failed to convert variable type: %s\n", |
463 | strerror(-ret)); | 463 | strerror(-ret)); |
464 | return ret; | 464 | return ret; |
465 | } | 465 | } |
466 | tvar->type = strdup(buf); | 466 | tvar->type = strdup(buf); |
467 | if (tvar->type == NULL) | 467 | if (tvar->type == NULL) |
468 | return -ENOMEM; | 468 | return -ENOMEM; |
469 | return 0; | 469 | return 0; |
470 | } | 470 | } |
471 | 471 | ||
472 | static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, | 472 | static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, |
473 | struct perf_probe_arg_field *field, | 473 | struct perf_probe_arg_field *field, |
474 | struct probe_trace_arg_ref **ref_ptr, | 474 | struct probe_trace_arg_ref **ref_ptr, |
475 | Dwarf_Die *die_mem) | 475 | Dwarf_Die *die_mem) |
476 | { | 476 | { |
477 | struct probe_trace_arg_ref *ref = *ref_ptr; | 477 | struct probe_trace_arg_ref *ref = *ref_ptr; |
478 | Dwarf_Die type; | 478 | Dwarf_Die type; |
479 | Dwarf_Word offs; | 479 | Dwarf_Word offs; |
480 | int ret, tag; | 480 | int ret, tag; |
481 | 481 | ||
482 | pr_debug("converting %s in %s\n", field->name, varname); | 482 | pr_debug("converting %s in %s\n", field->name, varname); |
483 | if (die_get_real_type(vr_die, &type) == NULL) { | 483 | if (die_get_real_type(vr_die, &type) == NULL) { |
484 | pr_warning("Failed to get the type of %s.\n", varname); | 484 | pr_warning("Failed to get the type of %s.\n", varname); |
485 | return -ENOENT; | 485 | return -ENOENT; |
486 | } | 486 | } |
487 | pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type)); | 487 | pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type)); |
488 | tag = dwarf_tag(&type); | 488 | tag = dwarf_tag(&type); |
489 | 489 | ||
490 | if (field->name[0] == '[' && | 490 | if (field->name[0] == '[' && |
491 | (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { | 491 | (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) { |
492 | if (field->next) | 492 | if (field->next) |
493 | /* Save original type for next field */ | 493 | /* Save original type for next field */ |
494 | memcpy(die_mem, &type, sizeof(*die_mem)); | 494 | memcpy(die_mem, &type, sizeof(*die_mem)); |
495 | /* Get the type of this array */ | 495 | /* Get the type of this array */ |
496 | if (die_get_real_type(&type, &type) == NULL) { | 496 | if (die_get_real_type(&type, &type) == NULL) { |
497 | pr_warning("Failed to get the type of %s.\n", varname); | 497 | pr_warning("Failed to get the type of %s.\n", varname); |
498 | return -ENOENT; | 498 | return -ENOENT; |
499 | } | 499 | } |
500 | pr_debug2("Array real type: (%x)\n", | 500 | pr_debug2("Array real type: (%x)\n", |
501 | (unsigned)dwarf_dieoffset(&type)); | 501 | (unsigned)dwarf_dieoffset(&type)); |
502 | if (tag == DW_TAG_pointer_type) { | 502 | if (tag == DW_TAG_pointer_type) { |
503 | ref = zalloc(sizeof(struct probe_trace_arg_ref)); | 503 | ref = zalloc(sizeof(struct probe_trace_arg_ref)); |
504 | if (ref == NULL) | 504 | if (ref == NULL) |
505 | return -ENOMEM; | 505 | return -ENOMEM; |
506 | if (*ref_ptr) | 506 | if (*ref_ptr) |
507 | (*ref_ptr)->next = ref; | 507 | (*ref_ptr)->next = ref; |
508 | else | 508 | else |
509 | *ref_ptr = ref; | 509 | *ref_ptr = ref; |
510 | } | 510 | } |
511 | ref->offset += dwarf_bytesize(&type) * field->index; | 511 | ref->offset += dwarf_bytesize(&type) * field->index; |
512 | if (!field->next) | 512 | if (!field->next) |
513 | /* Save vr_die for converting types */ | 513 | /* Save vr_die for converting types */ |
514 | memcpy(die_mem, vr_die, sizeof(*die_mem)); | 514 | memcpy(die_mem, vr_die, sizeof(*die_mem)); |
515 | goto next; | 515 | goto next; |
516 | } else if (tag == DW_TAG_pointer_type) { | 516 | } else if (tag == DW_TAG_pointer_type) { |
517 | /* Check the pointer and dereference */ | 517 | /* Check the pointer and dereference */ |
518 | if (!field->ref) { | 518 | if (!field->ref) { |
519 | pr_err("Semantic error: %s must be referred by '->'\n", | 519 | pr_err("Semantic error: %s must be referred by '->'\n", |
520 | field->name); | 520 | field->name); |
521 | return -EINVAL; | 521 | return -EINVAL; |
522 | } | 522 | } |
523 | /* Get the type pointed by this pointer */ | 523 | /* Get the type pointed by this pointer */ |
524 | if (die_get_real_type(&type, &type) == NULL) { | 524 | if (die_get_real_type(&type, &type) == NULL) { |
525 | pr_warning("Failed to get the type of %s.\n", varname); | 525 | pr_warning("Failed to get the type of %s.\n", varname); |
526 | return -ENOENT; | 526 | return -ENOENT; |
527 | } | 527 | } |
528 | /* Verify it is a data structure */ | 528 | /* Verify it is a data structure */ |
529 | if (dwarf_tag(&type) != DW_TAG_structure_type) { | 529 | if (dwarf_tag(&type) != DW_TAG_structure_type) { |
530 | pr_warning("%s is not a data structure.\n", varname); | 530 | pr_warning("%s is not a data structure.\n", varname); |
531 | return -EINVAL; | 531 | return -EINVAL; |
532 | } | 532 | } |
533 | 533 | ||
534 | ref = zalloc(sizeof(struct probe_trace_arg_ref)); | 534 | ref = zalloc(sizeof(struct probe_trace_arg_ref)); |
535 | if (ref == NULL) | 535 | if (ref == NULL) |
536 | return -ENOMEM; | 536 | return -ENOMEM; |
537 | if (*ref_ptr) | 537 | if (*ref_ptr) |
538 | (*ref_ptr)->next = ref; | 538 | (*ref_ptr)->next = ref; |
539 | else | 539 | else |
540 | *ref_ptr = ref; | 540 | *ref_ptr = ref; |
541 | } else { | 541 | } else { |
542 | /* Verify it is a data structure */ | 542 | /* Verify it is a data structure */ |
543 | if (tag != DW_TAG_structure_type) { | 543 | if (tag != DW_TAG_structure_type) { |
544 | pr_warning("%s is not a data structure.\n", varname); | 544 | pr_warning("%s is not a data structure.\n", varname); |
545 | return -EINVAL; | 545 | return -EINVAL; |
546 | } | 546 | } |
547 | if (field->name[0] == '[') { | 547 | if (field->name[0] == '[') { |
548 | pr_err("Semantic error: %s is not a pointor" | 548 | pr_err("Semantic error: %s is not a pointor" |
549 | " nor array.\n", varname); | 549 | " nor array.\n", varname); |
550 | return -EINVAL; | 550 | return -EINVAL; |
551 | } | 551 | } |
552 | if (field->ref) { | 552 | if (field->ref) { |
553 | pr_err("Semantic error: %s must be referred by '.'\n", | 553 | pr_err("Semantic error: %s must be referred by '.'\n", |
554 | field->name); | 554 | field->name); |
555 | return -EINVAL; | 555 | return -EINVAL; |
556 | } | 556 | } |
557 | if (!ref) { | 557 | if (!ref) { |
558 | pr_warning("Structure on a register is not " | 558 | pr_warning("Structure on a register is not " |
559 | "supported yet.\n"); | 559 | "supported yet.\n"); |
560 | return -ENOTSUP; | 560 | return -ENOTSUP; |
561 | } | 561 | } |
562 | } | 562 | } |
563 | 563 | ||
564 | if (die_find_member(&type, field->name, die_mem) == NULL) { | 564 | if (die_find_member(&type, field->name, die_mem) == NULL) { |
565 | pr_warning("%s(tyep:%s) has no member %s.\n", varname, | 565 | pr_warning("%s(tyep:%s) has no member %s.\n", varname, |
566 | dwarf_diename(&type), field->name); | 566 | dwarf_diename(&type), field->name); |
567 | return -EINVAL; | 567 | return -EINVAL; |
568 | } | 568 | } |
569 | 569 | ||
570 | /* Get the offset of the field */ | 570 | /* Get the offset of the field */ |
571 | ret = die_get_data_member_location(die_mem, &offs); | 571 | ret = die_get_data_member_location(die_mem, &offs); |
572 | if (ret < 0) { | 572 | if (ret < 0) { |
573 | pr_warning("Failed to get the offset of %s.\n", field->name); | 573 | pr_warning("Failed to get the offset of %s.\n", field->name); |
574 | return ret; | 574 | return ret; |
575 | } | 575 | } |
576 | ref->offset += (long)offs; | 576 | ref->offset += (long)offs; |
577 | 577 | ||
578 | next: | 578 | next: |
579 | /* Converting next field */ | 579 | /* Converting next field */ |
580 | if (field->next) | 580 | if (field->next) |
581 | return convert_variable_fields(die_mem, field->name, | 581 | return convert_variable_fields(die_mem, field->name, |
582 | field->next, &ref, die_mem); | 582 | field->next, &ref, die_mem); |
583 | else | 583 | else |
584 | return 0; | 584 | return 0; |
585 | } | 585 | } |
586 | 586 | ||
587 | /* Show a variables in kprobe event format */ | 587 | /* Show a variables in kprobe event format */ |
588 | static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | 588 | static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) |
589 | { | 589 | { |
590 | Dwarf_Die die_mem; | 590 | Dwarf_Die die_mem; |
591 | int ret; | 591 | int ret; |
592 | 592 | ||
593 | pr_debug("Converting variable %s into trace event.\n", | 593 | pr_debug("Converting variable %s into trace event.\n", |
594 | dwarf_diename(vr_die)); | 594 | dwarf_diename(vr_die)); |
595 | 595 | ||
596 | ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, | 596 | ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, |
597 | pf->tvar); | 597 | pf->tvar); |
598 | if (ret == -ENOENT) | 598 | if (ret == -ENOENT) |
599 | pr_err("Failed to find the location of %s at this address.\n" | 599 | pr_err("Failed to find the location of %s at this address.\n" |
600 | " Perhaps, it has been optimized out.\n", pf->pvar->var); | 600 | " Perhaps, it has been optimized out.\n", pf->pvar->var); |
601 | else if (ret == -ENOTSUP) | 601 | else if (ret == -ENOTSUP) |
602 | pr_err("Sorry, we don't support this variable location yet.\n"); | 602 | pr_err("Sorry, we don't support this variable location yet.\n"); |
603 | else if (pf->pvar->field) { | 603 | else if (pf->pvar->field) { |
604 | ret = convert_variable_fields(vr_die, pf->pvar->var, | 604 | ret = convert_variable_fields(vr_die, pf->pvar->var, |
605 | pf->pvar->field, &pf->tvar->ref, | 605 | pf->pvar->field, &pf->tvar->ref, |
606 | &die_mem); | 606 | &die_mem); |
607 | vr_die = &die_mem; | 607 | vr_die = &die_mem; |
608 | } | 608 | } |
609 | if (ret == 0) | 609 | if (ret == 0) |
610 | ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); | 610 | ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); |
611 | /* *expr will be cached in libdw. Don't free it. */ | 611 | /* *expr will be cached in libdw. Don't free it. */ |
612 | return ret; | 612 | return ret; |
613 | } | 613 | } |
614 | 614 | ||
615 | /* Find a variable in a scope DIE */ | 615 | /* Find a variable in a scope DIE */ |
616 | static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) | 616 | static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) |
617 | { | 617 | { |
618 | Dwarf_Die vr_die; | 618 | Dwarf_Die vr_die; |
619 | char buf[32], *ptr; | 619 | char buf[32], *ptr; |
620 | int ret = 0; | 620 | int ret = 0; |
621 | 621 | ||
622 | if (!is_c_varname(pf->pvar->var)) { | 622 | if (!is_c_varname(pf->pvar->var)) { |
623 | /* Copy raw parameters */ | 623 | /* Copy raw parameters */ |
624 | pf->tvar->value = strdup(pf->pvar->var); | 624 | pf->tvar->value = strdup(pf->pvar->var); |
625 | if (pf->tvar->value == NULL) | 625 | if (pf->tvar->value == NULL) |
626 | return -ENOMEM; | 626 | return -ENOMEM; |
627 | if (pf->pvar->type) { | 627 | if (pf->pvar->type) { |
628 | pf->tvar->type = strdup(pf->pvar->type); | 628 | pf->tvar->type = strdup(pf->pvar->type); |
629 | if (pf->tvar->type == NULL) | 629 | if (pf->tvar->type == NULL) |
630 | return -ENOMEM; | 630 | return -ENOMEM; |
631 | } | 631 | } |
632 | if (pf->pvar->name) { | 632 | if (pf->pvar->name) { |
633 | pf->tvar->name = strdup(pf->pvar->name); | 633 | pf->tvar->name = strdup(pf->pvar->name); |
634 | if (pf->tvar->name == NULL) | 634 | if (pf->tvar->name == NULL) |
635 | return -ENOMEM; | 635 | return -ENOMEM; |
636 | } else | 636 | } else |
637 | pf->tvar->name = NULL; | 637 | pf->tvar->name = NULL; |
638 | return 0; | 638 | return 0; |
639 | } | 639 | } |
640 | 640 | ||
641 | if (pf->pvar->name) | 641 | if (pf->pvar->name) |
642 | pf->tvar->name = strdup(pf->pvar->name); | 642 | pf->tvar->name = strdup(pf->pvar->name); |
643 | else { | 643 | else { |
644 | ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); | 644 | ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); |
645 | if (ret < 0) | 645 | if (ret < 0) |
646 | return ret; | 646 | return ret; |
647 | ptr = strchr(buf, ':'); /* Change type separator to _ */ | 647 | ptr = strchr(buf, ':'); /* Change type separator to _ */ |
648 | if (ptr) | 648 | if (ptr) |
649 | *ptr = '_'; | 649 | *ptr = '_'; |
650 | pf->tvar->name = strdup(buf); | 650 | pf->tvar->name = strdup(buf); |
651 | } | 651 | } |
652 | if (pf->tvar->name == NULL) | 652 | if (pf->tvar->name == NULL) |
653 | return -ENOMEM; | 653 | return -ENOMEM; |
654 | 654 | ||
655 | pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); | 655 | pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); |
656 | /* Search child die for local variables and parameters. */ | 656 | /* Search child die for local variables and parameters. */ |
657 | if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { | 657 | if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { |
658 | /* Search again in global variables */ | 658 | /* Search again in global variables */ |
659 | if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) | 659 | if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) |
660 | ret = -ENOENT; | 660 | ret = -ENOENT; |
661 | } | 661 | } |
662 | if (ret == 0) | 662 | if (ret == 0) |
663 | ret = convert_variable(&vr_die, pf); | 663 | ret = convert_variable(&vr_die, pf); |
664 | 664 | ||
665 | if (ret < 0) | 665 | if (ret < 0) |
666 | pr_warning("Failed to find '%s' in this function.\n", | 666 | pr_warning("Failed to find '%s' in this function.\n", |
667 | pf->pvar->var); | 667 | pf->pvar->var); |
668 | return ret; | 668 | return ret; |
669 | } | 669 | } |
670 | 670 | ||
671 | /* Convert subprogram DIE to trace point */ | 671 | /* Convert subprogram DIE to trace point */ |
672 | static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, | 672 | static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, |
673 | bool retprobe, struct probe_trace_point *tp) | 673 | bool retprobe, struct probe_trace_point *tp) |
674 | { | 674 | { |
675 | Dwarf_Addr eaddr; | 675 | Dwarf_Addr eaddr; |
676 | const char *name; | 676 | const char *name; |
677 | 677 | ||
678 | /* Copy the name of probe point */ | 678 | /* Copy the name of probe point */ |
679 | name = dwarf_diename(sp_die); | 679 | name = dwarf_diename(sp_die); |
680 | if (name) { | 680 | if (name) { |
681 | if (dwarf_entrypc(sp_die, &eaddr) != 0) { | 681 | if (dwarf_entrypc(sp_die, &eaddr) != 0) { |
682 | pr_warning("Failed to get entry address of %s\n", | 682 | pr_warning("Failed to get entry address of %s\n", |
683 | dwarf_diename(sp_die)); | 683 | dwarf_diename(sp_die)); |
684 | return -ENOENT; | 684 | return -ENOENT; |
685 | } | 685 | } |
686 | tp->symbol = strdup(name); | 686 | tp->symbol = strdup(name); |
687 | if (tp->symbol == NULL) | 687 | if (tp->symbol == NULL) |
688 | return -ENOMEM; | 688 | return -ENOMEM; |
689 | tp->offset = (unsigned long)(paddr - eaddr); | 689 | tp->offset = (unsigned long)(paddr - eaddr); |
690 | } else | 690 | } else |
691 | /* This function has no name. */ | 691 | /* This function has no name. */ |
692 | tp->offset = (unsigned long)paddr; | 692 | tp->offset = (unsigned long)paddr; |
693 | 693 | ||
694 | /* Return probe must be on the head of a subprogram */ | 694 | /* Return probe must be on the head of a subprogram */ |
695 | if (retprobe) { | 695 | if (retprobe) { |
696 | if (eaddr != paddr) { | 696 | if (eaddr != paddr) { |
697 | pr_warning("Return probe must be on the head of" | 697 | pr_warning("Return probe must be on the head of" |
698 | " a real function.\n"); | 698 | " a real function.\n"); |
699 | return -EINVAL; | 699 | return -EINVAL; |
700 | } | 700 | } |
701 | tp->retprobe = true; | 701 | tp->retprobe = true; |
702 | } | 702 | } |
703 | 703 | ||
704 | return 0; | 704 | return 0; |
705 | } | 705 | } |
706 | 706 | ||
707 | /* Call probe_finder callback with scope DIE */ | 707 | /* Call probe_finder callback with scope DIE */ |
708 | static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) | 708 | static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) |
709 | { | 709 | { |
710 | Dwarf_Attribute fb_attr; | 710 | Dwarf_Attribute fb_attr; |
711 | size_t nops; | 711 | size_t nops; |
712 | int ret; | 712 | int ret; |
713 | 713 | ||
714 | if (!sc_die) { | 714 | if (!sc_die) { |
715 | pr_err("Caller must pass a scope DIE. Program error.\n"); | 715 | pr_err("Caller must pass a scope DIE. Program error.\n"); |
716 | return -EINVAL; | 716 | return -EINVAL; |
717 | } | 717 | } |
718 | 718 | ||
719 | /* If not a real subprogram, find a real one */ | 719 | /* If not a real subprogram, find a real one */ |
720 | if (dwarf_tag(sc_die) != DW_TAG_subprogram) { | 720 | if (dwarf_tag(sc_die) != DW_TAG_subprogram) { |
721 | if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { | 721 | if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { |
722 | pr_warning("Failed to find probe point in any " | 722 | pr_warning("Failed to find probe point in any " |
723 | "functions.\n"); | 723 | "functions.\n"); |
724 | return -ENOENT; | 724 | return -ENOENT; |
725 | } | 725 | } |
726 | } else | 726 | } else |
727 | memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); | 727 | memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); |
728 | 728 | ||
729 | /* Get the frame base attribute/ops from subprogram */ | 729 | /* Get the frame base attribute/ops from subprogram */ |
730 | dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); | 730 | dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); |
731 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); | 731 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); |
732 | if (ret <= 0 || nops == 0) { | 732 | if (ret <= 0 || nops == 0) { |
733 | pf->fb_ops = NULL; | 733 | pf->fb_ops = NULL; |
734 | #if _ELFUTILS_PREREQ(0, 142) | 734 | #if _ELFUTILS_PREREQ(0, 142) |
735 | } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && | 735 | } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && |
736 | pf->cfi != NULL) { | 736 | pf->cfi != NULL) { |
737 | Dwarf_Frame *frame; | 737 | Dwarf_Frame *frame; |
738 | if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || | 738 | if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || |
739 | dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { | 739 | dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { |
740 | pr_warning("Failed to get call frame on 0x%jx\n", | 740 | pr_warning("Failed to get call frame on 0x%jx\n", |
741 | (uintmax_t)pf->addr); | 741 | (uintmax_t)pf->addr); |
742 | return -ENOENT; | 742 | return -ENOENT; |
743 | } | 743 | } |
744 | #endif | 744 | #endif |
745 | } | 745 | } |
746 | 746 | ||
747 | /* Call finder's callback handler */ | 747 | /* Call finder's callback handler */ |
748 | ret = pf->callback(sc_die, pf); | 748 | ret = pf->callback(sc_die, pf); |
749 | 749 | ||
750 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ | 750 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ |
751 | pf->fb_ops = NULL; | 751 | pf->fb_ops = NULL; |
752 | 752 | ||
753 | return ret; | 753 | return ret; |
754 | } | 754 | } |
755 | 755 | ||
756 | struct find_scope_param { | 756 | struct find_scope_param { |
757 | const char *function; | 757 | const char *function; |
758 | const char *file; | 758 | const char *file; |
759 | int line; | 759 | int line; |
760 | int diff; | 760 | int diff; |
761 | Dwarf_Die *die_mem; | 761 | Dwarf_Die *die_mem; |
762 | bool found; | 762 | bool found; |
763 | }; | 763 | }; |
764 | 764 | ||
765 | static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) | 765 | static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) |
766 | { | 766 | { |
767 | struct find_scope_param *fsp = data; | 767 | struct find_scope_param *fsp = data; |
768 | const char *file; | 768 | const char *file; |
769 | int lno; | 769 | int lno; |
770 | 770 | ||
771 | /* Skip if declared file name does not match */ | 771 | /* Skip if declared file name does not match */ |
772 | if (fsp->file) { | 772 | if (fsp->file) { |
773 | file = dwarf_decl_file(fn_die); | 773 | file = dwarf_decl_file(fn_die); |
774 | if (!file || strcmp(fsp->file, file) != 0) | 774 | if (!file || strcmp(fsp->file, file) != 0) |
775 | return 0; | 775 | return 0; |
776 | } | 776 | } |
777 | /* If the function name is given, that's what user expects */ | 777 | /* If the function name is given, that's what user expects */ |
778 | if (fsp->function) { | 778 | if (fsp->function) { |
779 | if (die_compare_name(fn_die, fsp->function)) { | 779 | if (die_compare_name(fn_die, fsp->function)) { |
780 | memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); | 780 | memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); |
781 | fsp->found = true; | 781 | fsp->found = true; |
782 | return 1; | 782 | return 1; |
783 | } | 783 | } |
784 | } else { | 784 | } else { |
785 | /* With the line number, find the nearest declared DIE */ | 785 | /* With the line number, find the nearest declared DIE */ |
786 | dwarf_decl_line(fn_die, &lno); | 786 | dwarf_decl_line(fn_die, &lno); |
787 | if (lno < fsp->line && fsp->diff > fsp->line - lno) { | 787 | if (lno < fsp->line && fsp->diff > fsp->line - lno) { |
788 | /* Keep a candidate and continue */ | 788 | /* Keep a candidate and continue */ |
789 | fsp->diff = fsp->line - lno; | 789 | fsp->diff = fsp->line - lno; |
790 | memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); | 790 | memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); |
791 | fsp->found = true; | 791 | fsp->found = true; |
792 | } | 792 | } |
793 | } | 793 | } |
794 | return 0; | 794 | return 0; |
795 | } | 795 | } |
796 | 796 | ||
797 | /* Find an appropriate scope fits to given conditions */ | 797 | /* Find an appropriate scope fits to given conditions */ |
798 | static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) | 798 | static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) |
799 | { | 799 | { |
800 | struct find_scope_param fsp = { | 800 | struct find_scope_param fsp = { |
801 | .function = pf->pev->point.function, | 801 | .function = pf->pev->point.function, |
802 | .file = pf->fname, | 802 | .file = pf->fname, |
803 | .line = pf->lno, | 803 | .line = pf->lno, |
804 | .diff = INT_MAX, | 804 | .diff = INT_MAX, |
805 | .die_mem = die_mem, | 805 | .die_mem = die_mem, |
806 | .found = false, | 806 | .found = false, |
807 | }; | 807 | }; |
808 | 808 | ||
809 | cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); | 809 | cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); |
810 | 810 | ||
811 | return fsp.found ? die_mem : NULL; | 811 | return fsp.found ? die_mem : NULL; |
812 | } | 812 | } |
813 | 813 | ||
814 | static int probe_point_line_walker(const char *fname, int lineno, | 814 | static int probe_point_line_walker(const char *fname, int lineno, |
815 | Dwarf_Addr addr, void *data) | 815 | Dwarf_Addr addr, void *data) |
816 | { | 816 | { |
817 | struct probe_finder *pf = data; | 817 | struct probe_finder *pf = data; |
818 | Dwarf_Die *sc_die, die_mem; | 818 | Dwarf_Die *sc_die, die_mem; |
819 | int ret; | 819 | int ret; |
820 | 820 | ||
821 | if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) | 821 | if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) |
822 | return 0; | 822 | return 0; |
823 | 823 | ||
824 | pf->addr = addr; | 824 | pf->addr = addr; |
825 | sc_die = find_best_scope(pf, &die_mem); | 825 | sc_die = find_best_scope(pf, &die_mem); |
826 | if (!sc_die) { | 826 | if (!sc_die) { |
827 | pr_warning("Failed to find scope of probe point.\n"); | 827 | pr_warning("Failed to find scope of probe point.\n"); |
828 | return -ENOENT; | 828 | return -ENOENT; |
829 | } | 829 | } |
830 | 830 | ||
831 | ret = call_probe_finder(sc_die, pf); | 831 | ret = call_probe_finder(sc_die, pf); |
832 | 832 | ||
833 | /* Continue if no error, because the line will be in inline function */ | 833 | /* Continue if no error, because the line will be in inline function */ |
834 | return ret < 0 ? ret : 0; | 834 | return ret < 0 ? ret : 0; |
835 | } | 835 | } |
836 | 836 | ||
837 | /* Find probe point from its line number */ | 837 | /* Find probe point from its line number */ |
838 | static int find_probe_point_by_line(struct probe_finder *pf) | 838 | static int find_probe_point_by_line(struct probe_finder *pf) |
839 | { | 839 | { |
840 | return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); | 840 | return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); |
841 | } | 841 | } |
842 | 842 | ||
843 | /* Find lines which match lazy pattern */ | 843 | /* Find lines which match lazy pattern */ |
844 | static int find_lazy_match_lines(struct list_head *head, | 844 | static int find_lazy_match_lines(struct list_head *head, |
845 | const char *fname, const char *pat) | 845 | const char *fname, const char *pat) |
846 | { | 846 | { |
847 | FILE *fp; | 847 | FILE *fp; |
848 | char *line = NULL; | 848 | char *line = NULL; |
849 | size_t line_len; | 849 | size_t line_len; |
850 | ssize_t len; | 850 | ssize_t len; |
851 | int count = 0, linenum = 1; | 851 | int count = 0, linenum = 1; |
852 | 852 | ||
853 | fp = fopen(fname, "r"); | 853 | fp = fopen(fname, "r"); |
854 | if (!fp) { | 854 | if (!fp) { |
855 | pr_warning("Failed to open %s: %s\n", fname, strerror(errno)); | 855 | pr_warning("Failed to open %s: %s\n", fname, strerror(errno)); |
856 | return -errno; | 856 | return -errno; |
857 | } | 857 | } |
858 | 858 | ||
859 | while ((len = getline(&line, &line_len, fp)) > 0) { | 859 | while ((len = getline(&line, &line_len, fp)) > 0) { |
860 | 860 | ||
861 | if (line[len - 1] == '\n') | 861 | if (line[len - 1] == '\n') |
862 | line[len - 1] = '\0'; | 862 | line[len - 1] = '\0'; |
863 | 863 | ||
864 | if (strlazymatch(line, pat)) { | 864 | if (strlazymatch(line, pat)) { |
865 | line_list__add_line(head, linenum); | 865 | line_list__add_line(head, linenum); |
866 | count++; | 866 | count++; |
867 | } | 867 | } |
868 | linenum++; | 868 | linenum++; |
869 | } | 869 | } |
870 | 870 | ||
871 | if (ferror(fp)) | 871 | if (ferror(fp)) |
872 | count = -errno; | 872 | count = -errno; |
873 | free(line); | 873 | free(line); |
874 | fclose(fp); | 874 | fclose(fp); |
875 | 875 | ||
876 | if (count == 0) | 876 | if (count == 0) |
877 | pr_debug("No matched lines found in %s.\n", fname); | 877 | pr_debug("No matched lines found in %s.\n", fname); |
878 | return count; | 878 | return count; |
879 | } | 879 | } |
880 | 880 | ||
881 | static int probe_point_lazy_walker(const char *fname, int lineno, | 881 | static int probe_point_lazy_walker(const char *fname, int lineno, |
882 | Dwarf_Addr addr, void *data) | 882 | Dwarf_Addr addr, void *data) |
883 | { | 883 | { |
884 | struct probe_finder *pf = data; | 884 | struct probe_finder *pf = data; |
885 | Dwarf_Die *sc_die, die_mem; | 885 | Dwarf_Die *sc_die, die_mem; |
886 | int ret; | 886 | int ret; |
887 | 887 | ||
888 | if (!line_list__has_line(&pf->lcache, lineno) || | 888 | if (!line_list__has_line(&pf->lcache, lineno) || |
889 | strtailcmp(fname, pf->fname) != 0) | 889 | strtailcmp(fname, pf->fname) != 0) |
890 | return 0; | 890 | return 0; |
891 | 891 | ||
892 | pr_debug("Probe line found: line:%d addr:0x%llx\n", | 892 | pr_debug("Probe line found: line:%d addr:0x%llx\n", |
893 | lineno, (unsigned long long)addr); | 893 | lineno, (unsigned long long)addr); |
894 | pf->addr = addr; | 894 | pf->addr = addr; |
895 | pf->lno = lineno; | 895 | pf->lno = lineno; |
896 | sc_die = find_best_scope(pf, &die_mem); | 896 | sc_die = find_best_scope(pf, &die_mem); |
897 | if (!sc_die) { | 897 | if (!sc_die) { |
898 | pr_warning("Failed to find scope of probe point.\n"); | 898 | pr_warning("Failed to find scope of probe point.\n"); |
899 | return -ENOENT; | 899 | return -ENOENT; |
900 | } | 900 | } |
901 | 901 | ||
902 | ret = call_probe_finder(sc_die, pf); | 902 | ret = call_probe_finder(sc_die, pf); |
903 | 903 | ||
904 | /* | 904 | /* |
905 | * Continue if no error, because the lazy pattern will match | 905 | * Continue if no error, because the lazy pattern will match |
906 | * to other lines | 906 | * to other lines |
907 | */ | 907 | */ |
908 | return ret < 0 ? ret : 0; | 908 | return ret < 0 ? ret : 0; |
909 | } | 909 | } |
910 | 910 | ||
911 | /* Find probe points from lazy pattern */ | 911 | /* Find probe points from lazy pattern */ |
912 | static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | 912 | static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) |
913 | { | 913 | { |
914 | int ret = 0; | 914 | int ret = 0; |
915 | 915 | ||
916 | if (list_empty(&pf->lcache)) { | 916 | if (list_empty(&pf->lcache)) { |
917 | /* Matching lazy line pattern */ | 917 | /* Matching lazy line pattern */ |
918 | ret = find_lazy_match_lines(&pf->lcache, pf->fname, | 918 | ret = find_lazy_match_lines(&pf->lcache, pf->fname, |
919 | pf->pev->point.lazy_line); | 919 | pf->pev->point.lazy_line); |
920 | if (ret <= 0) | 920 | if (ret <= 0) |
921 | return ret; | 921 | return ret; |
922 | } | 922 | } |
923 | 923 | ||
924 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); | 924 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); |
925 | } | 925 | } |
926 | 926 | ||
927 | /* Callback parameter with return value */ | ||
928 | struct dwarf_callback_param { | ||
929 | void *data; | ||
930 | int retval; | ||
931 | }; | ||
932 | |||
933 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | 927 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) |
934 | { | 928 | { |
935 | struct dwarf_callback_param *param = data; | 929 | struct probe_finder *pf = data; |
936 | struct probe_finder *pf = param->data; | ||
937 | struct perf_probe_point *pp = &pf->pev->point; | 930 | struct perf_probe_point *pp = &pf->pev->point; |
938 | Dwarf_Addr addr; | 931 | Dwarf_Addr addr; |
932 | int ret; | ||
939 | 933 | ||
940 | if (pp->lazy_line) | 934 | if (pp->lazy_line) |
941 | param->retval = find_probe_point_lazy(in_die, pf); | 935 | ret = find_probe_point_lazy(in_die, pf); |
942 | else { | 936 | else { |
943 | /* Get probe address */ | 937 | /* Get probe address */ |
944 | if (dwarf_entrypc(in_die, &addr) != 0) { | 938 | if (dwarf_entrypc(in_die, &addr) != 0) { |
945 | pr_warning("Failed to get entry address of %s.\n", | 939 | pr_warning("Failed to get entry address of %s.\n", |
946 | dwarf_diename(in_die)); | 940 | dwarf_diename(in_die)); |
947 | param->retval = -ENOENT; | 941 | return -ENOENT; |
948 | return DWARF_CB_ABORT; | ||
949 | } | 942 | } |
950 | pf->addr = addr; | 943 | pf->addr = addr; |
951 | pf->addr += pp->offset; | 944 | pf->addr += pp->offset; |
952 | pr_debug("found inline addr: 0x%jx\n", | 945 | pr_debug("found inline addr: 0x%jx\n", |
953 | (uintmax_t)pf->addr); | 946 | (uintmax_t)pf->addr); |
954 | 947 | ||
955 | param->retval = call_probe_finder(in_die, pf); | 948 | ret = call_probe_finder(in_die, pf); |
956 | if (param->retval < 0) | ||
957 | return DWARF_CB_ABORT; | ||
958 | } | 949 | } |
959 | 950 | ||
960 | return DWARF_CB_OK; | 951 | return ret; |
961 | } | 952 | } |
962 | 953 | ||
954 | /* Callback parameter with return value for libdw */ | ||
955 | struct dwarf_callback_param { | ||
956 | void *data; | ||
957 | int retval; | ||
958 | }; | ||
959 | |||
963 | /* Search function from function name */ | 960 | /* Search function from function name */ |
964 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | 961 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) |
965 | { | 962 | { |
966 | struct dwarf_callback_param *param = data; | 963 | struct dwarf_callback_param *param = data; |
967 | struct probe_finder *pf = param->data; | 964 | struct probe_finder *pf = param->data; |
968 | struct perf_probe_point *pp = &pf->pev->point; | 965 | struct perf_probe_point *pp = &pf->pev->point; |
969 | 966 | ||
970 | /* Check tag and diename */ | 967 | /* Check tag and diename */ |
971 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || | 968 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || |
972 | !die_compare_name(sp_die, pp->function)) | 969 | !die_compare_name(sp_die, pp->function)) |
973 | return DWARF_CB_OK; | 970 | return DWARF_CB_OK; |
974 | 971 | ||
975 | /* Check declared file */ | 972 | /* Check declared file */ |
976 | if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) | 973 | if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) |
977 | return DWARF_CB_OK; | 974 | return DWARF_CB_OK; |
978 | 975 | ||
979 | pf->fname = dwarf_decl_file(sp_die); | 976 | pf->fname = dwarf_decl_file(sp_die); |
980 | if (pp->line) { /* Function relative line */ | 977 | if (pp->line) { /* Function relative line */ |
981 | dwarf_decl_line(sp_die, &pf->lno); | 978 | dwarf_decl_line(sp_die, &pf->lno); |
982 | pf->lno += pp->line; | 979 | pf->lno += pp->line; |
983 | param->retval = find_probe_point_by_line(pf); | 980 | param->retval = find_probe_point_by_line(pf); |
984 | } else if (!dwarf_func_inline(sp_die)) { | 981 | } else if (!dwarf_func_inline(sp_die)) { |
985 | /* Real function */ | 982 | /* Real function */ |
986 | if (pp->lazy_line) | 983 | if (pp->lazy_line) |
987 | param->retval = find_probe_point_lazy(sp_die, pf); | 984 | param->retval = find_probe_point_lazy(sp_die, pf); |
988 | else { | 985 | else { |
989 | if (dwarf_entrypc(sp_die, &pf->addr) != 0) { | 986 | if (dwarf_entrypc(sp_die, &pf->addr) != 0) { |
990 | pr_warning("Failed to get entry address of " | 987 | pr_warning("Failed to get entry address of " |
991 | "%s.\n", dwarf_diename(sp_die)); | 988 | "%s.\n", dwarf_diename(sp_die)); |
992 | param->retval = -ENOENT; | 989 | param->retval = -ENOENT; |
993 | return DWARF_CB_ABORT; | 990 | return DWARF_CB_ABORT; |
994 | } | 991 | } |
995 | pf->addr += pp->offset; | 992 | pf->addr += pp->offset; |
996 | /* TODO: Check the address in this function */ | 993 | /* TODO: Check the address in this function */ |
997 | param->retval = call_probe_finder(sp_die, pf); | 994 | param->retval = call_probe_finder(sp_die, pf); |
998 | } | 995 | } |
999 | } else { | 996 | } else |
1000 | struct dwarf_callback_param _param = {.data = (void *)pf, | ||
1001 | .retval = 0}; | ||
1002 | /* Inlined function: search instances */ | 997 | /* Inlined function: search instances */ |
1003 | dwarf_func_inline_instances(sp_die, probe_point_inline_cb, | 998 | param->retval = die_walk_instances(sp_die, |
1004 | &_param); | 999 | probe_point_inline_cb, (void *)pf); |
1005 | param->retval = _param.retval; | ||
1006 | } | ||
1007 | 1000 | ||
1008 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ | 1001 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ |
1009 | } | 1002 | } |
1010 | 1003 | ||
1011 | static int find_probe_point_by_func(struct probe_finder *pf) | 1004 | static int find_probe_point_by_func(struct probe_finder *pf) |
1012 | { | 1005 | { |
1013 | struct dwarf_callback_param _param = {.data = (void *)pf, | 1006 | struct dwarf_callback_param _param = {.data = (void *)pf, |
1014 | .retval = 0}; | 1007 | .retval = 0}; |
1015 | dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); | 1008 | dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); |
1016 | return _param.retval; | 1009 | return _param.retval; |
1017 | } | 1010 | } |
1018 | 1011 | ||
1019 | struct pubname_callback_param { | 1012 | struct pubname_callback_param { |
1020 | char *function; | 1013 | char *function; |
1021 | char *file; | 1014 | char *file; |
1022 | Dwarf_Die *cu_die; | 1015 | Dwarf_Die *cu_die; |
1023 | Dwarf_Die *sp_die; | 1016 | Dwarf_Die *sp_die; |
1024 | int found; | 1017 | int found; |
1025 | }; | 1018 | }; |
1026 | 1019 | ||
1027 | static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) | 1020 | static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) |
1028 | { | 1021 | { |
1029 | struct pubname_callback_param *param = data; | 1022 | struct pubname_callback_param *param = data; |
1030 | 1023 | ||
1031 | if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) { | 1024 | if (dwarf_offdie(dbg, gl->die_offset, param->sp_die)) { |
1032 | if (dwarf_tag(param->sp_die) != DW_TAG_subprogram) | 1025 | if (dwarf_tag(param->sp_die) != DW_TAG_subprogram) |
1033 | return DWARF_CB_OK; | 1026 | return DWARF_CB_OK; |
1034 | 1027 | ||
1035 | if (die_compare_name(param->sp_die, param->function)) { | 1028 | if (die_compare_name(param->sp_die, param->function)) { |
1036 | if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die)) | 1029 | if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die)) |
1037 | return DWARF_CB_OK; | 1030 | return DWARF_CB_OK; |
1038 | 1031 | ||
1039 | if (param->file && | 1032 | if (param->file && |
1040 | strtailcmp(param->file, dwarf_decl_file(param->sp_die))) | 1033 | strtailcmp(param->file, dwarf_decl_file(param->sp_die))) |
1041 | return DWARF_CB_OK; | 1034 | return DWARF_CB_OK; |
1042 | 1035 | ||
1043 | param->found = 1; | 1036 | param->found = 1; |
1044 | return DWARF_CB_ABORT; | 1037 | return DWARF_CB_ABORT; |
1045 | } | 1038 | } |
1046 | } | 1039 | } |
1047 | 1040 | ||
1048 | return DWARF_CB_OK; | 1041 | return DWARF_CB_OK; |
1049 | } | 1042 | } |
1050 | 1043 | ||
1051 | /* Find probe points from debuginfo */ | 1044 | /* Find probe points from debuginfo */ |
1052 | static int debuginfo__find_probes(struct debuginfo *self, | 1045 | static int debuginfo__find_probes(struct debuginfo *self, |
1053 | struct probe_finder *pf) | 1046 | struct probe_finder *pf) |
1054 | { | 1047 | { |
1055 | struct perf_probe_point *pp = &pf->pev->point; | 1048 | struct perf_probe_point *pp = &pf->pev->point; |
1056 | Dwarf_Off off, noff; | 1049 | Dwarf_Off off, noff; |
1057 | size_t cuhl; | 1050 | size_t cuhl; |
1058 | Dwarf_Die *diep; | 1051 | Dwarf_Die *diep; |
1059 | int ret = 0; | 1052 | int ret = 0; |
1060 | 1053 | ||
1061 | #if _ELFUTILS_PREREQ(0, 142) | 1054 | #if _ELFUTILS_PREREQ(0, 142) |
1062 | /* Get the call frame information from this dwarf */ | 1055 | /* Get the call frame information from this dwarf */ |
1063 | pf->cfi = dwarf_getcfi(self->dbg); | 1056 | pf->cfi = dwarf_getcfi(self->dbg); |
1064 | #endif | 1057 | #endif |
1065 | 1058 | ||
1066 | off = 0; | 1059 | off = 0; |
1067 | line_list__init(&pf->lcache); | 1060 | line_list__init(&pf->lcache); |
1068 | 1061 | ||
1069 | /* Fastpath: lookup by function name from .debug_pubnames section */ | 1062 | /* Fastpath: lookup by function name from .debug_pubnames section */ |
1070 | if (pp->function) { | 1063 | if (pp->function) { |
1071 | struct pubname_callback_param pubname_param = { | 1064 | struct pubname_callback_param pubname_param = { |
1072 | .function = pp->function, | 1065 | .function = pp->function, |
1073 | .file = pp->file, | 1066 | .file = pp->file, |
1074 | .cu_die = &pf->cu_die, | 1067 | .cu_die = &pf->cu_die, |
1075 | .sp_die = &pf->sp_die, | 1068 | .sp_die = &pf->sp_die, |
1076 | .found = 0, | 1069 | .found = 0, |
1077 | }; | 1070 | }; |
1078 | struct dwarf_callback_param probe_param = { | 1071 | struct dwarf_callback_param probe_param = { |
1079 | .data = pf, | 1072 | .data = pf, |
1080 | }; | 1073 | }; |
1081 | 1074 | ||
1082 | dwarf_getpubnames(self->dbg, pubname_search_cb, | 1075 | dwarf_getpubnames(self->dbg, pubname_search_cb, |
1083 | &pubname_param, 0); | 1076 | &pubname_param, 0); |
1084 | if (pubname_param.found) { | 1077 | if (pubname_param.found) { |
1085 | ret = probe_point_search_cb(&pf->sp_die, &probe_param); | 1078 | ret = probe_point_search_cb(&pf->sp_die, &probe_param); |
1086 | if (ret) | 1079 | if (ret) |
1087 | goto found; | 1080 | goto found; |
1088 | } | 1081 | } |
1089 | } | 1082 | } |
1090 | 1083 | ||
1091 | /* Loop on CUs (Compilation Unit) */ | 1084 | /* Loop on CUs (Compilation Unit) */ |
1092 | while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { | 1085 | while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { |
1093 | /* Get the DIE(Debugging Information Entry) of this CU */ | 1086 | /* Get the DIE(Debugging Information Entry) of this CU */ |
1094 | diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die); | 1087 | diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die); |
1095 | if (!diep) | 1088 | if (!diep) |
1096 | continue; | 1089 | continue; |
1097 | 1090 | ||
1098 | /* Check if target file is included. */ | 1091 | /* Check if target file is included. */ |
1099 | if (pp->file) | 1092 | if (pp->file) |
1100 | pf->fname = cu_find_realpath(&pf->cu_die, pp->file); | 1093 | pf->fname = cu_find_realpath(&pf->cu_die, pp->file); |
1101 | else | 1094 | else |
1102 | pf->fname = NULL; | 1095 | pf->fname = NULL; |
1103 | 1096 | ||
1104 | if (!pp->file || pf->fname) { | 1097 | if (!pp->file || pf->fname) { |
1105 | if (pp->function) | 1098 | if (pp->function) |
1106 | ret = find_probe_point_by_func(pf); | 1099 | ret = find_probe_point_by_func(pf); |
1107 | else if (pp->lazy_line) | 1100 | else if (pp->lazy_line) |
1108 | ret = find_probe_point_lazy(NULL, pf); | 1101 | ret = find_probe_point_lazy(NULL, pf); |
1109 | else { | 1102 | else { |
1110 | pf->lno = pp->line; | 1103 | pf->lno = pp->line; |
1111 | ret = find_probe_point_by_line(pf); | 1104 | ret = find_probe_point_by_line(pf); |
1112 | } | 1105 | } |
1113 | if (ret < 0) | 1106 | if (ret < 0) |
1114 | break; | 1107 | break; |
1115 | } | 1108 | } |
1116 | off = noff; | 1109 | off = noff; |
1117 | } | 1110 | } |
1118 | 1111 | ||
1119 | found: | 1112 | found: |
1120 | line_list__free(&pf->lcache); | 1113 | line_list__free(&pf->lcache); |
1121 | 1114 | ||
1122 | return ret; | 1115 | return ret; |
1123 | } | 1116 | } |
1124 | 1117 | ||
1125 | /* Add a found probe point into trace event list */ | 1118 | /* Add a found probe point into trace event list */ |
1126 | static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) | 1119 | static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) |
1127 | { | 1120 | { |
1128 | struct trace_event_finder *tf = | 1121 | struct trace_event_finder *tf = |
1129 | container_of(pf, struct trace_event_finder, pf); | 1122 | container_of(pf, struct trace_event_finder, pf); |
1130 | struct probe_trace_event *tev; | 1123 | struct probe_trace_event *tev; |
1131 | int ret, i; | 1124 | int ret, i; |
1132 | 1125 | ||
1133 | /* Check number of tevs */ | 1126 | /* Check number of tevs */ |
1134 | if (tf->ntevs == tf->max_tevs) { | 1127 | if (tf->ntevs == tf->max_tevs) { |
1135 | pr_warning("Too many( > %d) probe point found.\n", | 1128 | pr_warning("Too many( > %d) probe point found.\n", |
1136 | tf->max_tevs); | 1129 | tf->max_tevs); |
1137 | return -ERANGE; | 1130 | return -ERANGE; |
1138 | } | 1131 | } |
1139 | tev = &tf->tevs[tf->ntevs++]; | 1132 | tev = &tf->tevs[tf->ntevs++]; |
1140 | 1133 | ||
1141 | /* Trace point should be converted from subprogram DIE */ | 1134 | /* Trace point should be converted from subprogram DIE */ |
1142 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, | 1135 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, |
1143 | pf->pev->point.retprobe, &tev->point); | 1136 | pf->pev->point.retprobe, &tev->point); |
1144 | if (ret < 0) | 1137 | if (ret < 0) |
1145 | return ret; | 1138 | return ret; |
1146 | 1139 | ||
1147 | pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, | 1140 | pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, |
1148 | tev->point.offset); | 1141 | tev->point.offset); |
1149 | 1142 | ||
1150 | /* Find each argument */ | 1143 | /* Find each argument */ |
1151 | tev->nargs = pf->pev->nargs; | 1144 | tev->nargs = pf->pev->nargs; |
1152 | tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); | 1145 | tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); |
1153 | if (tev->args == NULL) | 1146 | if (tev->args == NULL) |
1154 | return -ENOMEM; | 1147 | return -ENOMEM; |
1155 | for (i = 0; i < pf->pev->nargs; i++) { | 1148 | for (i = 0; i < pf->pev->nargs; i++) { |
1156 | pf->pvar = &pf->pev->args[i]; | 1149 | pf->pvar = &pf->pev->args[i]; |
1157 | pf->tvar = &tev->args[i]; | 1150 | pf->tvar = &tev->args[i]; |
1158 | /* Variable should be found from scope DIE */ | 1151 | /* Variable should be found from scope DIE */ |
1159 | ret = find_variable(sc_die, pf); | 1152 | ret = find_variable(sc_die, pf); |
1160 | if (ret != 0) | 1153 | if (ret != 0) |
1161 | return ret; | 1154 | return ret; |
1162 | } | 1155 | } |
1163 | 1156 | ||
1164 | return 0; | 1157 | return 0; |
1165 | } | 1158 | } |
1166 | 1159 | ||
1167 | /* Find probe_trace_events specified by perf_probe_event from debuginfo */ | 1160 | /* Find probe_trace_events specified by perf_probe_event from debuginfo */ |
1168 | int debuginfo__find_trace_events(struct debuginfo *self, | 1161 | int debuginfo__find_trace_events(struct debuginfo *self, |
1169 | struct perf_probe_event *pev, | 1162 | struct perf_probe_event *pev, |
1170 | struct probe_trace_event **tevs, int max_tevs) | 1163 | struct probe_trace_event **tevs, int max_tevs) |
1171 | { | 1164 | { |
1172 | struct trace_event_finder tf = { | 1165 | struct trace_event_finder tf = { |
1173 | .pf = {.pev = pev, .callback = add_probe_trace_event}, | 1166 | .pf = {.pev = pev, .callback = add_probe_trace_event}, |
1174 | .max_tevs = max_tevs}; | 1167 | .max_tevs = max_tevs}; |
1175 | int ret; | 1168 | int ret; |
1176 | 1169 | ||
1177 | /* Allocate result tevs array */ | 1170 | /* Allocate result tevs array */ |
1178 | *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); | 1171 | *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs); |
1179 | if (*tevs == NULL) | 1172 | if (*tevs == NULL) |
1180 | return -ENOMEM; | 1173 | return -ENOMEM; |
1181 | 1174 | ||
1182 | tf.tevs = *tevs; | 1175 | tf.tevs = *tevs; |
1183 | tf.ntevs = 0; | 1176 | tf.ntevs = 0; |
1184 | 1177 | ||
1185 | ret = debuginfo__find_probes(self, &tf.pf); | 1178 | ret = debuginfo__find_probes(self, &tf.pf); |
1186 | if (ret < 0) { | 1179 | if (ret < 0) { |
1187 | free(*tevs); | 1180 | free(*tevs); |
1188 | *tevs = NULL; | 1181 | *tevs = NULL; |
1189 | return ret; | 1182 | return ret; |
1190 | } | 1183 | } |
1191 | 1184 | ||
1192 | return (ret < 0) ? ret : tf.ntevs; | 1185 | return (ret < 0) ? ret : tf.ntevs; |
1193 | } | 1186 | } |
1194 | 1187 | ||
1195 | #define MAX_VAR_LEN 64 | 1188 | #define MAX_VAR_LEN 64 |
1196 | 1189 | ||
1197 | /* Collect available variables in this scope */ | 1190 | /* Collect available variables in this scope */ |
1198 | static int collect_variables_cb(Dwarf_Die *die_mem, void *data) | 1191 | static int collect_variables_cb(Dwarf_Die *die_mem, void *data) |
1199 | { | 1192 | { |
1200 | struct available_var_finder *af = data; | 1193 | struct available_var_finder *af = data; |
1201 | struct variable_list *vl; | 1194 | struct variable_list *vl; |
1202 | char buf[MAX_VAR_LEN]; | 1195 | char buf[MAX_VAR_LEN]; |
1203 | int tag, ret; | 1196 | int tag, ret; |
1204 | 1197 | ||
1205 | vl = &af->vls[af->nvls - 1]; | 1198 | vl = &af->vls[af->nvls - 1]; |
1206 | 1199 | ||
1207 | tag = dwarf_tag(die_mem); | 1200 | tag = dwarf_tag(die_mem); |
1208 | if (tag == DW_TAG_formal_parameter || | 1201 | if (tag == DW_TAG_formal_parameter || |
1209 | tag == DW_TAG_variable) { | 1202 | tag == DW_TAG_variable) { |
1210 | ret = convert_variable_location(die_mem, af->pf.addr, | 1203 | ret = convert_variable_location(die_mem, af->pf.addr, |
1211 | af->pf.fb_ops, NULL); | 1204 | af->pf.fb_ops, NULL); |
1212 | if (ret == 0) { | 1205 | if (ret == 0) { |
1213 | ret = die_get_varname(die_mem, buf, MAX_VAR_LEN); | 1206 | ret = die_get_varname(die_mem, buf, MAX_VAR_LEN); |
1214 | pr_debug2("Add new var: %s\n", buf); | 1207 | pr_debug2("Add new var: %s\n", buf); |
1215 | if (ret > 0) | 1208 | if (ret > 0) |
1216 | strlist__add(vl->vars, buf); | 1209 | strlist__add(vl->vars, buf); |
1217 | } | 1210 | } |
1218 | } | 1211 | } |
1219 | 1212 | ||
1220 | if (af->child && dwarf_haspc(die_mem, af->pf.addr)) | 1213 | if (af->child && dwarf_haspc(die_mem, af->pf.addr)) |
1221 | return DIE_FIND_CB_CONTINUE; | 1214 | return DIE_FIND_CB_CONTINUE; |
1222 | else | 1215 | else |
1223 | return DIE_FIND_CB_SIBLING; | 1216 | return DIE_FIND_CB_SIBLING; |
1224 | } | 1217 | } |
1225 | 1218 | ||
1226 | /* Add a found vars into available variables list */ | 1219 | /* Add a found vars into available variables list */ |
1227 | static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) | 1220 | static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) |
1228 | { | 1221 | { |
1229 | struct available_var_finder *af = | 1222 | struct available_var_finder *af = |
1230 | container_of(pf, struct available_var_finder, pf); | 1223 | container_of(pf, struct available_var_finder, pf); |
1231 | struct variable_list *vl; | 1224 | struct variable_list *vl; |
1232 | Dwarf_Die die_mem; | 1225 | Dwarf_Die die_mem; |
1233 | int ret; | 1226 | int ret; |
1234 | 1227 | ||
1235 | /* Check number of tevs */ | 1228 | /* Check number of tevs */ |
1236 | if (af->nvls == af->max_vls) { | 1229 | if (af->nvls == af->max_vls) { |
1237 | pr_warning("Too many( > %d) probe point found.\n", af->max_vls); | 1230 | pr_warning("Too many( > %d) probe point found.\n", af->max_vls); |
1238 | return -ERANGE; | 1231 | return -ERANGE; |
1239 | } | 1232 | } |
1240 | vl = &af->vls[af->nvls++]; | 1233 | vl = &af->vls[af->nvls++]; |
1241 | 1234 | ||
1242 | /* Trace point should be converted from subprogram DIE */ | 1235 | /* Trace point should be converted from subprogram DIE */ |
1243 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, | 1236 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, |
1244 | pf->pev->point.retprobe, &vl->point); | 1237 | pf->pev->point.retprobe, &vl->point); |
1245 | if (ret < 0) | 1238 | if (ret < 0) |
1246 | return ret; | 1239 | return ret; |
1247 | 1240 | ||
1248 | pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, | 1241 | pr_debug("Probe point found: %s+%lu\n", vl->point.symbol, |
1249 | vl->point.offset); | 1242 | vl->point.offset); |
1250 | 1243 | ||
1251 | /* Find local variables */ | 1244 | /* Find local variables */ |
1252 | vl->vars = strlist__new(true, NULL); | 1245 | vl->vars = strlist__new(true, NULL); |
1253 | if (vl->vars == NULL) | 1246 | if (vl->vars == NULL) |
1254 | return -ENOMEM; | 1247 | return -ENOMEM; |
1255 | af->child = true; | 1248 | af->child = true; |
1256 | die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); | 1249 | die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); |
1257 | 1250 | ||
1258 | /* Find external variables */ | 1251 | /* Find external variables */ |
1259 | if (!af->externs) | 1252 | if (!af->externs) |
1260 | goto out; | 1253 | goto out; |
1261 | /* Don't need to search child DIE for externs. */ | 1254 | /* Don't need to search child DIE for externs. */ |
1262 | af->child = false; | 1255 | af->child = false; |
1263 | die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); | 1256 | die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); |
1264 | 1257 | ||
1265 | out: | 1258 | out: |
1266 | if (strlist__empty(vl->vars)) { | 1259 | if (strlist__empty(vl->vars)) { |
1267 | strlist__delete(vl->vars); | 1260 | strlist__delete(vl->vars); |
1268 | vl->vars = NULL; | 1261 | vl->vars = NULL; |
1269 | } | 1262 | } |
1270 | 1263 | ||
1271 | return ret; | 1264 | return ret; |
1272 | } | 1265 | } |
1273 | 1266 | ||
1274 | /* Find available variables at given probe point */ | 1267 | /* Find available variables at given probe point */ |
1275 | int debuginfo__find_available_vars_at(struct debuginfo *self, | 1268 | int debuginfo__find_available_vars_at(struct debuginfo *self, |
1276 | struct perf_probe_event *pev, | 1269 | struct perf_probe_event *pev, |
1277 | struct variable_list **vls, | 1270 | struct variable_list **vls, |
1278 | int max_vls, bool externs) | 1271 | int max_vls, bool externs) |
1279 | { | 1272 | { |
1280 | struct available_var_finder af = { | 1273 | struct available_var_finder af = { |
1281 | .pf = {.pev = pev, .callback = add_available_vars}, | 1274 | .pf = {.pev = pev, .callback = add_available_vars}, |
1282 | .max_vls = max_vls, .externs = externs}; | 1275 | .max_vls = max_vls, .externs = externs}; |
1283 | int ret; | 1276 | int ret; |
1284 | 1277 | ||
1285 | /* Allocate result vls array */ | 1278 | /* Allocate result vls array */ |
1286 | *vls = zalloc(sizeof(struct variable_list) * max_vls); | 1279 | *vls = zalloc(sizeof(struct variable_list) * max_vls); |
1287 | if (*vls == NULL) | 1280 | if (*vls == NULL) |
1288 | return -ENOMEM; | 1281 | return -ENOMEM; |
1289 | 1282 | ||
1290 | af.vls = *vls; | 1283 | af.vls = *vls; |
1291 | af.nvls = 0; | 1284 | af.nvls = 0; |
1292 | 1285 | ||
1293 | ret = debuginfo__find_probes(self, &af.pf); | 1286 | ret = debuginfo__find_probes(self, &af.pf); |
1294 | if (ret < 0) { | 1287 | if (ret < 0) { |
1295 | /* Free vlist for error */ | 1288 | /* Free vlist for error */ |
1296 | while (af.nvls--) { | 1289 | while (af.nvls--) { |
1297 | if (af.vls[af.nvls].point.symbol) | 1290 | if (af.vls[af.nvls].point.symbol) |
1298 | free(af.vls[af.nvls].point.symbol); | 1291 | free(af.vls[af.nvls].point.symbol); |
1299 | if (af.vls[af.nvls].vars) | 1292 | if (af.vls[af.nvls].vars) |
1300 | strlist__delete(af.vls[af.nvls].vars); | 1293 | strlist__delete(af.vls[af.nvls].vars); |
1301 | } | 1294 | } |
1302 | free(af.vls); | 1295 | free(af.vls); |
1303 | *vls = NULL; | 1296 | *vls = NULL; |
1304 | return ret; | 1297 | return ret; |
1305 | } | 1298 | } |
1306 | 1299 | ||
1307 | return (ret < 0) ? ret : af.nvls; | 1300 | return (ret < 0) ? ret : af.nvls; |
1308 | } | 1301 | } |
1309 | 1302 | ||
1310 | /* Reverse search */ | 1303 | /* Reverse search */ |
1311 | int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, | 1304 | int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, |
1312 | struct perf_probe_point *ppt) | 1305 | struct perf_probe_point *ppt) |
1313 | { | 1306 | { |
1314 | Dwarf_Die cudie, spdie, indie; | 1307 | Dwarf_Die cudie, spdie, indie; |
1315 | Dwarf_Addr _addr, baseaddr; | 1308 | Dwarf_Addr _addr, baseaddr; |
1316 | const char *fname = NULL, *func = NULL, *tmp; | 1309 | const char *fname = NULL, *func = NULL, *tmp; |
1317 | int baseline = 0, lineno = 0, ret = 0; | 1310 | int baseline = 0, lineno = 0, ret = 0; |
1318 | 1311 | ||
1319 | /* Adjust address with bias */ | 1312 | /* Adjust address with bias */ |
1320 | addr += self->bias; | 1313 | addr += self->bias; |
1321 | 1314 | ||
1322 | /* Find cu die */ | 1315 | /* Find cu die */ |
1323 | if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) { | 1316 | if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) { |
1324 | pr_warning("Failed to find debug information for address %lx\n", | 1317 | pr_warning("Failed to find debug information for address %lx\n", |
1325 | addr); | 1318 | addr); |
1326 | ret = -EINVAL; | 1319 | ret = -EINVAL; |
1327 | goto end; | 1320 | goto end; |
1328 | } | 1321 | } |
1329 | 1322 | ||
1330 | /* Find a corresponding line (filename and lineno) */ | 1323 | /* Find a corresponding line (filename and lineno) */ |
1331 | cu_find_lineinfo(&cudie, addr, &fname, &lineno); | 1324 | cu_find_lineinfo(&cudie, addr, &fname, &lineno); |
1332 | /* Don't care whether it failed or not */ | 1325 | /* Don't care whether it failed or not */ |
1333 | 1326 | ||
1334 | /* Find a corresponding function (name, baseline and baseaddr) */ | 1327 | /* Find a corresponding function (name, baseline and baseaddr) */ |
1335 | if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { | 1328 | if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { |
1336 | /* Get function entry information */ | 1329 | /* Get function entry information */ |
1337 | tmp = dwarf_diename(&spdie); | 1330 | tmp = dwarf_diename(&spdie); |
1338 | if (!tmp || | 1331 | if (!tmp || |
1339 | dwarf_entrypc(&spdie, &baseaddr) != 0 || | 1332 | dwarf_entrypc(&spdie, &baseaddr) != 0 || |
1340 | dwarf_decl_line(&spdie, &baseline) != 0) | 1333 | dwarf_decl_line(&spdie, &baseline) != 0) |
1341 | goto post; | 1334 | goto post; |
1342 | func = tmp; | 1335 | func = tmp; |
1343 | 1336 | ||
1344 | if (addr == (unsigned long)baseaddr) | 1337 | if (addr == (unsigned long)baseaddr) |
1345 | /* Function entry - Relative line number is 0 */ | 1338 | /* Function entry - Relative line number is 0 */ |
1346 | lineno = baseline; | 1339 | lineno = baseline; |
1347 | else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, | 1340 | else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, |
1348 | &indie)) { | 1341 | &indie)) { |
1349 | if (dwarf_entrypc(&indie, &_addr) == 0 && | 1342 | if (dwarf_entrypc(&indie, &_addr) == 0 && |
1350 | _addr == addr) | 1343 | _addr == addr) |
1351 | /* | 1344 | /* |
1352 | * addr is at an inline function entry. | 1345 | * addr is at an inline function entry. |
1353 | * In this case, lineno should be the call-site | 1346 | * In this case, lineno should be the call-site |
1354 | * line number. | 1347 | * line number. |
1355 | */ | 1348 | */ |
1356 | lineno = die_get_call_lineno(&indie); | 1349 | lineno = die_get_call_lineno(&indie); |
1357 | else { | 1350 | else { |
1358 | /* | 1351 | /* |
1359 | * addr is in an inline function body. | 1352 | * addr is in an inline function body. |
1360 | * Since lineno points one of the lines | 1353 | * Since lineno points one of the lines |
1361 | * of the inline function, baseline should | 1354 | * of the inline function, baseline should |
1362 | * be the entry line of the inline function. | 1355 | * be the entry line of the inline function. |
1363 | */ | 1356 | */ |
1364 | tmp = dwarf_diename(&indie); | 1357 | tmp = dwarf_diename(&indie); |
1365 | if (tmp && | 1358 | if (tmp && |
1366 | dwarf_decl_line(&spdie, &baseline) == 0) | 1359 | dwarf_decl_line(&spdie, &baseline) == 0) |
1367 | func = tmp; | 1360 | func = tmp; |
1368 | } | 1361 | } |
1369 | } | 1362 | } |
1370 | } | 1363 | } |
1371 | 1364 | ||
1372 | post: | 1365 | post: |
1373 | /* Make a relative line number or an offset */ | 1366 | /* Make a relative line number or an offset */ |
1374 | if (lineno) | 1367 | if (lineno) |
1375 | ppt->line = lineno - baseline; | 1368 | ppt->line = lineno - baseline; |
1376 | else if (func) | 1369 | else if (func) |
1377 | ppt->offset = addr - (unsigned long)baseaddr; | 1370 | ppt->offset = addr - (unsigned long)baseaddr; |
1378 | 1371 | ||
1379 | /* Duplicate strings */ | 1372 | /* Duplicate strings */ |
1380 | if (func) { | 1373 | if (func) { |
1381 | ppt->function = strdup(func); | 1374 | ppt->function = strdup(func); |
1382 | if (ppt->function == NULL) { | 1375 | if (ppt->function == NULL) { |
1383 | ret = -ENOMEM; | 1376 | ret = -ENOMEM; |
1384 | goto end; | 1377 | goto end; |
1385 | } | 1378 | } |
1386 | } | 1379 | } |
1387 | if (fname) { | 1380 | if (fname) { |
1388 | ppt->file = strdup(fname); | 1381 | ppt->file = strdup(fname); |
1389 | if (ppt->file == NULL) { | 1382 | if (ppt->file == NULL) { |
1390 | if (ppt->function) { | 1383 | if (ppt->function) { |
1391 | free(ppt->function); | 1384 | free(ppt->function); |
1392 | ppt->function = NULL; | 1385 | ppt->function = NULL; |
1393 | } | 1386 | } |
1394 | ret = -ENOMEM; | 1387 | ret = -ENOMEM; |
1395 | goto end; | 1388 | goto end; |
1396 | } | 1389 | } |
1397 | } | 1390 | } |
1398 | end: | 1391 | end: |
1399 | if (ret == 0 && (fname || func)) | 1392 | if (ret == 0 && (fname || func)) |
1400 | ret = 1; /* Found a point */ | 1393 | ret = 1; /* Found a point */ |
1401 | return ret; | 1394 | return ret; |
1402 | } | 1395 | } |
1403 | 1396 | ||
1404 | /* Add a line and store the src path */ | 1397 | /* Add a line and store the src path */ |
1405 | static int line_range_add_line(const char *src, unsigned int lineno, | 1398 | static int line_range_add_line(const char *src, unsigned int lineno, |
1406 | struct line_range *lr) | 1399 | struct line_range *lr) |
1407 | { | 1400 | { |
1408 | /* Copy source path */ | 1401 | /* Copy source path */ |
1409 | if (!lr->path) { | 1402 | if (!lr->path) { |
1410 | lr->path = strdup(src); | 1403 | lr->path = strdup(src); |
1411 | if (lr->path == NULL) | 1404 | if (lr->path == NULL) |
1412 | return -ENOMEM; | 1405 | return -ENOMEM; |
1413 | } | 1406 | } |
1414 | return line_list__add_line(&lr->line_list, lineno); | 1407 | return line_list__add_line(&lr->line_list, lineno); |
1415 | } | 1408 | } |
1416 | 1409 | ||
1417 | static int line_range_walk_cb(const char *fname, int lineno, | 1410 | static int line_range_walk_cb(const char *fname, int lineno, |
1418 | Dwarf_Addr addr __used, | 1411 | Dwarf_Addr addr __used, |
1419 | void *data) | 1412 | void *data) |
1420 | { | 1413 | { |
1421 | struct line_finder *lf = data; | 1414 | struct line_finder *lf = data; |
1422 | 1415 | ||
1423 | if ((strtailcmp(fname, lf->fname) != 0) || | 1416 | if ((strtailcmp(fname, lf->fname) != 0) || |
1424 | (lf->lno_s > lineno || lf->lno_e < lineno)) | 1417 | (lf->lno_s > lineno || lf->lno_e < lineno)) |
1425 | return 0; | 1418 | return 0; |
1426 | 1419 | ||
1427 | if (line_range_add_line(fname, lineno, lf->lr) < 0) | 1420 | if (line_range_add_line(fname, lineno, lf->lr) < 0) |
1428 | return -EINVAL; | 1421 | return -EINVAL; |
1429 | 1422 | ||
1430 | return 0; | 1423 | return 0; |
1431 | } | 1424 | } |
1432 | 1425 | ||
1433 | /* Find line range from its line number */ | 1426 | /* Find line range from its line number */ |
1434 | static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | 1427 | static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) |
1435 | { | 1428 | { |
1436 | int ret; | 1429 | int ret; |
1437 | 1430 | ||
1438 | ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); | 1431 | ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); |
1439 | 1432 | ||
1440 | /* Update status */ | 1433 | /* Update status */ |
1441 | if (ret >= 0) | 1434 | if (ret >= 0) |
1442 | if (!list_empty(&lf->lr->line_list)) | 1435 | if (!list_empty(&lf->lr->line_list)) |
1443 | ret = lf->found = 1; | 1436 | ret = lf->found = 1; |
1444 | else | 1437 | else |
1445 | ret = 0; /* Lines are not found */ | 1438 | ret = 0; /* Lines are not found */ |
1446 | else { | 1439 | else { |
1447 | free(lf->lr->path); | 1440 | free(lf->lr->path); |
1448 | lf->lr->path = NULL; | 1441 | lf->lr->path = NULL; |
1449 | } | 1442 | } |
1450 | return ret; | 1443 | return ret; |
1451 | } | 1444 | } |
1452 | 1445 | ||
1453 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) | 1446 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) |
1454 | { | 1447 | { |
1455 | struct dwarf_callback_param *param = data; | 1448 | find_line_range_by_line(in_die, data); |
1456 | 1449 | ||
1457 | param->retval = find_line_range_by_line(in_die, param->data); | ||
1458 | |||
1459 | /* | 1450 | /* |
1460 | * We have to check all instances of inlined function, because | 1451 | * We have to check all instances of inlined function, because |
1461 | * some execution paths can be optimized out depends on the | 1452 | * some execution paths can be optimized out depends on the |
1462 | * function argument of instances | 1453 | * function argument of instances |
1463 | */ | 1454 | */ |
1464 | return DWARF_CB_OK; | 1455 | return 0; |
1465 | } | 1456 | } |
1466 | 1457 | ||
1467 | /* Search function from function name */ | 1458 | /* Search function from function name */ |
1468 | static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | 1459 | static int line_range_search_cb(Dwarf_Die *sp_die, void *data) |
1469 | { | 1460 | { |
1470 | struct dwarf_callback_param *param = data; | 1461 | struct dwarf_callback_param *param = data; |
1471 | struct line_finder *lf = param->data; | 1462 | struct line_finder *lf = param->data; |
1472 | struct line_range *lr = lf->lr; | 1463 | struct line_range *lr = lf->lr; |
1473 | 1464 | ||
1474 | /* Check declared file */ | 1465 | /* Check declared file */ |
1475 | if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) | 1466 | if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) |
1476 | return DWARF_CB_OK; | 1467 | return DWARF_CB_OK; |
1477 | 1468 | ||
1478 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && | 1469 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && |
1479 | die_compare_name(sp_die, lr->function)) { | 1470 | die_compare_name(sp_die, lr->function)) { |
1480 | lf->fname = dwarf_decl_file(sp_die); | 1471 | lf->fname = dwarf_decl_file(sp_die); |
1481 | dwarf_decl_line(sp_die, &lr->offset); | 1472 | dwarf_decl_line(sp_die, &lr->offset); |
1482 | pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); | 1473 | pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); |
1483 | lf->lno_s = lr->offset + lr->start; | 1474 | lf->lno_s = lr->offset + lr->start; |
1484 | if (lf->lno_s < 0) /* Overflow */ | 1475 | if (lf->lno_s < 0) /* Overflow */ |
1485 | lf->lno_s = INT_MAX; | 1476 | lf->lno_s = INT_MAX; |
1486 | lf->lno_e = lr->offset + lr->end; | 1477 | lf->lno_e = lr->offset + lr->end; |
1487 | if (lf->lno_e < 0) /* Overflow */ | 1478 | if (lf->lno_e < 0) /* Overflow */ |
1488 | lf->lno_e = INT_MAX; | 1479 | lf->lno_e = INT_MAX; |
1489 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); | 1480 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); |
1490 | lr->start = lf->lno_s; | 1481 | lr->start = lf->lno_s; |
1491 | lr->end = lf->lno_e; | 1482 | lr->end = lf->lno_e; |
1492 | if (dwarf_func_inline(sp_die)) { | 1483 | if (dwarf_func_inline(sp_die)) |
1493 | struct dwarf_callback_param _param; | 1484 | param->retval = die_walk_instances(sp_die, |
1494 | _param.data = (void *)lf; | 1485 | line_range_inline_cb, lf); |
1495 | _param.retval = 0; | 1486 | else |
1496 | dwarf_func_inline_instances(sp_die, | ||
1497 | line_range_inline_cb, | ||
1498 | &_param); | ||
1499 | param->retval = _param.retval; | ||
1500 | } else | ||
1501 | param->retval = find_line_range_by_line(sp_die, lf); | 1487 | param->retval = find_line_range_by_line(sp_die, lf); |
1502 | return DWARF_CB_ABORT; | 1488 | return DWARF_CB_ABORT; |
1503 | } | 1489 | } |
1504 | return DWARF_CB_OK; | 1490 | return DWARF_CB_OK; |
1505 | } | 1491 | } |
1506 | 1492 | ||
1507 | static int find_line_range_by_func(struct line_finder *lf) | 1493 | static int find_line_range_by_func(struct line_finder *lf) |
1508 | { | 1494 | { |
1509 | struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; | 1495 | struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; |
1510 | dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); | 1496 | dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); |
1511 | return param.retval; | 1497 | return param.retval; |
1512 | } | 1498 | } |
1513 | 1499 | ||
1514 | int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr) | 1500 | int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr) |
1515 | { | 1501 | { |
1516 | struct line_finder lf = {.lr = lr, .found = 0}; | 1502 | struct line_finder lf = {.lr = lr, .found = 0}; |
1517 | int ret = 0; | 1503 | int ret = 0; |
1518 | Dwarf_Off off = 0, noff; | 1504 | Dwarf_Off off = 0, noff; |
1519 | size_t cuhl; | 1505 | size_t cuhl; |
1520 | Dwarf_Die *diep; | 1506 | Dwarf_Die *diep; |
1521 | const char *comp_dir; | 1507 | const char *comp_dir; |
1522 | 1508 | ||
1523 | /* Fastpath: lookup by function name from .debug_pubnames section */ | 1509 | /* Fastpath: lookup by function name from .debug_pubnames section */ |
1524 | if (lr->function) { | 1510 | if (lr->function) { |
1525 | struct pubname_callback_param pubname_param = { | 1511 | struct pubname_callback_param pubname_param = { |
1526 | .function = lr->function, .file = lr->file, | 1512 | .function = lr->function, .file = lr->file, |
1527 | .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0}; | 1513 | .cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0}; |
1528 | struct dwarf_callback_param line_range_param = { | 1514 | struct dwarf_callback_param line_range_param = { |
1529 | .data = (void *)&lf, .retval = 0}; | 1515 | .data = (void *)&lf, .retval = 0}; |
1530 | 1516 | ||
1531 | dwarf_getpubnames(self->dbg, pubname_search_cb, | 1517 | dwarf_getpubnames(self->dbg, pubname_search_cb, |
1532 | &pubname_param, 0); | 1518 | &pubname_param, 0); |
1533 | if (pubname_param.found) { | 1519 | if (pubname_param.found) { |
1534 | line_range_search_cb(&lf.sp_die, &line_range_param); | 1520 | line_range_search_cb(&lf.sp_die, &line_range_param); |
1535 | if (lf.found) | 1521 | if (lf.found) |
1536 | goto found; | 1522 | goto found; |
1537 | } | 1523 | } |
1538 | } | 1524 | } |
1539 | 1525 | ||
1540 | /* Loop on CUs (Compilation Unit) */ | 1526 | /* Loop on CUs (Compilation Unit) */ |
1541 | while (!lf.found && ret >= 0) { | 1527 | while (!lf.found && ret >= 0) { |
1542 | if (dwarf_nextcu(self->dbg, off, &noff, &cuhl, | 1528 | if (dwarf_nextcu(self->dbg, off, &noff, &cuhl, |
1543 | NULL, NULL, NULL) != 0) | 1529 | NULL, NULL, NULL) != 0) |
1544 | break; | 1530 | break; |
1545 | 1531 | ||
1546 | /* Get the DIE(Debugging Information Entry) of this CU */ | 1532 | /* Get the DIE(Debugging Information Entry) of this CU */ |
1547 | diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die); | 1533 | diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die); |
1548 | if (!diep) | 1534 | if (!diep) |
1549 | continue; | 1535 | continue; |
1550 | 1536 | ||
1551 | /* Check if target file is included. */ | 1537 | /* Check if target file is included. */ |
1552 | if (lr->file) | 1538 | if (lr->file) |
1553 | lf.fname = cu_find_realpath(&lf.cu_die, lr->file); | 1539 | lf.fname = cu_find_realpath(&lf.cu_die, lr->file); |
1554 | else | 1540 | else |
1555 | lf.fname = 0; | 1541 | lf.fname = 0; |
1556 | 1542 | ||
1557 | if (!lr->file || lf.fname) { | 1543 | if (!lr->file || lf.fname) { |
1558 | if (lr->function) | 1544 | if (lr->function) |
1559 | ret = find_line_range_by_func(&lf); | 1545 | ret = find_line_range_by_func(&lf); |
1560 | else { | 1546 | else { |
1561 | lf.lno_s = lr->start; | 1547 | lf.lno_s = lr->start; |
1562 | lf.lno_e = lr->end; | 1548 | lf.lno_e = lr->end; |
1563 | ret = find_line_range_by_line(NULL, &lf); | 1549 | ret = find_line_range_by_line(NULL, &lf); |
1564 | } | 1550 | } |
1565 | } | 1551 | } |
1566 | off = noff; | 1552 | off = noff; |
1567 | } | 1553 | } |
1568 | 1554 | ||
1569 | found: | 1555 | found: |
1570 | /* Store comp_dir */ | 1556 | /* Store comp_dir */ |
1571 | if (lf.found) { | 1557 | if (lf.found) { |
1572 | comp_dir = cu_get_comp_dir(&lf.cu_die); | 1558 | comp_dir = cu_get_comp_dir(&lf.cu_die); |
1573 | if (comp_dir) { | 1559 | if (comp_dir) { |
1574 | lr->comp_dir = strdup(comp_dir); | 1560 | lr->comp_dir = strdup(comp_dir); |
1575 | if (!lr->comp_dir) | 1561 | if (!lr->comp_dir) |
1576 | ret = -ENOMEM; | 1562 | ret = -ENOMEM; |
1577 | } | 1563 | } |