aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2010-02-25 08:35:50 -0500
committerIngo Molnar <mingo@elte.hu>2010-02-25 11:49:29 -0500
commite92b85e1ffaa0bd8e5d92e7c378a3909e7f23122 (patch)
tree6bd934ca363a3529ad4ecb1112c1d2c70c13089b /tools/perf/util
parent804b36068eccd8163ccea420c662fb5d1a21b141 (diff)
perf probe: Use libdw callback routines
Use libdw callback functions aggressively, and remove local tree-search API. This change simplifies the code. Changes in v3: - Cast Dwarf_Addr to uintmax_t for printf-formats. Changes in v2: - Cast Dwarf_Addr to unsigned long long for printf-formats. 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: Peter Zijlstra <peterz@infradead.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Mike Galbraith <efault@gmx.de> Cc: K.Prasad <prasad@linux.vnet.ibm.com> Cc: Ulrich Drepper <drepper@redhat.com> Cc: Roland McGrath <roland@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> LKML-Reference: <20100225133549.6725.81499.stgit@localhost6.localdomain6> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/probe-finder.c262
-rw-r--r--tools/perf/util/probe-finder.h1
2 files changed, 86 insertions, 177 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c422472fe4d1..6305f344f382 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -38,13 +38,6 @@
38#include "probe-finder.h" 38#include "probe-finder.h"
39 39
40 40
41/* Dwarf_Die Linkage to parent Die */
42struct die_link {
43 struct die_link *parent; /* Parent die */
44 Dwarf_Die die; /* Current die */
45};
46
47
48/* 41/*
49 * Generic dwarf analysis helpers 42 * Generic dwarf analysis helpers
50 */ 43 */
@@ -177,26 +170,6 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
177 return strcmp(tname, name); 170 return strcmp(tname, name);
178} 171}
179 172
180/* Check the address is in the subprogram(function). */
181static bool die_within_subprogram(Dwarf_Die *sp_die, Dwarf_Addr addr,
182 size_t *offs)
183{
184 Dwarf_Addr epc;
185 int ret;
186
187 ret = dwarf_haspc(sp_die, addr);
188 if (ret <= 0)
189 return false;
190
191 if (offs) {
192 ret = dwarf_entrypc(sp_die, &epc);
193 DIE_IF(ret == -1);
194 *offs = addr - epc;
195 }
196
197 return true;
198}
199
200/* Get entry pc(or low pc, 1st entry of ranges) of the die */ 173/* Get entry pc(or low pc, 1st entry of ranges) of the die */
201static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die) 174static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
202{ 175{
@@ -208,70 +181,34 @@ static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
208 return epc; 181 return epc;
209} 182}
210 183
211/* Check if the abstract origin's address or not */ 184/* Get a variable die */
212static bool die_compare_abstract_origin(Dwarf_Die *in_die, void *origin_addr) 185static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
213{ 186 Dwarf_Die *die_mem)
214 Dwarf_Attribute attr;
215 Dwarf_Die origin;
216
217 if (!dwarf_attr(in_die, DW_AT_abstract_origin, &attr))
218 return false;
219 if (!dwarf_formref_die(&attr, &origin))
220 return false;
221
222 return origin.addr == origin_addr;
223}
224
225/*
226 * Search a Die from Die tree.
227 * Note: cur_link->die should be deallocated in this function.
228 */
229static int __search_die_tree(struct die_link *cur_link,
230 int (*die_cb)(struct die_link *, void *),
231 void *data)
232{ 187{
233 struct die_link new_link; 188 Dwarf_Die child_die;
189 int tag;
234 int ret; 190 int ret;
235 191
236 if (!die_cb) 192 ret = dwarf_child(sp_die, die_mem);
237 return 0; 193 if (ret != 0)
238 194 return NULL;
239 /* Check current die */
240 while (!(ret = die_cb(cur_link, data))) {
241 /* Check child die */
242 ret = dwarf_child(&cur_link->die, &new_link.die);
243 if (ret == 0) {
244 new_link.parent = cur_link;
245 ret = __search_die_tree(&new_link, die_cb, data);
246 if (ret)
247 break;
248 }
249 195
250 /* Move to next sibling */ 196 do {
251 ret = dwarf_siblingof(&cur_link->die, &cur_link->die); 197 tag = dwarf_tag(die_mem);
252 if (ret != 0) 198 if ((tag == DW_TAG_formal_parameter ||
253 return 0; 199 tag == DW_TAG_variable) &&
254 } 200 (die_compare_name(die_mem, name) == 0))
255 return ret; 201 return die_mem;
256}
257 202
258/* Search a die in its children's die tree */ 203 if (die_find_variable(die_mem, name, &child_die)) {
259static int search_die_from_children(Dwarf_Die *parent_die, 204 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
260 int (*die_cb)(struct die_link *, void *), 205 return die_mem;
261 void *data) 206 }
262{ 207 } while (dwarf_siblingof(die_mem, die_mem) == 0);
263 struct die_link new_link;
264 int ret;
265 208
266 new_link.parent = NULL; 209 return NULL;
267 ret = dwarf_child(parent_die, &new_link.die);
268 if (ret == 0)
269 return __search_die_tree(&new_link, die_cb, data);
270 else
271 return 0;
272} 210}
273 211
274
275/* 212/*
276 * Probe finder related functions 213 * Probe finder related functions
277 */ 214 */
@@ -347,28 +284,13 @@ error:
347 " Perhaps, it has been optimized out.", pf->var); 284 " Perhaps, it has been optimized out.", pf->var);
348} 285}
349 286
350static int variable_search_cb(struct die_link *dlink, void *data)
351{
352 struct probe_finder *pf = (struct probe_finder *)data;
353 int tag;
354
355 tag = dwarf_tag(&dlink->die);
356 DIE_IF(tag < 0);
357 if ((tag == DW_TAG_formal_parameter ||
358 tag == DW_TAG_variable) &&
359 (die_compare_name(&dlink->die, pf->var) == 0)) {
360 show_variable(&dlink->die, pf);
361 return 1;
362 }
363 /* TODO: Support struct members and arrays */
364 return 0;
365}
366
367/* Find a variable in a subprogram die */ 287/* Find a variable in a subprogram die */
368static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) 288static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
369{ 289{
370 int ret; 290 int ret;
291 Dwarf_Die vr_die;
371 292
293 /* TODO: Support struct members and arrays */
372 if (!is_c_varname(pf->var)) { 294 if (!is_c_varname(pf->var)) {
373 /* Output raw parameters */ 295 /* Output raw parameters */
374 ret = snprintf(pf->buf, pf->len, " %s", pf->var); 296 ret = snprintf(pf->buf, pf->len, " %s", pf->var);
@@ -379,31 +301,42 @@ static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
379 301
380 pr_debug("Searching '%s' variable in context.\n", pf->var); 302 pr_debug("Searching '%s' variable in context.\n", pf->var);
381 /* Search child die for local variables and parameters. */ 303 /* Search child die for local variables and parameters. */
382 ret = search_die_from_children(sp_die, variable_search_cb, pf); 304 if (!die_find_variable(sp_die, pf->var, &vr_die))
383 if (!ret)
384 die("Failed to find '%s' in this function.", pf->var); 305 die("Failed to find '%s' in this function.", pf->var);
306
307 show_variable(&vr_die, pf);
385} 308}
386 309
387/* Show a probe point to output buffer */ 310/* Show a probe point to output buffer */
388static void show_probe_point(Dwarf_Die *sp_die, size_t offs, 311static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
389 struct probe_finder *pf)
390{ 312{
391 struct probe_point *pp = pf->pp; 313 struct probe_point *pp = pf->pp;
314 Dwarf_Addr eaddr;
315 Dwarf_Die die_mem;
392 const char *name; 316 const char *name;
393 char tmp[MAX_PROBE_BUFFER]; 317 char tmp[MAX_PROBE_BUFFER];
394 int ret, i, len; 318 int ret, i, len;
395 Dwarf_Attribute fb_attr; 319 Dwarf_Attribute fb_attr;
396 size_t nops; 320 size_t nops;
397 321
322 /* If no real subprogram, find a real one */
323 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
324 sp_die = die_get_real_subprogram(&pf->cu_die,
325 pf->addr, &die_mem);
326 if (!sp_die)
327 die("Probe point is not found in subprograms.");
328 }
329
398 /* Output name of probe point */ 330 /* Output name of probe point */
399 name = dwarf_diename(sp_die); 331 name = dwarf_diename(sp_die);
400 if (name) { 332 if (name) {
401 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name, 333 dwarf_entrypc(sp_die, &eaddr);
402 (unsigned int)offs); 334 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name,
335 (unsigned long)(pf->addr - eaddr));
403 /* Copy the function name if possible */ 336 /* Copy the function name if possible */
404 if (!pp->function) { 337 if (!pp->function) {
405 pp->function = strdup(name); 338 pp->function = strdup(name);
406 pp->offset = offs; 339 pp->offset = (size_t)(pf->addr - eaddr);
407 } 340 }
408 } else { 341 } else {
409 /* This function has no name. */ 342 /* This function has no name. */
@@ -450,10 +383,9 @@ static void find_probe_point_by_line(struct probe_finder *pf)
450 Dwarf_Lines *lines; 383 Dwarf_Lines *lines;
451 Dwarf_Line *line; 384 Dwarf_Line *line;
452 size_t nlines, i; 385 size_t nlines, i;
453 Dwarf_Addr addr, epc; 386 Dwarf_Addr addr;
454 int lineno; 387 int lineno;
455 int ret; 388 int ret;
456 Dwarf_Die *sp_die, die_mem;
457 389
458 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines); 390 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
459 DIE_IF(ret != 0); 391 DIE_IF(ret != 0);
@@ -474,77 +406,57 @@ static void find_probe_point_by_line(struct probe_finder *pf)
474 (int)i, lineno, (uintmax_t)addr); 406 (int)i, lineno, (uintmax_t)addr);
475 pf->addr = addr; 407 pf->addr = addr;
476 408
477 sp_die = die_get_real_subprogram(&pf->cu_die, addr, &die_mem); 409 show_probe_point(NULL, pf);
478 if (!sp_die)
479 die("Probe point is not found in subprograms.");
480 dwarf_entrypc(sp_die, &epc);
481 show_probe_point(sp_die, (size_t)(addr - epc), pf);
482 /* Continuing, because target line might be inlined. */ 410 /* Continuing, because target line might be inlined. */
483 } 411 }
484} 412}
485 413
414static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
415{
416 struct probe_finder *pf = (struct probe_finder *)data;
417 struct probe_point *pp = pf->pp;
418
419 /* Get probe address */
420 pf->addr = die_get_entrypc(in_die);
421 pf->addr += pp->offset;
422 pr_debug("found inline addr: 0x%jx\n", (uintmax_t)pf->addr);
423
424 show_probe_point(in_die, pf);
425 return DWARF_CB_OK;
426}
486 427
487/* Search function from function name */ 428/* Search function from function name */
488static int probe_point_search_cb(struct die_link *dlink, void *data) 429static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
489{ 430{
490 struct probe_finder *pf = (struct probe_finder *)data; 431 struct probe_finder *pf = (struct probe_finder *)data;
491 struct probe_point *pp = pf->pp; 432 struct probe_point *pp = pf->pp;
492 struct die_link *lk;
493 size_t offs;
494 int tag;
495 int ret;
496 433
497 tag = dwarf_tag(&dlink->die); 434 /* Check tag and diename */
498 if (tag == DW_TAG_subprogram) { 435 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
499 if (die_compare_name(&dlink->die, pp->function) == 0) { 436 die_compare_name(sp_die, pp->function) != 0)
500 if (pp->line) { /* Function relative line */ 437 return 0;
501 pf->fname = dwarf_decl_file(&dlink->die); 438
502 dwarf_decl_line(&dlink->die, &pf->lno); 439 if (pp->line) { /* Function relative line */
503 pf->lno += pp->line; 440 pf->fname = dwarf_decl_file(sp_die);
504 find_probe_point_by_line(pf); 441 dwarf_decl_line(sp_die, &pf->lno);
505 return 1; 442 pf->lno += pp->line;
506 } 443 find_probe_point_by_line(pf);
507 if (dwarf_func_inline(&dlink->die)) { 444 } else if (!dwarf_func_inline(sp_die)) {
508 /* Inlined function, save it. */ 445 /* Real function */
509 pf->origin = dlink->die.addr; 446 pf->addr = die_get_entrypc(sp_die);
510 return 0; /* Continue to search */ 447 pf->addr += pp->offset;
511 } 448 /* TODO: Check the address in this function */
512 /* Get probe address */ 449 show_probe_point(sp_die, pf);
513 pf->addr = die_get_entrypc(&dlink->die); 450 } else
514 pf->addr += pp->offset; 451 /* Inlined function: search instances */
515 /* TODO: Check the address in this function */ 452 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf);
516 show_probe_point(&dlink->die, pp->offset, pf); 453
517 return 1; /* Exit; no same symbol in this CU. */ 454 return 1; /* Exit; no same symbol in this CU. */
518 }
519 } else if (tag == DW_TAG_inlined_subroutine && pf->origin) {
520 if (die_compare_abstract_origin(&dlink->die, pf->origin)) {
521 /* Get probe address */
522 pf->addr = die_get_entrypc(&dlink->die);
523 pf->addr += pp->offset;
524 pr_debug("found inline addr: 0x%jx\n",
525 (uintmax_t)pf->addr);
526 /* Inlined function. Get a real subprogram */
527 for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
528 tag = dwarf_tag(&lk->die);
529 if (tag == DW_TAG_subprogram &&
530 !dwarf_func_inline(&lk->die))
531 goto found;
532 }
533 die("Failed to find real subprogram.");
534found:
535 /* Get offset from subprogram */
536 ret = die_within_subprogram(&lk->die, pf->addr, &offs);
537 DIE_IF(!ret);
538 show_probe_point(&lk->die, offs, pf);
539 /* Continue to search */
540 }
541 }
542 return 0;
543} 455}
544 456
545static void find_probe_point_by_func(struct probe_finder *pf) 457static void find_probe_point_by_func(struct probe_finder *pf)
546{ 458{
547 search_die_from_children(&pf->cu_die, probe_point_search_cb, pf); 459 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
548} 460}
549 461
550/* Find a probe point */ 462/* Find a probe point */
@@ -669,27 +581,25 @@ static void find_line_range_by_line(struct line_finder *lf)
669} 581}
670 582
671/* Search function from function name */ 583/* Search function from function name */
672static int line_range_search_cb(struct die_link *dlink, void *data) 584static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
673{ 585{
674 struct line_finder *lf = (struct line_finder *)data; 586 struct line_finder *lf = (struct line_finder *)data;
675 struct line_range *lr = lf->lr; 587 struct line_range *lr = lf->lr;
676 int tag;
677 int ret; 588 int ret;
678 589
679 tag = dwarf_tag(&dlink->die); 590 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
680 if (tag == DW_TAG_subprogram && 591 die_compare_name(sp_die, lr->function) == 0) {
681 die_compare_name(&dlink->die, lr->function) == 0) {
682 /* Get the address range of this function */ 592 /* Get the address range of this function */
683 ret = dwarf_highpc(&dlink->die, &lf->addr_e); 593 ret = dwarf_highpc(sp_die, &lf->addr_e);
684 if (ret == 0) 594 if (ret == 0)
685 ret = dwarf_lowpc(&dlink->die, &lf->addr_s); 595 ret = dwarf_lowpc(sp_die, &lf->addr_s);
686 if (ret != 0) { 596 if (ret != 0) {
687 lf->addr_s = 0; 597 lf->addr_s = 0;
688 lf->addr_e = 0; 598 lf->addr_e = 0;
689 } 599 }
690 600
691 lf->fname = dwarf_decl_file(&dlink->die); 601 lf->fname = dwarf_decl_file(sp_die);
692 dwarf_decl_line(&dlink->die, &lr->offset); 602 dwarf_decl_line(sp_die, &lr->offset);
693 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); 603 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
694 lf->lno_s = lr->offset + lr->start; 604 lf->lno_s = lr->offset + lr->start;
695 if (!lr->end) 605 if (!lr->end)
@@ -706,7 +616,7 @@ static int line_range_search_cb(struct die_link *dlink, void *data)
706 616
707static void find_line_range_by_func(struct line_finder *lf) 617static void find_line_range_by_func(struct line_finder *lf)
708{ 618{
709 search_die_from_children(&lf->cu_die, line_range_search_cb, lf); 619 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0);
710} 620}
711 621
712int find_line_range(int fd, struct line_range *lr) 622int find_line_range(int fd, struct line_range *lr)
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 9dd4a884d0e6..74525aeb30fe 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -66,7 +66,6 @@ struct probe_finder {
66 Dwarf_Addr addr; /* Address */ 66 Dwarf_Addr addr; /* Address */
67 const char *fname; /* File name */ 67 const char *fname; /* File name */
68 int lno; /* Line number */ 68 int lno; /* Line number */
69 void *origin; /* Inline origin addr */
70 Dwarf_Die cu_die; /* Current CU */ 69 Dwarf_Die cu_die; /* Current CU */
71 70
72 /* For variable searching */ 71 /* For variable searching */