aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
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
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')
-rw-r--r--tools/perf/Documentation/perf-probe.txt30
-rw-r--r--tools/perf/builtin-probe.c12
-rw-r--r--tools/perf/util/probe-event.c48
-rw-r--r--tools/perf/util/probe-finder.c249
-rw-r--r--tools/perf/util/probe-finder.h2
-rw-r--r--tools/perf/util/string.c55
-rw-r--r--tools/perf/util/string.h1
7 files changed, 298 insertions, 99 deletions
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 5fe63c0ca80c..34202b1be0bb 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -61,11 +61,19 @@ PROBE SYNTAX
61------------ 61------------
62Probe points are defined by following syntax. 62Probe points are defined by following syntax.
63 63
64 "[EVENT=]FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]" 64 1) Define event based on function name
65 [EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...]
66
67 2) Define event based on source file with line number
68 [EVENT=]SRC:ALN [ARG ...]
69
70 3) Define event based on source file with lazy pattern
71 [EVENT=]SRC;PTN [ARG ...]
72
65 73
66'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'. 74'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'.
67'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, 'RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. In addition, 'SRC' specifies a source file which has that function. 75'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function.
68It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number. 76It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern.
69'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc). 77'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc).
70 78
71LINE SYNTAX 79LINE SYNTAX
@@ -81,6 +89,16 @@ and 'ALN2' is end line number in the file. It is also possible to specify how
81many lines to show by using 'NUM'. 89many lines to show by using 'NUM'.
82So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function. 90So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function.
83 91
92LAZY MATCHING
93-------------
94 The lazy line matching is similar to glob matching but ignoring spaces in both of pattern and target. So this accepts wildcards('*', '?') and character classes(e.g. [a-z], [!A-Z]).
95
96e.g.
97 'a=*' can matches 'a=b', 'a = b', 'a == b' and so on.
98
99This provides some sort of flexibility and robustness to probe point definitions against minor code changes. For example, actual 10th line of schedule() can be moved easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist in the function.)
100
101
84EXAMPLES 102EXAMPLES
85-------- 103--------
86Display which lines in schedule() can be probed: 104Display which lines in schedule() can be probed:
@@ -95,6 +113,12 @@ Add a probe on schedule() function 12th line with recording cpu local variable:
95 113
96 this will add one or more probes which has the name start with "schedule". 114 this will add one or more probes which has the name start with "schedule".
97 115
116 Add probes on lines in schedule() function which calls update_rq_clock().
117
118 ./perf probe 'schedule;update_rq_clock*'
119 or
120 ./perf probe --add='schedule;update_rq_clock*'
121
98Delete all probes on schedule(). 122Delete all probes on schedule().
99 123
100 ./perf probe --del='schedule*' 124 ./perf probe --del='schedule*'
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index d8d3f0525895..e3dfd0dcce24 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -175,22 +175,24 @@ static const struct option options[] = {
175 opt_del_probe_event), 175 opt_del_probe_event),
176 OPT_CALLBACK('a', "add", NULL, 176 OPT_CALLBACK('a', "add", NULL,
177#ifdef NO_DWARF_SUPPORT 177#ifdef NO_DWARF_SUPPORT
178 "[EVENT=]FUNC[+OFFS|%return] [ARG ...]", 178 "[EVENT=]FUNC[+OFF|%return] [ARG ...]",
179#else 179#else
180 "[EVENT=]FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]", 180 "[EVENT=]FUNC[+OFF|%return|:RL|;PT][@SRC]|SRC:AL|SRC;PT"
181 " [ARG ...]",
181#endif 182#endif
182 "probe point definition, where\n" 183 "probe point definition, where\n"
183 "\t\tGROUP:\tGroup name (optional)\n" 184 "\t\tGROUP:\tGroup name (optional)\n"
184 "\t\tEVENT:\tEvent name\n" 185 "\t\tEVENT:\tEvent name\n"
185 "\t\tFUNC:\tFunction name\n" 186 "\t\tFUNC:\tFunction name\n"
186 "\t\tOFFS:\tOffset from function entry (in byte)\n" 187 "\t\tOFF:\tOffset from function entry (in byte)\n"
187 "\t\t%return:\tPut the probe at function return\n" 188 "\t\t%return:\tPut the probe at function return\n"
188#ifdef NO_DWARF_SUPPORT 189#ifdef NO_DWARF_SUPPORT
189 "\t\tARG:\tProbe argument (only \n" 190 "\t\tARG:\tProbe argument (only \n"
190#else 191#else
191 "\t\tSRC:\tSource code path\n" 192 "\t\tSRC:\tSource code path\n"
192 "\t\tRLN:\tRelative line number from function entry.\n" 193 "\t\tRL:\tRelative line number from function entry.\n"
193 "\t\tALN:\tAbsolute line number in file.\n" 194 "\t\tAL:\tAbsolute line number in file.\n"
195 "\t\tPT:\tLazy expression of line code.\n"
194 "\t\tARG:\tProbe argument (local variable name or\n" 196 "\t\tARG:\tProbe argument (local variable name or\n"
195#endif 197#endif
196 "\t\t\tkprobe-tracer argument format.)\n", 198 "\t\t\tkprobe-tracer argument format.)\n",
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 91f55f24fa9d..fa156f008e0b 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -119,14 +119,14 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
119 char c, nc = 0; 119 char c, nc = 0;
120 /* 120 /*
121 * <Syntax> 121 * <Syntax>
122 * perf probe [EVENT=]SRC:LN 122 * perf probe [EVENT=]SRC[:LN|;PTN]
123 * perf probe [EVENT=]FUNC[+OFFS|%return][@SRC] 123 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
124 * 124 *
125 * TODO:Group name support 125 * TODO:Group name support
126 */ 126 */
127 127
128 ptr = strchr(arg, '='); 128 ptr = strpbrk(arg, ";=@+%");
129 if (ptr) { /* Event name */ 129 if (ptr && *ptr == '=') { /* Event name */
130 *ptr = '\0'; 130 *ptr = '\0';
131 tmp = ptr + 1; 131 tmp = ptr + 1;
132 ptr = strchr(arg, ':'); 132 ptr = strchr(arg, ':');
@@ -139,7 +139,7 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
139 arg = tmp; 139 arg = tmp;
140 } 140 }
141 141
142 ptr = strpbrk(arg, ":+@%"); 142 ptr = strpbrk(arg, ";:+@%");
143 if (ptr) { 143 if (ptr) {
144 nc = *ptr; 144 nc = *ptr;
145 *ptr++ = '\0'; 145 *ptr++ = '\0';
@@ -156,7 +156,11 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
156 while (ptr) { 156 while (ptr) {
157 arg = ptr; 157 arg = ptr;
158 c = nc; 158 c = nc;
159 ptr = strpbrk(arg, ":+@%"); 159 if (c == ';') { /* Lazy pattern must be the last part */
160 pp->lazy_line = strdup(arg);
161 break;
162 }
163 ptr = strpbrk(arg, ";:+@%");
160 if (ptr) { 164 if (ptr) {
161 nc = *ptr; 165 nc = *ptr;
162 *ptr++ = '\0'; 166 *ptr++ = '\0';
@@ -165,13 +169,13 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
165 case ':': /* Line number */ 169 case ':': /* Line number */
166 pp->line = strtoul(arg, &tmp, 0); 170 pp->line = strtoul(arg, &tmp, 0);
167 if (*tmp != '\0') 171 if (*tmp != '\0')
168 semantic_error("There is non-digit charactor" 172 semantic_error("There is non-digit char"
169 " in line number."); 173 " in line number.");
170 break; 174 break;
171 case '+': /* Byte offset from a symbol */ 175 case '+': /* Byte offset from a symbol */
172 pp->offset = strtoul(arg, &tmp, 0); 176 pp->offset = strtoul(arg, &tmp, 0);
173 if (*tmp != '\0') 177 if (*tmp != '\0')
174 semantic_error("There is non-digit charactor" 178 semantic_error("There is non-digit character"
175 " in offset."); 179 " in offset.");
176 break; 180 break;
177 case '@': /* File name */ 181 case '@': /* File name */
@@ -179,9 +183,6 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
179 semantic_error("SRC@SRC is not allowed."); 183 semantic_error("SRC@SRC is not allowed.");
180 pp->file = strdup(arg); 184 pp->file = strdup(arg);
181 DIE_IF(pp->file == NULL); 185 DIE_IF(pp->file == NULL);
182 if (ptr)
183 semantic_error("@SRC must be the last "
184 "option.");
185 break; 186 break;
186 case '%': /* Probe places */ 187 case '%': /* Probe places */
187 if (strcmp(arg, "return") == 0) { 188 if (strcmp(arg, "return") == 0) {
@@ -196,11 +197,18 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
196 } 197 }
197 198
198 /* Exclusion check */ 199 /* Exclusion check */
200 if (pp->lazy_line && pp->line)
201 semantic_error("Lazy pattern can't be used with line number.");
202
203 if (pp->lazy_line && pp->offset)
204 semantic_error("Lazy pattern can't be used with offset.");
205
199 if (pp->line && pp->offset) 206 if (pp->line && pp->offset)
200 semantic_error("Offset can't be used with line number."); 207 semantic_error("Offset can't be used with line number.");
201 208
202 if (!pp->line && pp->file && !pp->function) 209 if (!pp->line && !pp->lazy_line && pp->file && !pp->function)
203 semantic_error("File always requires line number."); 210 semantic_error("File always requires line number or "
211 "lazy pattern.");
204 212
205 if (pp->offset && !pp->function) 213 if (pp->offset && !pp->function)
206 semantic_error("Offset requires an entry function."); 214 semantic_error("Offset requires an entry function.");
@@ -208,11 +216,13 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
208 if (pp->retprobe && !pp->function) 216 if (pp->retprobe && !pp->function)
209 semantic_error("Return probe requires an entry function."); 217 semantic_error("Return probe requires an entry function.");
210 218
211 if ((pp->offset || pp->line) && pp->retprobe) 219 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe)
212 semantic_error("Offset/Line can't be used with return probe."); 220 semantic_error("Offset/Line/Lazy pattern can't be used with "
221 "return probe.");
213 222
214 pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n", 223 pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n",
215 pp->function, pp->file, pp->line, pp->offset, pp->retprobe); 224 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
225 pp->lazy_line);
216} 226}
217 227
218/* Parse perf-probe event definition */ 228/* Parse perf-probe event definition */
@@ -456,6 +466,8 @@ static void clear_probe_point(struct probe_point *pp)
456 free(pp->function); 466 free(pp->function);
457 if (pp->file) 467 if (pp->file)
458 free(pp->file); 468 free(pp->file);
469 if (pp->lazy_line)
470 free(pp->lazy_line);
459 for (i = 0; i < pp->nr_args; i++) 471 for (i = 0; i < pp->nr_args; i++)
460 free(pp->args[i]); 472 free(pp->args[i]);
461 if (pp->args) 473 if (pp->args)
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;
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 75a660d4bdb2..d1a651793ba6 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -21,6 +21,7 @@ struct probe_point {
21 /* Inputs */ 21 /* Inputs */
22 char *file; /* File name */ 22 char *file; /* File name */
23 int line; /* Line number */ 23 int line; /* Line number */
24 char *lazy_line; /* Lazy line pattern */
24 25
25 char *function; /* Function name */ 26 char *function; /* Function name */
26 int offset; /* Offset bytes */ 27 int offset; /* Offset bytes */
@@ -74,6 +75,7 @@ struct probe_finder {
74 const char *var; /* Current variable name */ 75 const char *var; /* Current variable name */
75 char *buf; /* Current output buffer */ 76 char *buf; /* Current output buffer */
76 int len; /* Length of output buffer */ 77 int len; /* Length of output buffer */
78 struct list_head lcache; /* Line cache for lazy match */
77}; 79};
78 80
79struct line_finder { 81struct line_finder {
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index c397d4f6f748..a175949ed216 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -265,21 +265,21 @@ error:
265 return false; 265 return false;
266} 266}
267 267
268/** 268/* Glob/lazy pattern matching */
269 * strglobmatch - glob expression pattern matching 269static bool __match_glob(const char *str, const char *pat, bool ignore_space)
270 * @str: the target string to match
271 * @pat: the pattern string to match
272 *
273 * This returns true if the @str matches @pat. @pat can includes wildcards
274 * ('*','?') and character classes ([CHARS], complementation and ranges are
275 * also supported). Also, this supports escape character ('\') to use special
276 * characters as normal character.
277 *
278 * Note: if @pat syntax is broken, this always returns false.
279 */
280bool strglobmatch(const char *str, const char *pat)
281{ 270{
282 while (*str && *pat && *pat != '*') { 271 while (*str && *pat && *pat != '*') {
272 if (ignore_space) {
273 /* Ignore spaces for lazy matching */
274 if (isspace(*str)) {
275 str++;
276 continue;
277 }
278 if (isspace(*pat)) {
279 pat++;
280 continue;
281 }
282 }
283 if (*pat == '?') { /* Matches any single character */ 283 if (*pat == '?') { /* Matches any single character */
284 str++; 284 str++;
285 pat++; 285 pat++;
@@ -308,3 +308,32 @@ bool strglobmatch(const char *str, const char *pat)
308 return !*str && !*pat; 308 return !*str && !*pat;
309} 309}
310 310
311/**
312 * strglobmatch - glob expression pattern matching
313 * @str: the target string to match
314 * @pat: the pattern string to match
315 *
316 * This returns true if the @str matches @pat. @pat can includes wildcards
317 * ('*','?') and character classes ([CHARS], complementation and ranges are
318 * also supported). Also, this supports escape character ('\') to use special
319 * characters as normal character.
320 *
321 * Note: if @pat syntax is broken, this always returns false.
322 */
323bool strglobmatch(const char *str, const char *pat)
324{
325 return __match_glob(str, pat, false);
326}
327
328/**
329 * strlazymatch - matching pattern strings lazily with glob pattern
330 * @str: the target string to match
331 * @pat: the pattern string to match
332 *
333 * This is similar to strglobmatch, except this ignores spaces in
334 * the target string.
335 */
336bool strlazymatch(const char *str, const char *pat)
337{
338 return __match_glob(str, pat, true);
339}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index 02ede58c54b4..542e44de3719 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -10,6 +10,7 @@ s64 perf_atoll(const char *str);
10char **argv_split(const char *str, int *argcp); 10char **argv_split(const char *str, int *argcp);
11void argv_free(char **argv); 11void argv_free(char **argv);
12bool strglobmatch(const char *str, const char *pat); 12bool strglobmatch(const char *str, const char *pat);
13bool strlazymatch(const char *str, const char *pat);
13 14
14#define _STR(x) #x 15#define _STR(x) #x
15#define STR(x) _STR(x) 16#define STR(x) _STR(x)