diff options
author | Masami Hiramatsu <mhiramat@redhat.com> | 2010-03-16 18:05:58 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-03-17 06:32:31 -0400 |
commit | 016f262e4fb10c6ecff709317098912f94a21efa (patch) | |
tree | e1fcdcb3f842f5eda123893de083a1cdfcb5528e /tools/perf/util/probe-finder.c | |
parent | 95a3e4c4e21de1920a2ddb54bfc57c0af7e2561e (diff) |
perf probe: Introduce die_find_child() function
Introduce die_find_child() function to integrate DIE-tree
searching functions.
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220558.32050.7905.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r-- | tools/perf/util/probe-finder.c | 136 |
1 files changed, 80 insertions, 56 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index c91a9605c162..3942e14e95cf 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -186,6 +186,62 @@ static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname) | |||
186 | return src; | 186 | return src; |
187 | } | 187 | } |
188 | 188 | ||
189 | /* Compare diename and tname */ | ||
190 | static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | ||
191 | { | ||
192 | const char *name; | ||
193 | name = dwarf_diename(dw_die); | ||
194 | DIE_IF(name == NULL); | ||
195 | return strcmp(tname, name); | ||
196 | } | ||
197 | |||
198 | /* Get entry pc(or low pc, 1st entry of ranges) of the die */ | ||
199 | static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die) | ||
200 | { | ||
201 | Dwarf_Addr epc; | ||
202 | int ret; | ||
203 | |||
204 | ret = dwarf_entrypc(dw_die, &epc); | ||
205 | DIE_IF(ret == -1); | ||
206 | return epc; | ||
207 | } | ||
208 | |||
209 | /* Return values for die_find callbacks */ | ||
210 | enum { | ||
211 | DIE_FIND_CB_FOUND = 0, /* End of Search */ | ||
212 | DIE_FIND_CB_CHILD = 1, /* Search only children */ | ||
213 | DIE_FIND_CB_SIBLING = 2, /* Search only siblings */ | ||
214 | DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */ | ||
215 | }; | ||
216 | |||
217 | /* Search a child die */ | ||
218 | static Dwarf_Die *die_find_child(Dwarf_Die *rt_die, | ||
219 | int (*callback)(Dwarf_Die *, void *), | ||
220 | void *data, Dwarf_Die *die_mem) | ||
221 | { | ||
222 | Dwarf_Die child_die; | ||
223 | int ret; | ||
224 | |||
225 | ret = dwarf_child(rt_die, die_mem); | ||
226 | if (ret != 0) | ||
227 | return NULL; | ||
228 | |||
229 | do { | ||
230 | ret = callback(die_mem, data); | ||
231 | if (ret == DIE_FIND_CB_FOUND) | ||
232 | return die_mem; | ||
233 | |||
234 | if ((ret & DIE_FIND_CB_CHILD) && | ||
235 | die_find_child(die_mem, callback, data, &child_die)) { | ||
236 | memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); | ||
237 | return die_mem; | ||
238 | } | ||
239 | } while ((ret & DIE_FIND_CB_SIBLING) && | ||
240 | dwarf_siblingof(die_mem, die_mem) == 0); | ||
241 | |||
242 | return NULL; | ||
243 | } | ||
244 | |||
189 | struct __addr_die_search_param { | 245 | struct __addr_die_search_param { |
190 | Dwarf_Addr addr; | 246 | Dwarf_Addr addr; |
191 | Dwarf_Die *die_mem; | 247 | Dwarf_Die *die_mem; |
@@ -217,77 +273,45 @@ static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr, | |||
217 | return die_mem; | 273 | return die_mem; |
218 | } | 274 | } |
219 | 275 | ||
220 | /* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */ | 276 | /* die_find callback for inline function search */ |
221 | static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 277 | static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) |
222 | Dwarf_Die *die_mem) | ||
223 | { | 278 | { |
224 | Dwarf_Die child_die; | 279 | Dwarf_Addr *addr = data; |
225 | int ret; | ||
226 | 280 | ||
227 | ret = dwarf_child(sp_die, die_mem); | 281 | if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && |
228 | if (ret != 0) | 282 | dwarf_haspc(die_mem, *addr)) |
229 | return NULL; | 283 | return DIE_FIND_CB_FOUND; |
230 | |||
231 | do { | ||
232 | if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && | ||
233 | dwarf_haspc(die_mem, addr)) | ||
234 | return die_mem; | ||
235 | 284 | ||
236 | if (die_find_inlinefunc(die_mem, addr, &child_die)) { | 285 | return DIE_FIND_CB_CONTINUE; |
237 | memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); | ||
238 | return die_mem; | ||
239 | } | ||
240 | } while (dwarf_siblingof(die_mem, die_mem) == 0); | ||
241 | |||
242 | return NULL; | ||
243 | } | 286 | } |
244 | 287 | ||
245 | /* Compare diename and tname */ | 288 | /* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */ |
246 | static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | 289 | static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
290 | Dwarf_Die *die_mem) | ||
247 | { | 291 | { |
248 | const char *name; | 292 | return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); |
249 | name = dwarf_diename(dw_die); | ||
250 | DIE_IF(name == NULL); | ||
251 | return strcmp(tname, name); | ||
252 | } | 293 | } |
253 | 294 | ||
254 | /* Get entry pc(or low pc, 1st entry of ranges) of the die */ | 295 | static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) |
255 | static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die) | ||
256 | { | 296 | { |
257 | Dwarf_Addr epc; | 297 | const char *name = data; |
258 | int ret; | 298 | int tag; |
259 | 299 | ||
260 | ret = dwarf_entrypc(dw_die, &epc); | 300 | tag = dwarf_tag(die_mem); |
261 | DIE_IF(ret == -1); | 301 | if ((tag == DW_TAG_formal_parameter || |
262 | return epc; | 302 | tag == DW_TAG_variable) && |
303 | (die_compare_name(die_mem, name) == 0)) | ||
304 | return DIE_FIND_CB_FOUND; | ||
305 | |||
306 | return DIE_FIND_CB_CONTINUE; | ||
263 | } | 307 | } |
264 | 308 | ||
265 | /* Get a variable die */ | 309 | /* Find a variable called 'name' */ |
266 | static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name, | 310 | static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name, |
267 | Dwarf_Die *die_mem) | 311 | Dwarf_Die *die_mem) |
268 | { | 312 | { |
269 | Dwarf_Die child_die; | 313 | return die_find_child(sp_die, __die_find_variable_cb, (void *)name, |
270 | int tag; | 314 | die_mem); |
271 | int ret; | ||
272 | |||
273 | ret = dwarf_child(sp_die, die_mem); | ||
274 | if (ret != 0) | ||
275 | return NULL; | ||
276 | |||
277 | do { | ||
278 | tag = dwarf_tag(die_mem); | ||
279 | if ((tag == DW_TAG_formal_parameter || | ||
280 | tag == DW_TAG_variable) && | ||
281 | (die_compare_name(die_mem, name) == 0)) | ||
282 | return die_mem; | ||
283 | |||
284 | if (die_find_variable(die_mem, name, &child_die)) { | ||
285 | memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); | ||
286 | return die_mem; | ||
287 | } | ||
288 | } while (dwarf_siblingof(die_mem, die_mem) == 0); | ||
289 | |||
290 | return NULL; | ||
291 | } | 315 | } |
292 | 316 | ||
293 | /* | 317 | /* |