probe-finder.c (161a26b0c231b5d2e60e9c132fa360cd9dac4720) | probe-finder.c (2a9c8c36092de41c13fdd81fe59556915b080c3e) |
---|---|
1/* 2 * probe-finder.c : C expression to kprobe event converter 3 * 4 * Written by Masami Hiramatsu <mhiramat@redhat.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or --- 18 unchanged lines hidden (view full) --- 27#include <stdio.h> 28#include <unistd.h> 29#include <getopt.h> 30#include <stdlib.h> 31#include <string.h> 32#include <stdarg.h> 33#include <ctype.h> 34 | 1/* 2 * probe-finder.c : C expression to kprobe event converter 3 * 4 * Written by Masami Hiramatsu <mhiramat@redhat.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or --- 18 unchanged lines hidden (view full) --- 27#include <stdio.h> 28#include <unistd.h> 29#include <getopt.h> 30#include <stdlib.h> 31#include <string.h> 32#include <stdarg.h> 33#include <ctype.h> 34 |
35#include "string.h" |
|
35#include "event.h" 36#include "debug.h" 37#include "util.h" 38#include "probe-finder.h" 39 40 41/* 42 * Generic dwarf analysis helpers --- 56 unchanged lines hidden (view full) --- 99 int i2 = strlen(s2); 100 while (--i1 >= 0 && --i2 >= 0) { 101 if (s1[i1] != s2[i2]) 102 return s1[i1] - s2[i2]; 103 } 104 return 0; 105} 106 | 36#include "event.h" 37#include "debug.h" 38#include "util.h" 39#include "probe-finder.h" 40 41 42/* 43 * Generic dwarf analysis helpers --- 56 unchanged lines hidden (view full) --- 100 int i2 = strlen(s2); 101 while (--i1 >= 0 && --i2 >= 0) { 102 if (s1[i1] != s2[i2]) 103 return s1[i1] - s2[i2]; 104 } 105 return 0; 106} 107 |
107/* Find the fileno of the target file. */ 108static int cu_find_fileno(Dwarf_Die *cu_die, const char *fname) | 108/* Line number list operations */ 109 110/* Add a line to line number list */ 111static void line_list__add_line(struct list_head *head, unsigned int line) |
109{ | 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) 169{ |
|
110 Dwarf_Files *files; 111 size_t nfiles, i; 112 const char *src; 113 int ret; 114 115 if (!fname) | 170 Dwarf_Files *files; 171 size_t nfiles, i; 172 const char *src; 173 int ret; 174 175 if (!fname) |
116 return -EINVAL; | 176 return NULL; |
117 118 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles); | 177 178 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles); |
119 if (ret == 0) { 120 for (i = 0; i < nfiles; i++) { 121 src = dwarf_filesrc(files, i, NULL, NULL); 122 if (strtailcmp(src, fname) == 0) { 123 ret = (int)i; /*???: +1 or not?*/ 124 break; 125 } 126 } 127 if (ret) 128 pr_debug("found fno: %d\n", ret); | 179 if (ret != 0) 180 return NULL; 181 182 for (i = 0; i < nfiles; i++) { 183 src = dwarf_filesrc(files, i, NULL, NULL); 184 if (strtailcmp(src, fname) == 0) 185 break; |
129 } | 186 } |
130 return ret; | 187 return src; |
131} 132 133struct __addr_die_search_param { 134 Dwarf_Addr addr; 135 Dwarf_Die *die_mem; 136}; 137 138static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) --- 292 unchanged lines hidden (view full) --- 431 (int)i, lineno, (uintmax_t)addr); 432 pf->addr = addr; 433 434 show_probe_point(NULL, pf); 435 /* Continuing, because target line might be inlined. */ 436 } 437} 438 | 188} 189 190struct __addr_die_search_param { 191 Dwarf_Addr addr; 192 Dwarf_Die *die_mem; 193}; 194 195static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) --- 292 unchanged lines hidden (view full) --- 488 (int)i, lineno, (uintmax_t)addr); 489 pf->addr = addr; 490 491 show_probe_point(NULL, pf); 492 /* Continuing, because target line might be inlined. */ 493 } 494} 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) 440{ 441 struct probe_finder *pf = (struct probe_finder *)data; 442 struct probe_point *pp = pf->pp; 443 | 582static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 583{ 584 struct probe_finder *pf = (struct probe_finder *)data; 585 struct probe_point *pp = pf->pp; 586 |
444 /* Get probe address */ 445 pf->addr = die_get_entrypc(in_die); 446 pf->addr += pp->offset; 447 pr_debug("found inline addr: 0x%jx\n", (uintmax_t)pf->addr); | 587 if (pp->lazy_line) 588 find_probe_point_lazy(in_die, pf); 589 else { 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); |
448 | 595 |
449 show_probe_point(in_die, pf); | 596 show_probe_point(in_die, pf); 597 } 598 |
450 return DWARF_CB_OK; 451} 452 453/* Search function from function name */ 454static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 455{ 456 struct probe_finder *pf = (struct probe_finder *)data; 457 struct probe_point *pp = pf->pp; 458 459 /* Check tag and diename */ 460 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 461 die_compare_name(sp_die, pp->function) != 0) 462 return 0; 463 | 599 return DWARF_CB_OK; 600} 601 602/* Search function from function name */ 603static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 604{ 605 struct probe_finder *pf = (struct probe_finder *)data; 606 struct probe_point *pp = pf->pp; 607 608 /* Check tag and diename */ 609 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 610 die_compare_name(sp_die, pp->function) != 0) 611 return 0; 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); 467 pf->lno += pp->line; 468 find_probe_point_by_line(pf); 469 } else if (!dwarf_func_inline(sp_die)) { 470 /* Real function */ | 615 dwarf_decl_line(sp_die, &pf->lno); 616 pf->lno += pp->line; 617 find_probe_point_by_line(pf); 618 } else if (!dwarf_func_inline(sp_die)) { 619 /* Real function */ |
471 pf->addr = die_get_entrypc(sp_die); 472 pf->addr += pp->offset; 473 /* TODO: Check the address in this function */ 474 show_probe_point(sp_die, pf); | 620 if (pp->lazy_line) 621 find_probe_point_lazy(sp_die, pf); 622 else { 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 476 /* Inlined function: search instances */ 477 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf); 478 479 return 1; /* Exit; no same symbol in this CU. */ 480} 481 482static void find_probe_point_by_func(struct probe_finder *pf) --- 5 unchanged lines hidden (view full) --- 488int find_probe_point(int fd, struct probe_point *pp) 489{ 490 struct probe_finder pf = {.pp = pp}; 491 int ret; 492 Dwarf_Off off, noff; 493 size_t cuhl; 494 Dwarf_Die *diep; 495 Dwarf *dbg; | 628 } else 629 /* Inlined function: search instances */ 630 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf); 631 632 return 1; /* Exit; no same symbol in this CU. */ 633} 634 635static void find_probe_point_by_func(struct probe_finder *pf) --- 5 unchanged lines hidden (view full) --- 641int find_probe_point(int fd, struct probe_point *pp) 642{ 643 struct probe_finder pf = {.pp = pp}; 644 int ret; 645 Dwarf_Off off, noff; 646 size_t cuhl; 647 Dwarf_Die *diep; 648 Dwarf *dbg; |
496 int fno = 0; | |
497 498 dbg = dwarf_begin(fd, DWARF_C_READ); 499 if (!dbg) 500 return -ENOENT; 501 502 pp->found = 0; 503 off = 0; | 649 650 dbg = dwarf_begin(fd, DWARF_C_READ); 651 if (!dbg) 652 return -ENOENT; 653 654 pp->found = 0; 655 off = 0; |
656 line_list__init(&pf.lcache); |
|
504 /* Loop on CUs (Compilation Unit) */ 505 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 506 /* Get the DIE(Debugging Information Entry) of this CU */ 507 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); 508 if (!diep) 509 continue; 510 511 /* Check if target file is included. */ 512 if (pp->file) | 657 /* Loop on CUs (Compilation Unit) */ 658 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { 659 /* Get the DIE(Debugging Information Entry) of this CU */ 660 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); 661 if (!diep) 662 continue; 663 664 /* Check if target file is included. */ 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) */ 519 ret = dwarf_lowpc(&pf.cu_die, &pf.cu_base); 520 if (ret != 0) 521 pf.cu_base = 0; 522 if (pp->function) 523 find_probe_point_by_func(&pf); | 671 /* Save CU base address (for frame_base) */ 672 ret = dwarf_lowpc(&pf.cu_die, &pf.cu_base); 673 if (ret != 0) 674 pf.cu_base = 0; 675 if (pp->function) 676 find_probe_point_by_func(&pf); |
677 else if (pp->lazy_line) 678 find_probe_point_lazy(NULL, &pf); |
|
524 else { 525 pf.lno = pp->line; 526 find_probe_point_by_line(&pf); 527 } 528 } 529 off = noff; 530 } | 679 else { 680 pf.lno = pp->line; 681 find_probe_point_by_line(&pf); 682 } 683 } 684 off = noff; 685 } |
686 line_list__free(&pf.lcache); |
|
531 dwarf_end(dbg); 532 533 return pp->found; 534} 535 | 687 dwarf_end(dbg); 688 689 return pp->found; 690} 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 */ 562static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 563{ 564 Dwarf_Lines *lines; 565 Dwarf_Line *line; 566 size_t nlines, i; 567 Dwarf_Addr addr; 568 int lineno; 569 int ret; 570 const char *src; 571 Dwarf_Die die_mem; 572 | 692/* Find line range from its line number */ 693static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) 694{ 695 Dwarf_Lines *lines; 696 Dwarf_Line *line; 697 size_t nlines, i; 698 Dwarf_Addr addr; 699 int lineno; 700 int ret; 701 const char *src; 702 Dwarf_Die die_mem; 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); 575 DIE_IF(ret != 0); 576 577 for (i = 0; i < nlines; i++) { 578 line = dwarf_onesrcline(lines, i); 579 ret = dwarf_lineno(line, &lineno); 580 DIE_IF(ret != 0); 581 if (lf->lno_s > lineno || lf->lno_e < lineno) --- 14 unchanged lines hidden (view full) --- 596 /* TODO: Get fileno from line, but how? */ 597 src = dwarf_linesrc(line, NULL, NULL); 598 if (strtailcmp(src, lf->fname) != 0) 599 continue; 600 601 /* Copy real path */ 602 if (!lf->lr->path) 603 lf->lr->path = strdup(src); | 705 ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines); 706 DIE_IF(ret != 0); 707 708 for (i = 0; i < nlines; i++) { 709 line = dwarf_onesrcline(lines, i); 710 ret = dwarf_lineno(line, &lineno); 711 DIE_IF(ret != 0); 712 if (lf->lno_s > lineno || lf->lno_e < lineno) --- 14 unchanged lines hidden (view full) --- 727 /* TODO: Get fileno from line, but how? */ 728 src = dwarf_linesrc(line, NULL, NULL); 729 if (strtailcmp(src, lf->fname) != 0) 730 continue; 731 732 /* Copy real path */ 733 if (!lf->lr->path) 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 } 606 /* Update status */ 607 if (!list_empty(&lf->lr->line_list)) 608 lf->found = 1; 609 else { 610 free(lf->lr->path); 611 lf->lr->path = NULL; 612 } --- 41 unchanged lines hidden (view full) --- 654int find_line_range(int fd, struct line_range *lr) 655{ 656 struct line_finder lf = {.lr = lr, .found = 0}; 657 int ret; 658 Dwarf_Off off = 0, noff; 659 size_t cuhl; 660 Dwarf_Die *diep; 661 Dwarf *dbg; | 736 } 737 /* Update status */ 738 if (!list_empty(&lf->lr->line_list)) 739 lf->found = 1; 740 else { 741 free(lf->lr->path); 742 lf->lr->path = NULL; 743 } --- 41 unchanged lines hidden (view full) --- 785int find_line_range(int fd, struct line_range *lr) 786{ 787 struct line_finder lf = {.lr = lr, .found = 0}; 788 int ret; 789 Dwarf_Off off = 0, noff; 790 size_t cuhl; 791 Dwarf_Die *diep; 792 Dwarf *dbg; |
662 int fno; | |
663 664 dbg = dwarf_begin(fd, DWARF_C_READ); 665 if (!dbg) 666 return -ENOENT; 667 668 /* Loop on CUs (Compilation Unit) */ 669 while (!lf.found) { 670 ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL); 671 if (ret != 0) 672 break; 673 674 /* Get the DIE(Debugging Information Entry) of this CU */ 675 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die); 676 if (!diep) 677 continue; 678 679 /* Check if target file is included. */ 680 if (lr->file) | 793 794 dbg = dwarf_begin(fd, DWARF_C_READ); 795 if (!dbg) 796 return -ENOENT; 797 798 /* Loop on CUs (Compilation Unit) */ 799 while (!lf.found) { 800 ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL); 801 if (ret != 0) 802 break; 803 804 /* Get the DIE(Debugging Information Entry) of this CU */ 805 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die); 806 if (!diep) 807 continue; 808 809 /* Check if target file is included. */ 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) 687 find_line_range_by_func(&lf); 688 else { | 816 if (lr->function) 817 find_line_range_by_func(&lf); 818 else { |
689 lf.fname = lr->file; | |
690 lf.lno_s = lr->start; 691 if (!lr->end) 692 lf.lno_e = INT_MAX; 693 else 694 lf.lno_e = lr->end; 695 find_line_range_by_line(NULL, &lf); 696 } 697 } 698 off = noff; 699 } 700 pr_debug("path: %lx\n", (unsigned long)lr->path); 701 dwarf_end(dbg); 702 return lf.found; 703} 704 | 819 lf.lno_s = lr->start; 820 if (!lr->end) 821 lf.lno_e = INT_MAX; 822 else 823 lf.lno_e = lr->end; 824 find_line_range_by_line(NULL, &lf); 825 } 826 } 827 off = noff; 828 } 829 pr_debug("path: %lx\n", (unsigned long)lr->path); 830 dwarf_end(dbg); 831 return lf.found; 832} 833 |