aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-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
5 files changed, 264 insertions, 91 deletions
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)