diff options
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r-- | tools/perf/util/probe-finder.c | 533 |
1 files changed, 306 insertions, 227 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index ab83b6ac5d65..194f9e2a3285 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <ctype.h> | 33 | #include <ctype.h> |
34 | #include <dwarf-regs.h> | 34 | #include <dwarf-regs.h> |
35 | 35 | ||
36 | #include <linux/bitops.h> | ||
36 | #include "event.h" | 37 | #include "event.h" |
37 | #include "debug.h" | 38 | #include "debug.h" |
38 | #include "util.h" | 39 | #include "util.h" |
@@ -280,6 +281,19 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | |||
280 | return name ? (strcmp(tname, name) == 0) : false; | 281 | return name ? (strcmp(tname, name) == 0) : false; |
281 | } | 282 | } |
282 | 283 | ||
284 | /* Get callsite line number of inline-function instance */ | ||
285 | static int die_get_call_lineno(Dwarf_Die *in_die) | ||
286 | { | ||
287 | Dwarf_Attribute attr; | ||
288 | Dwarf_Word ret; | ||
289 | |||
290 | if (!dwarf_attr(in_die, DW_AT_call_line, &attr)) | ||
291 | return -ENOENT; | ||
292 | |||
293 | dwarf_formudata(&attr, &ret); | ||
294 | return (int)ret; | ||
295 | } | ||
296 | |||
283 | /* Get type die */ | 297 | /* Get type die */ |
284 | static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) | 298 | static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) |
285 | { | 299 | { |
@@ -320,13 +334,23 @@ static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) | |||
320 | return vr_die; | 334 | return vr_die; |
321 | } | 335 | } |
322 | 336 | ||
323 | static bool die_is_signed_type(Dwarf_Die *tp_die) | 337 | static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name, |
338 | Dwarf_Word *result) | ||
324 | { | 339 | { |
325 | Dwarf_Attribute attr; | 340 | Dwarf_Attribute attr; |
341 | |||
342 | if (dwarf_attr(tp_die, attr_name, &attr) == NULL || | ||
343 | dwarf_formudata(&attr, result) != 0) | ||
344 | return -ENOENT; | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static bool die_is_signed_type(Dwarf_Die *tp_die) | ||
350 | { | ||
326 | Dwarf_Word ret; | 351 | Dwarf_Word ret; |
327 | 352 | ||
328 | if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL || | 353 | if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret)) |
329 | dwarf_formudata(&attr, &ret) != 0) | ||
330 | return false; | 354 | return false; |
331 | 355 | ||
332 | return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || | 356 | return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || |
@@ -335,11 +359,29 @@ static bool die_is_signed_type(Dwarf_Die *tp_die) | |||
335 | 359 | ||
336 | static int die_get_byte_size(Dwarf_Die *tp_die) | 360 | static int die_get_byte_size(Dwarf_Die *tp_die) |
337 | { | 361 | { |
338 | Dwarf_Attribute attr; | ||
339 | Dwarf_Word ret; | 362 | Dwarf_Word ret; |
340 | 363 | ||
341 | if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL || | 364 | if (die_get_attr_udata(tp_die, DW_AT_byte_size, &ret)) |
342 | dwarf_formudata(&attr, &ret) != 0) | 365 | return 0; |
366 | |||
367 | return (int)ret; | ||
368 | } | ||
369 | |||
370 | static int die_get_bit_size(Dwarf_Die *tp_die) | ||
371 | { | ||
372 | Dwarf_Word ret; | ||
373 | |||
374 | if (die_get_attr_udata(tp_die, DW_AT_bit_size, &ret)) | ||
375 | return 0; | ||
376 | |||
377 | return (int)ret; | ||
378 | } | ||
379 | |||
380 | static int die_get_bit_offset(Dwarf_Die *tp_die) | ||
381 | { | ||
382 | Dwarf_Word ret; | ||
383 | |||
384 | if (die_get_attr_udata(tp_die, DW_AT_bit_offset, &ret)) | ||
343 | return 0; | 385 | return 0; |
344 | 386 | ||
345 | return (int)ret; | 387 | return (int)ret; |
@@ -458,6 +500,151 @@ static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | |||
458 | return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); | 500 | return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); |
459 | } | 501 | } |
460 | 502 | ||
503 | /* Walker on lines (Note: line number will not be sorted) */ | ||
504 | typedef int (* line_walk_handler_t) (const char *fname, int lineno, | ||
505 | Dwarf_Addr addr, void *data); | ||
506 | |||
507 | struct __line_walk_param { | ||
508 | const char *fname; | ||
509 | line_walk_handler_t handler; | ||
510 | void *data; | ||
511 | int retval; | ||
512 | }; | ||
513 | |||
514 | static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) | ||
515 | { | ||
516 | struct __line_walk_param *lw = data; | ||
517 | Dwarf_Addr addr; | ||
518 | int lineno; | ||
519 | |||
520 | if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { | ||
521 | lineno = die_get_call_lineno(in_die); | ||
522 | if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { | ||
523 | lw->retval = lw->handler(lw->fname, lineno, addr, | ||
524 | lw->data); | ||
525 | if (lw->retval != 0) | ||
526 | return DIE_FIND_CB_FOUND; | ||
527 | } | ||
528 | } | ||
529 | return DIE_FIND_CB_SIBLING; | ||
530 | } | ||
531 | |||
532 | /* Walk on lines of blocks included in given DIE */ | ||
533 | static int __die_walk_funclines(Dwarf_Die *sp_die, | ||
534 | line_walk_handler_t handler, void *data) | ||
535 | { | ||
536 | struct __line_walk_param lw = { | ||
537 | .handler = handler, | ||
538 | .data = data, | ||
539 | .retval = 0, | ||
540 | }; | ||
541 | Dwarf_Die die_mem; | ||
542 | Dwarf_Addr addr; | ||
543 | int lineno; | ||
544 | |||
545 | /* Handle function declaration line */ | ||
546 | lw.fname = dwarf_decl_file(sp_die); | ||
547 | if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 && | ||
548 | dwarf_entrypc(sp_die, &addr) == 0) { | ||
549 | lw.retval = handler(lw.fname, lineno, addr, data); | ||
550 | if (lw.retval != 0) | ||
551 | goto done; | ||
552 | } | ||
553 | die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem); | ||
554 | done: | ||
555 | return lw.retval; | ||
556 | } | ||
557 | |||
558 | static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) | ||
559 | { | ||
560 | struct __line_walk_param *lw = data; | ||
561 | |||
562 | lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data); | ||
563 | if (lw->retval != 0) | ||
564 | return DWARF_CB_ABORT; | ||
565 | |||
566 | return DWARF_CB_OK; | ||
567 | } | ||
568 | |||
569 | /* | ||
570 | * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on | ||
571 | * the lines inside the subprogram, otherwise PDIE must be a CU DIE. | ||
572 | */ | ||
573 | static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler, | ||
574 | void *data) | ||
575 | { | ||
576 | Dwarf_Lines *lines; | ||
577 | Dwarf_Line *line; | ||
578 | Dwarf_Addr addr; | ||
579 | const char *fname; | ||
580 | int lineno, ret = 0; | ||
581 | Dwarf_Die die_mem, *cu_die; | ||
582 | size_t nlines, i; | ||
583 | |||
584 | /* Get the CU die */ | ||
585 | if (dwarf_tag(pdie) == DW_TAG_subprogram) | ||
586 | cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL); | ||
587 | else | ||
588 | cu_die = pdie; | ||
589 | if (!cu_die) { | ||
590 | pr_debug2("Failed to get CU from subprogram\n"); | ||
591 | return -EINVAL; | ||
592 | } | ||
593 | |||
594 | /* Get lines list in the CU */ | ||
595 | if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) { | ||
596 | pr_debug2("Failed to get source lines on this CU.\n"); | ||
597 | return -ENOENT; | ||
598 | } | ||
599 | pr_debug2("Get %zd lines from this CU\n", nlines); | ||
600 | |||
601 | /* Walk on the lines on lines list */ | ||
602 | for (i = 0; i < nlines; i++) { | ||
603 | line = dwarf_onesrcline(lines, i); | ||
604 | if (line == NULL || | ||
605 | dwarf_lineno(line, &lineno) != 0 || | ||
606 | dwarf_lineaddr(line, &addr) != 0) { | ||
607 | pr_debug2("Failed to get line info. " | ||
608 | "Possible error in debuginfo.\n"); | ||
609 | continue; | ||
610 | } | ||
611 | /* Filter lines based on address */ | ||
612 | if (pdie != cu_die) | ||
613 | /* | ||
614 | * Address filtering | ||
615 | * The line is included in given function, and | ||
616 | * no inline block includes it. | ||
617 | */ | ||
618 | if (!dwarf_haspc(pdie, addr) || | ||
619 | die_find_inlinefunc(pdie, addr, &die_mem)) | ||
620 | continue; | ||
621 | /* Get source line */ | ||
622 | fname = dwarf_linesrc(line, NULL, NULL); | ||
623 | |||
624 | ret = handler(fname, lineno, addr, data); | ||
625 | if (ret != 0) | ||
626 | return ret; | ||
627 | } | ||
628 | |||
629 | /* | ||
630 | * Dwarf lines doesn't include function declarations and inlined | ||
631 | * subroutines. We have to check functions list or given function. | ||
632 | */ | ||
633 | if (pdie != cu_die) | ||
634 | ret = __die_walk_funclines(pdie, handler, data); | ||
635 | else { | ||
636 | struct __line_walk_param param = { | ||
637 | .handler = handler, | ||
638 | .data = data, | ||
639 | .retval = 0, | ||
640 | }; | ||
641 | dwarf_getfuncs(cu_die, __die_walk_culines_cb, ¶m, 0); | ||
642 | ret = param.retval; | ||
643 | } | ||
644 | |||
645 | return ret; | ||
646 | } | ||
647 | |||
461 | struct __find_variable_param { | 648 | struct __find_variable_param { |
462 | const char *name; | 649 | const char *name; |
463 | Dwarf_Addr addr; | 650 | Dwarf_Addr addr; |
@@ -669,6 +856,8 @@ static_var: | |||
669 | return 0; | 856 | return 0; |
670 | } | 857 | } |
671 | 858 | ||
859 | #define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long)) | ||
860 | |||
672 | static int convert_variable_type(Dwarf_Die *vr_die, | 861 | static int convert_variable_type(Dwarf_Die *vr_die, |
673 | struct probe_trace_arg *tvar, | 862 | struct probe_trace_arg *tvar, |
674 | const char *cast) | 863 | const char *cast) |
@@ -685,6 +874,14 @@ static int convert_variable_type(Dwarf_Die *vr_die, | |||
685 | return (tvar->type == NULL) ? -ENOMEM : 0; | 874 | return (tvar->type == NULL) ? -ENOMEM : 0; |
686 | } | 875 | } |
687 | 876 | ||
877 | if (die_get_bit_size(vr_die) != 0) { | ||
878 | /* This is a bitfield */ | ||
879 | ret = snprintf(buf, 16, "b%d@%d/%zd", die_get_bit_size(vr_die), | ||
880 | die_get_bit_offset(vr_die), | ||
881 | BYTES_TO_BITS(die_get_byte_size(vr_die))); | ||
882 | goto formatted; | ||
883 | } | ||
884 | |||
688 | if (die_get_real_type(vr_die, &type) == NULL) { | 885 | if (die_get_real_type(vr_die, &type) == NULL) { |
689 | pr_warning("Failed to get a type information of %s.\n", | 886 | pr_warning("Failed to get a type information of %s.\n", |
690 | dwarf_diename(vr_die)); | 887 | dwarf_diename(vr_die)); |
@@ -729,29 +926,31 @@ static int convert_variable_type(Dwarf_Die *vr_die, | |||
729 | return (tvar->type == NULL) ? -ENOMEM : 0; | 926 | return (tvar->type == NULL) ? -ENOMEM : 0; |
730 | } | 927 | } |
731 | 928 | ||
732 | ret = die_get_byte_size(&type) * 8; | 929 | ret = BYTES_TO_BITS(die_get_byte_size(&type)); |
733 | if (ret) { | 930 | if (!ret) |
734 | /* Check the bitwidth */ | 931 | /* No size ... try to use default type */ |
735 | if (ret > MAX_BASIC_TYPE_BITS) { | 932 | return 0; |
736 | pr_info("%s exceeds max-bitwidth." | ||
737 | " Cut down to %d bits.\n", | ||
738 | dwarf_diename(&type), MAX_BASIC_TYPE_BITS); | ||
739 | ret = MAX_BASIC_TYPE_BITS; | ||
740 | } | ||
741 | 933 | ||
742 | ret = snprintf(buf, 16, "%c%d", | 934 | /* Check the bitwidth */ |
743 | die_is_signed_type(&type) ? 's' : 'u', ret); | 935 | if (ret > MAX_BASIC_TYPE_BITS) { |
744 | if (ret < 0 || ret >= 16) { | 936 | pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n", |
745 | if (ret >= 16) | 937 | dwarf_diename(&type), MAX_BASIC_TYPE_BITS); |
746 | ret = -E2BIG; | 938 | ret = MAX_BASIC_TYPE_BITS; |
747 | pr_warning("Failed to convert variable type: %s\n", | 939 | } |
748 | strerror(-ret)); | 940 | ret = snprintf(buf, 16, "%c%d", |
749 | return ret; | 941 | die_is_signed_type(&type) ? 's' : 'u', ret); |
750 | } | 942 | |
751 | tvar->type = strdup(buf); | 943 | formatted: |
752 | if (tvar->type == NULL) | 944 | if (ret < 0 || ret >= 16) { |
753 | return -ENOMEM; | 945 | if (ret >= 16) |
946 | ret = -E2BIG; | ||
947 | pr_warning("Failed to convert variable type: %s\n", | ||
948 | strerror(-ret)); | ||
949 | return ret; | ||
754 | } | 950 | } |
951 | tvar->type = strdup(buf); | ||
952 | if (tvar->type == NULL) | ||
953 | return -ENOMEM; | ||
755 | return 0; | 954 | return 0; |
756 | } | 955 | } |
757 | 956 | ||
@@ -1050,157 +1249,102 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1050 | return ret; | 1249 | return ret; |
1051 | } | 1250 | } |
1052 | 1251 | ||
1053 | /* Find probe point from its line number */ | 1252 | static int probe_point_line_walker(const char *fname, int lineno, |
1054 | static int find_probe_point_by_line(struct probe_finder *pf) | 1253 | Dwarf_Addr addr, void *data) |
1055 | { | 1254 | { |
1056 | Dwarf_Lines *lines; | 1255 | struct probe_finder *pf = data; |
1057 | Dwarf_Line *line; | 1256 | int ret; |
1058 | size_t nlines, i; | ||
1059 | Dwarf_Addr addr; | ||
1060 | int lineno; | ||
1061 | int ret = 0; | ||
1062 | |||
1063 | if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { | ||
1064 | pr_warning("No source lines found.\n"); | ||
1065 | return -ENOENT; | ||
1066 | } | ||
1067 | 1257 | ||
1068 | for (i = 0; i < nlines && ret == 0; i++) { | 1258 | if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) |
1069 | line = dwarf_onesrcline(lines, i); | 1259 | return 0; |
1070 | if (dwarf_lineno(line, &lineno) != 0 || | ||
1071 | lineno != pf->lno) | ||
1072 | continue; | ||
1073 | 1260 | ||
1074 | /* TODO: Get fileno from line, but how? */ | 1261 | pf->addr = addr; |
1075 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) | 1262 | ret = call_probe_finder(NULL, pf); |
1076 | continue; | ||
1077 | 1263 | ||
1078 | if (dwarf_lineaddr(line, &addr) != 0) { | 1264 | /* Continue if no error, because the line will be in inline function */ |
1079 | pr_warning("Failed to get the address of the line.\n"); | 1265 | return ret < 0 ? ret : 0; |
1080 | return -ENOENT; | 1266 | } |
1081 | } | ||
1082 | pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n", | ||
1083 | (int)i, lineno, (uintmax_t)addr); | ||
1084 | pf->addr = addr; | ||
1085 | 1267 | ||
1086 | ret = call_probe_finder(NULL, pf); | 1268 | /* Find probe point from its line number */ |
1087 | /* Continuing, because target line might be inlined. */ | 1269 | static int find_probe_point_by_line(struct probe_finder *pf) |
1088 | } | 1270 | { |
1089 | return ret; | 1271 | return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); |
1090 | } | 1272 | } |
1091 | 1273 | ||
1092 | /* Find lines which match lazy pattern */ | 1274 | /* Find lines which match lazy pattern */ |
1093 | static int find_lazy_match_lines(struct list_head *head, | 1275 | static int find_lazy_match_lines(struct list_head *head, |
1094 | const char *fname, const char *pat) | 1276 | const char *fname, const char *pat) |
1095 | { | 1277 | { |
1096 | char *fbuf, *p1, *p2; | 1278 | FILE *fp; |
1097 | int fd, line, nlines = -1; | 1279 | char *line = NULL; |
1098 | struct stat st; | 1280 | size_t line_len; |
1099 | 1281 | ssize_t len; | |
1100 | fd = open(fname, O_RDONLY); | 1282 | int count = 0, linenum = 1; |
1101 | if (fd < 0) { | 1283 | |
1102 | pr_warning("Failed to open %s: %s\n", fname, strerror(-fd)); | 1284 | fp = fopen(fname, "r"); |
1285 | if (!fp) { | ||
1286 | pr_warning("Failed to open %s: %s\n", fname, strerror(errno)); | ||
1103 | return -errno; | 1287 | return -errno; |
1104 | } | 1288 | } |
1105 | 1289 | ||
1106 | if (fstat(fd, &st) < 0) { | 1290 | while ((len = getline(&line, &line_len, fp)) > 0) { |
1107 | pr_warning("Failed to get the size of %s: %s\n", | 1291 | |
1108 | fname, strerror(errno)); | 1292 | if (line[len - 1] == '\n') |
1109 | nlines = -errno; | 1293 | line[len - 1] = '\0'; |
1110 | goto out_close; | 1294 | |
1111 | } | 1295 | if (strlazymatch(line, pat)) { |
1112 | 1296 | line_list__add_line(head, linenum); | |
1113 | nlines = -ENOMEM; | 1297 | count++; |
1114 | fbuf = malloc(st.st_size + 2); | ||
1115 | if (fbuf == NULL) | ||
1116 | goto out_close; | ||
1117 | if (read(fd, fbuf, st.st_size) < 0) { | ||
1118 | pr_warning("Failed to read %s: %s\n", fname, strerror(errno)); | ||
1119 | nlines = -errno; | ||
1120 | goto out_free_fbuf; | ||
1121 | } | ||
1122 | fbuf[st.st_size] = '\n'; /* Dummy line */ | ||
1123 | fbuf[st.st_size + 1] = '\0'; | ||
1124 | p1 = fbuf; | ||
1125 | line = 1; | ||
1126 | nlines = 0; | ||
1127 | while ((p2 = strchr(p1, '\n')) != NULL) { | ||
1128 | *p2 = '\0'; | ||
1129 | if (strlazymatch(p1, pat)) { | ||
1130 | line_list__add_line(head, line); | ||
1131 | nlines++; | ||
1132 | } | 1298 | } |
1133 | line++; | 1299 | linenum++; |
1134 | p1 = p2 + 1; | ||
1135 | } | 1300 | } |
1136 | out_free_fbuf: | 1301 | |
1137 | free(fbuf); | 1302 | if (ferror(fp)) |
1138 | out_close: | 1303 | count = -errno; |
1139 | close(fd); | 1304 | free(line); |
1140 | return nlines; | 1305 | fclose(fp); |
1306 | |||
1307 | if (count == 0) | ||
1308 | pr_debug("No matched lines found in %s.\n", fname); | ||
1309 | return count; | ||
1310 | } | ||
1311 | |||
1312 | static int probe_point_lazy_walker(const char *fname, int lineno, | ||
1313 | Dwarf_Addr addr, void *data) | ||
1314 | { | ||
1315 | struct probe_finder *pf = data; | ||
1316 | int ret; | ||
1317 | |||
1318 | if (!line_list__has_line(&pf->lcache, lineno) || | ||
1319 | strtailcmp(fname, pf->fname) != 0) | ||
1320 | return 0; | ||
1321 | |||
1322 | pr_debug("Probe line found: line:%d addr:0x%llx\n", | ||
1323 | lineno, (unsigned long long)addr); | ||
1324 | pf->addr = addr; | ||
1325 | ret = call_probe_finder(NULL, pf); | ||
1326 | |||
1327 | /* | ||
1328 | * Continue if no error, because the lazy pattern will match | ||
1329 | * to other lines | ||
1330 | */ | ||
1331 | return ret < 0 ? ret : 0; | ||
1141 | } | 1332 | } |
1142 | 1333 | ||
1143 | /* Find probe points from lazy pattern */ | 1334 | /* Find probe points from lazy pattern */ |
1144 | static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | 1335 | static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) |
1145 | { | 1336 | { |
1146 | Dwarf_Lines *lines; | ||
1147 | Dwarf_Line *line; | ||
1148 | size_t nlines, i; | ||
1149 | Dwarf_Addr addr; | ||
1150 | Dwarf_Die die_mem; | ||
1151 | int lineno; | ||
1152 | int ret = 0; | 1337 | int ret = 0; |
1153 | 1338 | ||
1154 | if (list_empty(&pf->lcache)) { | 1339 | if (list_empty(&pf->lcache)) { |
1155 | /* Matching lazy line pattern */ | 1340 | /* Matching lazy line pattern */ |
1156 | ret = find_lazy_match_lines(&pf->lcache, pf->fname, | 1341 | ret = find_lazy_match_lines(&pf->lcache, pf->fname, |
1157 | pf->pev->point.lazy_line); | 1342 | pf->pev->point.lazy_line); |
1158 | if (ret == 0) { | 1343 | if (ret <= 0) |
1159 | pr_debug("No matched lines found in %s.\n", pf->fname); | ||
1160 | return 0; | ||
1161 | } else if (ret < 0) | ||
1162 | return ret; | 1344 | return ret; |
1163 | } | 1345 | } |
1164 | 1346 | ||
1165 | if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { | 1347 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); |
1166 | pr_warning("No source lines found.\n"); | ||
1167 | return -ENOENT; | ||
1168 | } | ||
1169 | |||
1170 | for (i = 0; i < nlines && ret >= 0; i++) { | ||
1171 | line = dwarf_onesrcline(lines, i); | ||
1172 | |||
1173 | if (dwarf_lineno(line, &lineno) != 0 || | ||
1174 | !line_list__has_line(&pf->lcache, lineno)) | ||
1175 | continue; | ||
1176 | |||
1177 | /* TODO: Get fileno from line, but how? */ | ||
1178 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) | ||
1179 | continue; | ||
1180 | |||
1181 | if (dwarf_lineaddr(line, &addr) != 0) { | ||
1182 | pr_debug("Failed to get the address of line %d.\n", | ||
1183 | lineno); | ||
1184 | continue; | ||
1185 | } | ||
1186 | if (sp_die) { | ||
1187 | /* Address filtering 1: does sp_die include addr? */ | ||
1188 | if (!dwarf_haspc(sp_die, addr)) | ||
1189 | continue; | ||
1190 | /* Address filtering 2: No child include addr? */ | ||
1191 | if (die_find_inlinefunc(sp_die, addr, &die_mem)) | ||
1192 | continue; | ||
1193 | } | ||
1194 | |||
1195 | pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n", | ||
1196 | (int)i, lineno, (unsigned long long)addr); | ||
1197 | pf->addr = addr; | ||
1198 | |||
1199 | ret = call_probe_finder(sp_die, pf); | ||
1200 | /* Continuing, because target line might be inlined. */ | ||
1201 | } | ||
1202 | /* TODO: deallocate lines, but how? */ | ||
1203 | return ret; | ||
1204 | } | 1348 | } |
1205 | 1349 | ||
1206 | /* Callback parameter with return value */ | 1350 | /* Callback parameter with return value */ |
@@ -1318,8 +1462,7 @@ static int find_probes(int fd, struct probe_finder *pf) | |||
1318 | off = 0; | 1462 | off = 0; |
1319 | line_list__init(&pf->lcache); | 1463 | line_list__init(&pf->lcache); |
1320 | /* Loop on CUs (Compilation Unit) */ | 1464 | /* Loop on CUs (Compilation Unit) */ |
1321 | while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && | 1465 | while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { |
1322 | ret >= 0) { | ||
1323 | /* Get the DIE(Debugging Information Entry) of this CU */ | 1466 | /* Get the DIE(Debugging Information Entry) of this CU */ |
1324 | diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die); | 1467 | diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die); |
1325 | if (!diep) | 1468 | if (!diep) |
@@ -1340,6 +1483,8 @@ static int find_probes(int fd, struct probe_finder *pf) | |||
1340 | pf->lno = pp->line; | 1483 | pf->lno = pp->line; |
1341 | ret = find_probe_point_by_line(pf); | 1484 | ret = find_probe_point_by_line(pf); |
1342 | } | 1485 | } |
1486 | if (ret < 0) | ||
1487 | break; | ||
1343 | } | 1488 | } |
1344 | off = noff; | 1489 | off = noff; |
1345 | } | 1490 | } |
@@ -1644,91 +1789,28 @@ static int line_range_add_line(const char *src, unsigned int lineno, | |||
1644 | return line_list__add_line(&lr->line_list, lineno); | 1789 | return line_list__add_line(&lr->line_list, lineno); |
1645 | } | 1790 | } |
1646 | 1791 | ||
1647 | /* Search function declaration lines */ | 1792 | static int line_range_walk_cb(const char *fname, int lineno, |
1648 | static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data) | 1793 | Dwarf_Addr addr __used, |
1794 | void *data) | ||
1649 | { | 1795 | { |
1650 | struct dwarf_callback_param *param = data; | 1796 | struct line_finder *lf = data; |
1651 | struct line_finder *lf = param->data; | ||
1652 | const char *src; | ||
1653 | int lineno; | ||
1654 | 1797 | ||
1655 | src = dwarf_decl_file(sp_die); | 1798 | if ((strtailcmp(fname, lf->fname) != 0) || |
1656 | if (src && strtailcmp(src, lf->fname) != 0) | ||
1657 | return DWARF_CB_OK; | ||
1658 | |||
1659 | if (dwarf_decl_line(sp_die, &lineno) != 0 || | ||
1660 | (lf->lno_s > lineno || lf->lno_e < lineno)) | 1799 | (lf->lno_s > lineno || lf->lno_e < lineno)) |
1661 | return DWARF_CB_OK; | 1800 | return 0; |
1662 | 1801 | ||
1663 | param->retval = line_range_add_line(src, lineno, lf->lr); | 1802 | if (line_range_add_line(fname, lineno, lf->lr) < 0) |
1664 | if (param->retval < 0) | 1803 | return -EINVAL; |
1665 | return DWARF_CB_ABORT; | ||
1666 | return DWARF_CB_OK; | ||
1667 | } | ||
1668 | 1804 | ||
1669 | static int find_line_range_func_decl_lines(struct line_finder *lf) | 1805 | return 0; |
1670 | { | ||
1671 | struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; | ||
1672 | dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, ¶m, 0); | ||
1673 | return param.retval; | ||
1674 | } | 1806 | } |
1675 | 1807 | ||
1676 | /* Find line range from its line number */ | 1808 | /* Find line range from its line number */ |
1677 | static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | 1809 | static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) |
1678 | { | 1810 | { |
1679 | Dwarf_Lines *lines; | 1811 | int ret; |
1680 | Dwarf_Line *line; | ||
1681 | size_t nlines, i; | ||
1682 | Dwarf_Addr addr; | ||
1683 | int lineno, ret = 0; | ||
1684 | const char *src; | ||
1685 | Dwarf_Die die_mem; | ||
1686 | |||
1687 | line_list__init(&lf->lr->line_list); | ||
1688 | if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) { | ||
1689 | pr_warning("No source lines found.\n"); | ||
1690 | return -ENOENT; | ||
1691 | } | ||
1692 | |||
1693 | /* Search probable lines on lines list */ | ||
1694 | for (i = 0; i < nlines; i++) { | ||
1695 | line = dwarf_onesrcline(lines, i); | ||
1696 | if (dwarf_lineno(line, &lineno) != 0 || | ||
1697 | (lf->lno_s > lineno || lf->lno_e < lineno)) | ||
1698 | continue; | ||
1699 | |||
1700 | if (sp_die) { | ||
1701 | /* Address filtering 1: does sp_die include addr? */ | ||
1702 | if (dwarf_lineaddr(line, &addr) != 0 || | ||
1703 | !dwarf_haspc(sp_die, addr)) | ||
1704 | continue; | ||
1705 | |||
1706 | /* Address filtering 2: No child include addr? */ | ||
1707 | if (die_find_inlinefunc(sp_die, addr, &die_mem)) | ||
1708 | continue; | ||
1709 | } | ||
1710 | |||
1711 | /* TODO: Get fileno from line, but how? */ | ||
1712 | src = dwarf_linesrc(line, NULL, NULL); | ||
1713 | if (strtailcmp(src, lf->fname) != 0) | ||
1714 | continue; | ||
1715 | |||
1716 | ret = line_range_add_line(src, lineno, lf->lr); | ||
1717 | if (ret < 0) | ||
1718 | return ret; | ||
1719 | } | ||
1720 | 1812 | ||
1721 | /* | 1813 | ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); |
1722 | * Dwarf lines doesn't include function declarations. We have to | ||
1723 | * check functions list or given function. | ||
1724 | */ | ||
1725 | if (sp_die) { | ||
1726 | src = dwarf_decl_file(sp_die); | ||
1727 | if (src && dwarf_decl_line(sp_die, &lineno) == 0 && | ||
1728 | (lf->lno_s <= lineno && lf->lno_e >= lineno)) | ||
1729 | ret = line_range_add_line(src, lineno, lf->lr); | ||
1730 | } else | ||
1731 | ret = find_line_range_func_decl_lines(lf); | ||
1732 | 1814 | ||
1733 | /* Update status */ | 1815 | /* Update status */ |
1734 | if (ret >= 0) | 1816 | if (ret >= 0) |
@@ -1758,9 +1840,6 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
1758 | struct line_finder *lf = param->data; | 1840 | struct line_finder *lf = param->data; |
1759 | struct line_range *lr = lf->lr; | 1841 | struct line_range *lr = lf->lr; |
1760 | 1842 | ||
1761 | pr_debug("find (%llx) %s\n", | ||
1762 | (unsigned long long)dwarf_dieoffset(sp_die), | ||
1763 | dwarf_diename(sp_die)); | ||
1764 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && | 1843 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && |
1765 | die_compare_name(sp_die, lr->function)) { | 1844 | die_compare_name(sp_die, lr->function)) { |
1766 | lf->fname = dwarf_decl_file(sp_die); | 1845 | lf->fname = dwarf_decl_file(sp_die); |