diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/probe-event.c | 48 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 249 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.h | 2 | ||||
-rw-r--r-- | tools/perf/util/string.c | 55 | ||||
-rw-r--r-- | tools/perf/util/string.h | 1 |
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 */ |
108 | static int cu_find_fileno(Dwarf_Die *cu_die, const char *fname) | 109 | |
110 | /* Add a line to line number list */ | ||
111 | static 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; | ||
126 | found: | ||
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 */ | ||
136 | static 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 */ | ||
149 | static void line_list__init(struct list_head *head) | ||
150 | { | ||
151 | INIT_LIST_HEAD(head); | ||
152 | } | ||
153 | |||
154 | /* Free line number list */ | ||
155 | static 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. */ | ||
168 | static 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 | ||
133 | struct __addr_die_search_param { | 190 | struct __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 */ | ||
497 | static 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 */ | ||
530 | static 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 | |||
439 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | 582 | static 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 | |||
537 | static 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; | ||
552 | found: | ||
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 */ |
562 | static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | 693 | static 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 | ||
79 | struct line_finder { | 81 | struct 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 | 269 | static 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 | */ | ||
280 | bool 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 | */ | ||
323 | bool 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 | */ | ||
336 | bool 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); | |||
10 | char **argv_split(const char *str, int *argcp); | 10 | char **argv_split(const char *str, int *argcp); |
11 | void argv_free(char **argv); | 11 | void argv_free(char **argv); |
12 | bool strglobmatch(const char *str, const char *pat); | 12 | bool strglobmatch(const char *str, const char *pat); |
13 | bool 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) |