aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/probe-finder.c
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2010-02-25 08:36:12 -0500
committerIngo Molnar <mingo@elte.hu>2010-02-25 11:49:30 -0500
commit2a9c8c36092de41c13fdd81fe59556915b080c3e (patch)
tree07effa153812d5137b8b930d6b77e9fe9fedf529 /tools/perf/util/probe-finder.c
parent5c8d1cbbbed39dcab2ecf429d6e56ea548c0fda4 (diff)
perf probe: Add lazy line matching support
Add lazy line matching support for specifying new probes. This also changes the syntax of perf probe a bit. Now perf probe accepts one of below probe event definitions. 1) Define event based on function name [EVENT=]FUNC[@SRC][:RLN|+OFF|%return|;PTN] [ARG ...] 2) Define event based on source file with line number [EVENT=]SRC:ALN [ARG ...] 3) Define event based on source file with lazy pattern [EVENT=]SRC;PTN [ARG ...] - New lazy matching pattern(PTN) follows ';' (semicolon). And it must be put the end of the definition. - So, @SRC is no longer the part which must be put at the end of the definition. Note that ';' (semicolon) can be interpreted as the end of a command by the shell. This means that you need to quote it. (anyway you will need to quote the lazy pattern itself too, because it may contains other sensitive characters, like '[',']' etc.). Lazy matching ------------- The lazy line matching is similar to glob matching except ignoring spaces in both of pattern and target. e.g. 'a=*' can matches 'a=b', 'a = b', 'a == b' and so on. This provides some sort of flexibility and robustness to probe point definitions against minor code changes. (for example, actual 10th line of schedule() can be changed easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist.) 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: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> LKML-Reference: <20100225133611.6725.45078.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.c249
1 files changed, 189 insertions, 60 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index a41035634dd8..e77dc886760e 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -32,6 +32,7 @@
32#include <stdarg.h> 32#include <stdarg.h>
33#include <ctype.h> 33#include <ctype.h>
34 34
35#include "string.h"
35#include "event.h" 36#include "event.h"
36#include "debug.h" 37#include "debug.h"
37#include "util.h" 38#include "util.h"
@@ -104,8 +105,67 @@ static int strtailcmp(const char *s1, const char *s2)
104 return 0; 105 return 0;
105} 106}
106 107
107/* Find the fileno of the target file. */ 108/* Line number list operations */
108static int cu_find_fileno(Dwarf_Die *cu_die, const char *fname) 109
110/* Add a line to line number list */
111static void line_list__add_line(struct list_head *head, unsigned int line)
112{
113 struct line_node *ln;
114 struct list_head *p;
115
116 /* Reverse search, because new line will be the last one */
117 list_for_each_entry_reverse(ln, head, list) {
118 if (ln->line < line) {
119 p = &ln->list;
120 goto found;
121 } else if (ln->line == line) /* Already exist */
122 return ;
123 }
124 /* List is empty, or the smallest entry */
125 p = head;
126found:
127 pr_debug("line list: add a line %u\n", line);
128 ln = zalloc(sizeof(struct line_node));
129 DIE_IF(ln == NULL);
130 ln->line = line;
131 INIT_LIST_HEAD(&ln->list);
132 list_add(&ln->list, p);
133}
134
135/* Check if the line in line number list */
136static int line_list__has_line(struct list_head *head, unsigned int line)
137{
138 struct line_node *ln;
139
140 /* Reverse search, because new line will be the last one */
141 list_for_each_entry(ln, head, list)
142 if (ln->line == line)
143 return 1;
144
145 return 0;
146}
147
148/* Init line number list */
149static void line_list__init(struct list_head *head)
150{
151 INIT_LIST_HEAD(head);
152}
153
154/* Free line number list */
155static void line_list__free(struct list_head *head)
156{
157 struct line_node *ln;
158 while (!list_empty(head)) {
159 ln = list_first_entry(head, struct line_node, list);
160 list_del(&ln->list);
161 free(ln);
162 }
163}
164
165/* Dwarf wrappers */
166
167/* Find the realpath of the target file. */
168static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
109{ 169{
110 Dwarf_Files *files; 170 Dwarf_Files *files;
111 size_t nfiles, i; 171 size_t nfiles, i;
@@ -113,21 +173,18 @@ static int cu_find_fileno(Dwarf_Die *cu_die, const char *fname)
113 int ret; 173 int ret;
114 174
115 if (!fname) 175 if (!fname)
116 return -EINVAL; 176 return NULL;
117 177
118 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles); 178 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
119 if (ret == 0) { 179 if (ret != 0)
120 for (i = 0; i < nfiles; i++) { 180 return NULL;
121 src = dwarf_filesrc(files, i, NULL, NULL); 181
122 if (strtailcmp(src, fname) == 0) { 182 for (i = 0; i < nfiles; i++) {
123 ret = (int)i; /*???: +1 or not?*/ 183 src = dwarf_filesrc(files, i, NULL, NULL);
124 break; 184 if (strtailcmp(src, fname) == 0)
125 } 185 break;
126 }
127 if (ret)
128 pr_debug("found fno: %d\n", ret);
129 } 186 }
130 return ret; 187 return src;
131} 188}
132 189
133struct __addr_die_search_param { 190struct __addr_die_search_param {
@@ -436,17 +493,109 @@ static void find_probe_point_by_line(struct probe_finder *pf)
436 } 493 }
437} 494}
438 495
496/* Find lines which match lazy pattern */
497static int find_lazy_match_lines(struct list_head *head,
498 const char *fname, const char *pat)
499{
500 char *fbuf, *p1, *p2;
501 int fd, line, nlines = 0;
502 struct stat st;
503
504 fd = open(fname, O_RDONLY);
505 if (fd < 0)
506 die("failed to open %s", fname);
507 DIE_IF(fstat(fd, &st) < 0);
508 fbuf = malloc(st.st_size + 2);
509 DIE_IF(fbuf == NULL);
510 DIE_IF(read(fd, fbuf, st.st_size) < 0);
511 close(fd);
512 fbuf[st.st_size] = '\n'; /* Dummy line */
513 fbuf[st.st_size + 1] = '\0';
514 p1 = fbuf;
515 line = 1;
516 while ((p2 = strchr(p1, '\n')) != NULL) {
517 *p2 = '\0';
518 if (strlazymatch(p1, pat)) {
519 line_list__add_line(head, line);
520 nlines++;
521 }
522 line++;
523 p1 = p2 + 1;
524 }
525 free(fbuf);
526 return nlines;
527}
528
529/* Find probe points from lazy pattern */
530static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
531{
532 Dwarf_Lines *lines;
533 Dwarf_Line *line;
534 size_t nlines, i;
535 Dwarf_Addr addr;
536 Dwarf_Die die_mem;
537 int lineno;
538 int ret;
539
540 if (list_empty(&pf->lcache)) {
541 /* Matching lazy line pattern */
542 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
543 pf->pp->lazy_line);
544 if (ret <= 0)
545 die("No matched lines found in %s.", pf->fname);
546 }
547
548 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
549 DIE_IF(ret != 0);
550 for (i = 0; i < nlines; i++) {
551 line = dwarf_onesrcline(lines, i);
552
553 dwarf_lineno(line, &lineno);
554 if (!line_list__has_line(&pf->lcache, lineno))
555 continue;
556
557 /* TODO: Get fileno from line, but how? */
558 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
559 continue;
560
561 ret = dwarf_lineaddr(line, &addr);
562 DIE_IF(ret != 0);
563 if (sp_die) {
564 /* Address filtering 1: does sp_die include addr? */
565 if (!dwarf_haspc(sp_die, addr))
566 continue;
567 /* Address filtering 2: No child include addr? */
568 if (die_get_inlinefunc(sp_die, addr, &die_mem))
569 continue;
570 }
571
572 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
573 (int)i, lineno, (unsigned long long)addr);
574 pf->addr = addr;
575
576 show_probe_point(sp_die, pf);
577 /* Continuing, because target line might be inlined. */
578 }
579 /* TODO: deallocate lines, but how? */
580}
581
439static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 582static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
440{ 583{
441 struct probe_finder *pf = (struct probe_finder *)data; 584 struct probe_finder *pf = (struct probe_finder *)data;
442 struct probe_point *pp = pf->pp; 585 struct probe_point *pp = pf->pp;
443 586
444 /* Get probe address */ 587 if (pp->lazy_line)
445 pf->addr = die_get_entrypc(in_die); 588 find_probe_point_lazy(in_die, pf);
446 pf->addr += pp->offset; 589 else {
447 pr_debug("found inline addr: 0x%jx\n", (uintmax_t)pf->addr); 590 /* Get probe address */
591 pf->addr = die_get_entrypc(in_die);
592 pf->addr += pp->offset;
593 pr_debug("found inline addr: 0x%jx\n",
594 (uintmax_t)pf->addr);
595
596 show_probe_point(in_die, pf);
597 }
448 598
449 show_probe_point(in_die, pf);
450 return DWARF_CB_OK; 599 return DWARF_CB_OK;
451} 600}
452 601
@@ -461,17 +610,21 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
461 die_compare_name(sp_die, pp->function) != 0) 610 die_compare_name(sp_die, pp->function) != 0)
462 return 0; 611 return 0;
463 612
613 pf->fname = dwarf_decl_file(sp_die);
464 if (pp->line) { /* Function relative line */ 614 if (pp->line) { /* Function relative line */
465 pf->fname = dwarf_decl_file(sp_die);
466 dwarf_decl_line(sp_die, &pf->lno); 615 dwarf_decl_line(sp_die, &pf->lno);
467 pf->lno += pp->line; 616 pf->lno += pp->line;
468 find_probe_point_by_line(pf); 617 find_probe_point_by_line(pf);
469 } else if (!dwarf_func_inline(sp_die)) { 618 } else if (!dwarf_func_inline(sp_die)) {
470 /* Real function */ 619 /* Real function */
471 pf->addr = die_get_entrypc(sp_die); 620 if (pp->lazy_line)
472 pf->addr += pp->offset; 621 find_probe_point_lazy(sp_die, pf);
473 /* TODO: Check the address in this function */ 622 else {
474 show_probe_point(sp_die, pf); 623 pf->addr = die_get_entrypc(sp_die);
624 pf->addr += pp->offset;
625 /* TODO: Check the address in this function */
626 show_probe_point(sp_die, pf);
627 }
475 } else 628 } else
476 /* Inlined function: search instances */ 629 /* Inlined function: search instances */
477 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf); 630 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf);
@@ -493,7 +646,6 @@ int find_probe_point(int fd, struct probe_point *pp)
493 size_t cuhl; 646 size_t cuhl;
494 Dwarf_Die *diep; 647 Dwarf_Die *diep;
495 Dwarf *dbg; 648 Dwarf *dbg;
496 int fno = 0;
497 649
498 dbg = dwarf_begin(fd, DWARF_C_READ); 650 dbg = dwarf_begin(fd, DWARF_C_READ);
499 if (!dbg) 651 if (!dbg)
@@ -501,6 +653,7 @@ int find_probe_point(int fd, struct probe_point *pp)
501 653
502 pp->found = 0; 654 pp->found = 0;
503 off = 0; 655 off = 0;
656 line_list__init(&pf.lcache);
504 /* Loop on CUs (Compilation Unit) */ 657 /* Loop on CUs (Compilation Unit) */
505 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 658 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
506 /* Get the DIE(Debugging Information Entry) of this CU */ 659 /* Get the DIE(Debugging Information Entry) of this CU */
@@ -510,17 +663,19 @@ int find_probe_point(int fd, struct probe_point *pp)
510 663
511 /* Check if target file is included. */ 664 /* Check if target file is included. */
512 if (pp->file) 665 if (pp->file)
513 fno = cu_find_fileno(&pf.cu_die, pp->file); 666 pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
514 else 667 else
515 fno = 0; 668 pf.fname = NULL;
516 669
517 if (!pp->file || fno) { 670 if (!pp->file || pf.fname) {
518 /* Save CU base address (for frame_base) */ 671 /* Save CU base address (for frame_base) */
519 ret = dwarf_lowpc(&pf.cu_die, &pf.cu_base); 672 ret = dwarf_lowpc(&pf.cu_die, &pf.cu_base);
520 if (ret != 0) 673 if (ret != 0)
521 pf.cu_base = 0; 674 pf.cu_base = 0;
522 if (pp->function) 675 if (pp->function)
523 find_probe_point_by_func(&pf); 676 find_probe_point_by_func(&pf);
677 else if (pp->lazy_line)
678 find_probe_point_lazy(NULL, &pf);
524 else { 679 else {
525 pf.lno = pp->line; 680 pf.lno = pp->line;
526 find_probe_point_by_line(&pf); 681 find_probe_point_by_line(&pf);
@@ -528,36 +683,12 @@ int find_probe_point(int fd, struct probe_point *pp)
528 } 683 }
529 off = noff; 684 off = noff;
530 } 685 }
686 line_list__free(&pf.lcache);
531 dwarf_end(dbg); 687 dwarf_end(dbg);
532 688
533 return pp->found; 689 return pp->found;
534} 690}
535 691
536
537static void line_range_add_line(struct line_range *lr, unsigned int line)
538{
539 struct line_node *ln;
540 struct list_head *p;
541
542 /* Reverse search, because new line will be the last one */
543 list_for_each_entry_reverse(ln, &lr->line_list, list) {
544 if (ln->line < line) {
545 p = &ln->list;
546 goto found;
547 } else if (ln->line == line) /* Already exist */
548 return ;
549 }
550 /* List is empty, or the smallest entry */
551 p = &lr->line_list;
552found:
553 pr_debug("Debug: add a line %u\n", line);
554 ln = zalloc(sizeof(struct line_node));
555 DIE_IF(ln == NULL);
556 ln->line = line;
557 INIT_LIST_HEAD(&ln->list);
558 list_add(&ln->list, p);
559}
560
561/* Find line range from its line number */ 692/* Find line range from its line number */
562static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 693static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
563{ 694{
@@ -570,7 +701,7 @@ static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
570 const char *src; 701 const char *src;
571 Dwarf_Die die_mem; 702 Dwarf_Die die_mem;
572 703
573 INIT_LIST_HEAD(&lf->lr->line_list); 704 line_list__init(&lf->lr->line_list);
574 ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines); 705 ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines);
575 DIE_IF(ret != 0); 706 DIE_IF(ret != 0);
576 707
@@ -601,7 +732,7 @@ static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
601 /* Copy real path */ 732 /* Copy real path */
602 if (!lf->lr->path) 733 if (!lf->lr->path)
603 lf->lr->path = strdup(src); 734 lf->lr->path = strdup(src);
604 line_range_add_line(lf->lr, (unsigned int)lineno); 735 line_list__add_line(&lf->lr->line_list, (unsigned int)lineno);
605 } 736 }
606 /* Update status */ 737 /* Update status */
607 if (!list_empty(&lf->lr->line_list)) 738 if (!list_empty(&lf->lr->line_list))
@@ -659,7 +790,6 @@ int find_line_range(int fd, struct line_range *lr)
659 size_t cuhl; 790 size_t cuhl;
660 Dwarf_Die *diep; 791 Dwarf_Die *diep;
661 Dwarf *dbg; 792 Dwarf *dbg;
662 int fno;
663 793
664 dbg = dwarf_begin(fd, DWARF_C_READ); 794 dbg = dwarf_begin(fd, DWARF_C_READ);
665 if (!dbg) 795 if (!dbg)
@@ -678,15 +808,14 @@ int find_line_range(int fd, struct line_range *lr)
678 808
679 /* Check if target file is included. */ 809 /* Check if target file is included. */
680 if (lr->file) 810 if (lr->file)
681 fno = cu_find_fileno(&lf.cu_die, lr->file); 811 lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
682 else 812 else
683 fno = 0; 813 lf.fname = 0;
684 814
685 if (!lr->file || fno) { 815 if (!lr->file || lf.fname) {
686 if (lr->function) 816 if (lr->function)
687 find_line_range_by_func(&lf); 817 find_line_range_by_func(&lf);
688 else { 818 else {
689 lf.fname = lr->file;
690 lf.lno_s = lr->start; 819 lf.lno_s = lr->start;
691 if (!lr->end) 820 if (!lr->end)
692 lf.lno_e = INT_MAX; 821 lf.lno_e = INT_MAX;