1 /* 2 * probe-event.c : perf-probe definition to kprobe_events format 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 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 * 20 */ 21 22 #define _GNU_SOURCE 23 #include <sys/utsname.h> 24 #include <sys/types.h> 25 #include <sys/stat.h> 26 #include <fcntl.h> 27 #include <errno.h> 28 #include <stdio.h> 29 #include <unistd.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <stdarg.h> 33 #include <limits.h> 34 35 #undef _GNU_SOURCE 36 #include "event.h" 37 #include "string.h" 38 #include "strlist.h" 39 #include "debug.h" 40 #include "cache.h" 41 #include "color.h" 42 #include "parse-events.h" /* For debugfs_path */ 43 #include "probe-event.h" 44 45 #define MAX_CMDLEN 256 46 #define MAX_PROBE_ARGS 128 47 #define PERFPROBE_GROUP "probe" 48 49 #define semantic_error(msg ...) die("Semantic error :" msg) 50 51 /* If there is no space to write, returns -E2BIG. */ 52 static int e_snprintf(char *str, size_t size, const char *format, ...) 53 __attribute__((format(printf, 3, 4))); 54 55 static int e_snprintf(char *str, size_t size, const char *format, ...) 56 { 57 int ret; 58 va_list ap; 59 va_start(ap, format); 60 ret = vsnprintf(str, size, format, ap); 61 va_end(ap); 62 if (ret >= (int)size) 63 ret = -E2BIG; 64 return ret; 65 } 66 67 void parse_line_range_desc(const char *arg, struct line_range *lr) 68 { 69 const char *ptr; 70 char *tmp; 71 /* 72 * <Syntax> 73 * SRC:SLN[+NUM|-ELN] 74 * FUNC[:SLN[+NUM|-ELN]] 75 */ 76 ptr = strchr(arg, ':'); 77 if (ptr) { 78 lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0); 79 if (*tmp == '+') 80 lr->end = lr->start + (unsigned int)strtoul(tmp + 1, 81 &tmp, 0); 82 else if (*tmp == '-') 83 lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0); 84 else 85 lr->end = 0; 86 pr_debug("Line range is %u to %u\n", lr->start, lr->end); 87 if (lr->end && lr->start > lr->end) 88 semantic_error("Start line must be smaller" 89 " than end line."); 90 if (*tmp != '\0') 91 semantic_error("Tailing with invalid character '%d'.", 92 *tmp); 93 tmp = strndup(arg, (ptr - arg)); 94 } else 95 tmp = strdup(arg); 96 97 if (strchr(tmp, '.')) 98 lr->file = tmp; 99 else 100 lr->function = tmp; 101 } 102 103 /* Check the name is good for event/group */ 104 static bool check_event_name(const char *name) 105 { 106 if (!isalpha(*name) && *name != '_') 107 return false; 108 while (*++name != '\0') { 109 if (!isalpha(*name) && !isdigit(*name) && *name != '_') 110 return false; 111 } 112 return true; 113 } 114 115 /* Parse probepoint definition. */ 116 static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) 117 { 118 char *ptr, *tmp; 119 char c, nc = 0; 120 /* 121 * <Syntax> 122 * perf probe [EVENT=]SRC[:LN|;PTN] 123 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] 124 * 125 * TODO:Group name support 126 */ 127 128 ptr = strpbrk(arg, ";=@+%"); 129 if (ptr && *ptr == '=') { /* Event name */ 130 *ptr = '\0'; 131 tmp = ptr + 1; 132 ptr = strchr(arg, ':'); 133 if (ptr) /* Group name is not supported yet. */ 134 semantic_error("Group name is not supported yet."); 135 if (!check_event_name(arg)) 136 semantic_error("%s is bad for event name -it must " 137 "follow C symbol-naming rule.", arg); 138 pp->event = strdup(arg); 139 arg = tmp; 140 } 141 142 ptr = strpbrk(arg, ";:+@%"); 143 if (ptr) { 144 nc = *ptr; 145 *ptr++ = '\0'; 146 } 147 148 /* Check arg is function or file and copy it */ 149 if (strchr(arg, '.')) /* File */ 150 pp->file = strdup(arg); 151 else /* Function */ 152 pp->function = strdup(arg); 153 DIE_IF(pp->file == NULL && pp->function == NULL); 154 155 /* Parse other options */ 156 while (ptr) { 157 arg = ptr; 158 c = nc; 159 if (c == ';') { /* Lazy pattern must be the last part */ 160 pp->lazy_line = strdup(arg); 161 break; 162 } 163 ptr = strpbrk(arg, ";:+@%"); 164 if (ptr) { 165 nc = *ptr; 166 *ptr++ = '\0'; 167 } 168 switch (c) { 169 case ':': /* Line number */ 170 pp->line = strtoul(arg, &tmp, 0); 171 if (*tmp != '\0') 172 semantic_error("There is non-digit char" 173 " in line number."); 174 break; 175 case '+': /* Byte offset from a symbol */ 176 pp->offset = strtoul(arg, &tmp, 0); 177 if (*tmp != '\0') 178 semantic_error("There is non-digit character" 179 " in offset."); 180 break; 181 case '@': /* File name */ 182 if (pp->file) 183 semantic_error("SRC@SRC is not allowed."); 184 pp->file = strdup(arg); 185 DIE_IF(pp->file == NULL); 186 break; 187 case '%': /* Probe places */ 188 if (strcmp(arg, "return") == 0) { 189 pp->retprobe = 1; 190 } else /* Others not supported yet */ 191 semantic_error("%%%s is not supported.", arg); 192 break; 193 default: 194 DIE_IF("Program has a bug."); 195 break; 196 } 197 } 198 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 206 if (pp->line && pp->offset) 207 semantic_error("Offset can't be used with line number."); 208 209 if (!pp->line && !pp->lazy_line && pp->file && !pp->function) 210 semantic_error("File always requires line number or " 211 "lazy pattern."); 212 213 if (pp->offset && !pp->function) 214 semantic_error("Offset requires an entry function."); 215 216 if (pp->retprobe && !pp->function) 217 semantic_error("Return probe requires an entry function."); 218 219 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) 220 semantic_error("Offset/Line/Lazy pattern can't be used with " 221 "return probe."); 222 223 pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n", 224 pp->function, pp->file, pp->line, pp->offset, pp->retprobe, 225 pp->lazy_line); 226 } 227 228 /* Parse perf-probe event definition */ 229 void parse_perf_probe_event(const char *str, struct probe_point *pp, 230 bool *need_dwarf) 231 { 232 char **argv; 233 int argc, i; 234 235 *need_dwarf = false; 236 237 argv = argv_split(str, &argc); 238 if (!argv) 239 die("argv_split failed."); 240 if (argc > MAX_PROBE_ARGS + 1) 241 semantic_error("Too many arguments"); 242 243 /* Parse probe point */ 244 parse_perf_probe_probepoint(argv[0], pp); 245 if (pp->file || pp->line || pp->lazy_line) 246 *need_dwarf = true; 247 248 /* Copy arguments and ensure return probe has no C argument */ 249 pp->nr_args = argc - 1; 250 pp->args = zalloc(sizeof(char *) * pp->nr_args); 251 for (i = 0; i < pp->nr_args; i++) { 252 pp->args[i] = strdup(argv[i + 1]); 253 if (!pp->args[i]) 254 die("Failed to copy argument."); 255 if (is_c_varname(pp->args[i])) { 256 if (pp->retprobe) 257 semantic_error("You can't specify local" 258 " variable for kretprobe"); 259 *need_dwarf = true; 260 } 261 } 262 263 argv_free(argv); 264 } 265 266 /* Parse kprobe_events event into struct probe_point */ 267 void parse_trace_kprobe_event(const char *str, struct probe_point *pp) 268 { 269 char pr; 270 char *p; 271 int ret, i, argc; 272 char **argv; 273 274 pr_debug("Parsing kprobe_events: %s\n", str); 275 argv = argv_split(str, &argc); 276 if (!argv) 277 die("argv_split failed."); 278 if (argc < 2) 279 semantic_error("Too less arguments."); 280 281 /* Scan event and group name. */ 282 ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", 283 &pr, (float *)(void *)&pp->group, 284 (float *)(void *)&pp->event); 285 if (ret != 3) 286 semantic_error("Failed to parse event name: %s", argv[0]); 287 pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr); 288 289 pp->retprobe = (pr == 'r'); 290 291 /* Scan function name and offset */ 292 ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, 293 &pp->offset); 294 if (ret == 1) 295 pp->offset = 0; 296 297 /* kprobe_events doesn't have this information */ 298 pp->line = 0; 299 pp->file = NULL; 300 301 pp->nr_args = argc - 2; 302 pp->args = zalloc(sizeof(char *) * pp->nr_args); 303 for (i = 0; i < pp->nr_args; i++) { 304 p = strchr(argv[i + 2], '='); 305 if (p) /* We don't need which register is assigned. */ 306 *p = '\0'; 307 pp->args[i] = strdup(argv[i + 2]); 308 if (!pp->args[i]) 309 die("Failed to copy argument."); 310 } 311 312 argv_free(argv); 313 } 314 315 /* Synthesize only probe point (not argument) */ 316 int synthesize_perf_probe_point(struct probe_point *pp) 317 { 318 char *buf; 319 char offs[64] = "", line[64] = ""; 320 int ret; 321 322 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 323 pp->found = 1; 324 if (!buf) 325 die("Failed to allocate memory by zalloc."); 326 if (pp->offset) { 327 ret = e_snprintf(offs, 64, "+%d", pp->offset); 328 if (ret <= 0) 329 goto error; 330 } 331 if (pp->line) { 332 ret = e_snprintf(line, 64, ":%d", pp->line); 333 if (ret <= 0) 334 goto error; 335 } 336 337 if (pp->function) 338 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, 339 offs, pp->retprobe ? "%return" : "", line); 340 else 341 ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); 342 if (ret <= 0) { 343 error: 344 free(pp->probes[0]); 345 pp->probes[0] = NULL; 346 pp->found = 0; 347 } 348 return ret; 349 } 350 351 int synthesize_perf_probe_event(struct probe_point *pp) 352 { 353 char *buf; 354 int i, len, ret; 355 356 len = synthesize_perf_probe_point(pp); 357 if (len < 0) 358 return 0; 359 360 buf = pp->probes[0]; 361 for (i = 0; i < pp->nr_args; i++) { 362 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 363 pp->args[i]); 364 if (ret <= 0) 365 goto error; 366 len += ret; 367 } 368 pp->found = 1; 369 370 return pp->found; 371 error: 372 free(pp->probes[0]); 373 pp->probes[0] = NULL; 374 375 return ret; 376 } 377 378 int synthesize_trace_kprobe_event(struct probe_point *pp) 379 { 380 char *buf; 381 int i, len, ret; 382 383 pp->probes[0] = buf = zalloc(MAX_CMDLEN); 384 if (!buf) 385 die("Failed to allocate memory by zalloc."); 386 ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset); 387 if (ret <= 0) 388 goto error; 389 len = ret; 390 391 for (i = 0; i < pp->nr_args; i++) { 392 ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 393 pp->args[i]); 394 if (ret <= 0) 395 goto error; 396 len += ret; 397 } 398 pp->found = 1; 399 400 return pp->found; 401 error: 402 free(pp->probes[0]); 403 pp->probes[0] = NULL; 404 405 return ret; 406 } 407 408 static int open_kprobe_events(int flags, int mode) 409 { 410 char buf[PATH_MAX]; 411 int ret; 412 413 ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path); 414 if (ret < 0) 415 die("Failed to make kprobe_events path."); 416 417 ret = open(buf, flags, mode); 418 if (ret < 0) { 419 if (errno == ENOENT) 420 die("kprobe_events file does not exist -" 421 " please rebuild with CONFIG_KPROBE_EVENT."); 422 else 423 die("Could not open kprobe_events file: %s", 424 strerror(errno)); 425 } 426 return ret; 427 } 428 429 /* Get raw string list of current kprobe_events */ 430 static struct strlist *get_trace_kprobe_event_rawlist(int fd) 431 { 432 int ret, idx; 433 FILE *fp; 434 char buf[MAX_CMDLEN]; 435 char *p; 436 struct strlist *sl; 437 438 sl = strlist__new(true, NULL); 439 440 fp = fdopen(dup(fd), "r"); 441 while (!feof(fp)) { 442 p = fgets(buf, MAX_CMDLEN, fp); 443 if (!p) 444 break; 445 446 idx = strlen(p) - 1; 447 if (p[idx] == '\n') 448 p[idx] = '\0'; 449 ret = strlist__add(sl, buf); 450 if (ret < 0) 451 die("strlist__add failed: %s", strerror(-ret)); 452 } 453 fclose(fp); 454 455 return sl; 456 } 457 458 /* Free and zero clear probe_point */ 459 static void clear_probe_point(struct probe_point *pp) 460 { 461 int i; 462 463 if (pp->event) 464 free(pp->event); 465 if (pp->group) 466 free(pp->group); 467 if (pp->function) 468 free(pp->function); 469 if (pp->file) 470 free(pp->file); 471 if (pp->lazy_line) 472 free(pp->lazy_line); 473 for (i = 0; i < pp->nr_args; i++) 474 free(pp->args[i]); 475 if (pp->args) 476 free(pp->args); 477 for (i = 0; i < pp->found; i++) 478 free(pp->probes[i]); 479 memset(pp, 0, sizeof(*pp)); 480 } 481 482 /* Show an event */ 483 static void show_perf_probe_event(const char *event, const char *place, 484 struct probe_point *pp) 485 { 486 int i, ret; 487 char buf[128]; 488 489 ret = e_snprintf(buf, 128, "%s:%s", pp->group, event); 490 if (ret < 0) 491 die("Failed to copy event: %s", strerror(-ret)); 492 printf(" %-40s (on %s", buf, place); 493 494 if (pp->nr_args > 0) { 495 printf(" with"); 496 for (i = 0; i < pp->nr_args; i++) 497 printf(" %s", pp->args[i]); 498 } 499 printf(")\n"); 500 } 501 502 /* List up current perf-probe events */ 503 void show_perf_probe_events(void) 504 { 505 int fd; 506 struct probe_point pp; 507 struct strlist *rawlist; 508 struct str_node *ent; 509 510 setup_pager(); 511 memset(&pp, 0, sizeof(pp)); 512 513 fd = open_kprobe_events(O_RDONLY, 0); 514 rawlist = get_trace_kprobe_event_rawlist(fd); 515 close(fd); 516 517 strlist__for_each(ent, rawlist) { 518 parse_trace_kprobe_event(ent->s, &pp); 519 /* Synthesize only event probe point */ 520 synthesize_perf_probe_point(&pp); 521 /* Show an event */ 522 show_perf_probe_event(pp.event, pp.probes[0], &pp); 523 clear_probe_point(&pp); 524 } 525 526 strlist__delete(rawlist); 527 } 528 529 /* Get current perf-probe event names */ 530 static struct strlist *get_perf_event_names(int fd, bool include_group) 531 { 532 char buf[128]; 533 struct strlist *sl, *rawlist; 534 struct str_node *ent; 535 struct probe_point pp; 536 537 memset(&pp, 0, sizeof(pp)); 538 rawlist = get_trace_kprobe_event_rawlist(fd); 539 540 sl = strlist__new(true, NULL); 541 strlist__for_each(ent, rawlist) { 542 parse_trace_kprobe_event(ent->s, &pp); 543 if (include_group) { 544 if (e_snprintf(buf, 128, "%s:%s", pp.group, 545 pp.event) < 0) 546 die("Failed to copy group:event name."); 547 strlist__add(sl, buf); 548 } else 549 strlist__add(sl, pp.event); 550 clear_probe_point(&pp); 551 } 552 553 strlist__delete(rawlist); 554 555 return sl; 556 } 557 558 static void write_trace_kprobe_event(int fd, const char *buf) 559 { 560 int ret; 561 562 pr_debug("Writing event: %s\n", buf); 563 ret = write(fd, buf, strlen(buf)); 564 if (ret <= 0) 565 die("Failed to write event: %s", strerror(errno)); 566 } 567 568 static void get_new_event_name(char *buf, size_t len, const char *base, 569 struct strlist *namelist, bool allow_suffix) 570 { 571 int i, ret; 572 573 /* Try no suffix */ 574 ret = e_snprintf(buf, len, "%s", base); 575 if (ret < 0) 576 die("snprintf() failed: %s", strerror(-ret)); 577 if (!strlist__has_entry(namelist, buf)) 578 return; 579 580 if (!allow_suffix) { 581 pr_warning("Error: event \"%s\" already exists. " 582 "(Use -f to force duplicates.)\n", base); 583 die("Can't add new event."); 584 } 585 586 /* Try to add suffix */ 587 for (i = 1; i < MAX_EVENT_INDEX; i++) { 588 ret = e_snprintf(buf, len, "%s_%d", base, i); 589 if (ret < 0) 590 die("snprintf() failed: %s", strerror(-ret)); 591 if (!strlist__has_entry(namelist, buf)) 592 break; 593 } 594 if (i == MAX_EVENT_INDEX) 595 die("Too many events are on the same function."); 596 } 597 598 void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, 599 bool force_add) 600 { 601 int i, j, fd; 602 struct probe_point *pp; 603 char buf[MAX_CMDLEN]; 604 char event[64]; 605 struct strlist *namelist; 606 bool allow_suffix; 607 608 fd = open_kprobe_events(O_RDWR, O_APPEND); 609 /* Get current event names */ 610 namelist = get_perf_event_names(fd, false); 611 612 for (j = 0; j < nr_probes; j++) { 613 pp = probes + j; 614 if (!pp->event) 615 pp->event = strdup(pp->function); 616 if (!pp->group) 617 pp->group = strdup(PERFPROBE_GROUP); 618 DIE_IF(!pp->event || !pp->group); 619 /* If force_add is true, suffix search is allowed */ 620 allow_suffix = force_add; 621 for (i = 0; i < pp->found; i++) { 622 /* Get an unused new event name */ 623 get_new_event_name(event, 64, pp->event, namelist, 624 allow_suffix); 625 snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n", 626 pp->retprobe ? 'r' : 'p', 627 pp->group, event, 628 pp->probes[i]); 629 write_trace_kprobe_event(fd, buf); 630 printf("Added new event:\n"); 631 /* Get the first parameter (probe-point) */ 632 sscanf(pp->probes[i], "%s", buf); 633 show_perf_probe_event(event, buf, pp); 634 /* Add added event name to namelist */ 635 strlist__add(namelist, event); 636 /* 637 * Probes after the first probe which comes from same 638 * user input are always allowed to add suffix, because 639 * there might be several addresses corresponding to 640 * one code line. 641 */ 642 allow_suffix = true; 643 } 644 } 645 /* Show how to use the event. */ 646 printf("\nYou can now use it on all perf tools, such as:\n\n"); 647 printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event); 648 649 strlist__delete(namelist); 650 close(fd); 651 } 652 653 static void __del_trace_kprobe_event(int fd, struct str_node *ent) 654 { 655 char *p; 656 char buf[128]; 657 658 /* Convert from perf-probe event to trace-kprobe event */ 659 if (e_snprintf(buf, 128, "-:%s", ent->s) < 0) 660 die("Failed to copy event."); 661 p = strchr(buf + 2, ':'); 662 if (!p) 663 die("Internal error: %s should have ':' but not.", ent->s); 664 *p = '/'; 665 666 write_trace_kprobe_event(fd, buf); 667 printf("Remove event: %s\n", ent->s); 668 } 669 670 static void del_trace_kprobe_event(int fd, const char *group, 671 const char *event, struct strlist *namelist) 672 { 673 char buf[128]; 674 struct str_node *ent, *n; 675 int found = 0; 676 677 if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) 678 die("Failed to copy event."); 679 680 if (strpbrk(buf, "*?")) { /* Glob-exp */ 681 strlist__for_each_safe(ent, n, namelist) 682 if (strglobmatch(ent->s, buf)) { 683 found++; 684 __del_trace_kprobe_event(fd, ent); 685 strlist__remove(namelist, ent); 686 } 687 } else { 688 ent = strlist__find(namelist, buf); 689 if (ent) { 690 found++; 691 __del_trace_kprobe_event(fd, ent); 692 strlist__remove(namelist, ent); 693 } 694 } 695 if (found == 0) 696 pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf); 697 } 698 699 void del_trace_kprobe_events(struct strlist *dellist) 700 { 701 int fd; 702 const char *group, *event; 703 char *p, *str; 704 struct str_node *ent; 705 struct strlist *namelist; 706 707 fd = open_kprobe_events(O_RDWR, O_APPEND); 708 /* Get current event names */ 709 namelist = get_perf_event_names(fd, true); 710 711 strlist__for_each(ent, dellist) { 712 str = strdup(ent->s); 713 if (!str) 714 die("Failed to copy event."); 715 pr_debug("Parsing: %s\n", str); 716 p = strchr(str, ':'); 717 if (p) { 718 group = str; 719 *p = '\0'; 720 event = p + 1; 721 } else { 722 group = "*"; 723 event = str; 724 } 725 pr_debug("Group: %s, Event: %s\n", group, event); 726 del_trace_kprobe_event(fd, group, event, namelist); 727 free(str); 728 } 729 strlist__delete(namelist); 730 close(fd); 731 } 732 733 #define LINEBUF_SIZE 256 734 #define NR_ADDITIONAL_LINES 2 735 736 static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num) 737 { 738 char buf[LINEBUF_SIZE]; 739 const char *color = PERF_COLOR_BLUE; 740 741 if (fgets(buf, LINEBUF_SIZE, fp) == NULL) 742 goto error; 743 if (!skip) { 744 if (show_num) 745 fprintf(stdout, "%7u %s", l, buf); 746 else 747 color_fprintf(stdout, color, " %s", buf); 748 } 749 750 while (strlen(buf) == LINEBUF_SIZE - 1 && 751 buf[LINEBUF_SIZE - 2] != '\n') { 752 if (fgets(buf, LINEBUF_SIZE, fp) == NULL) 753 goto error; 754 if (!skip) { 755 if (show_num) 756 fprintf(stdout, "%s", buf); 757 else 758 color_fprintf(stdout, color, "%s", buf); 759 } 760 } 761 return; 762 error: 763 if (feof(fp)) 764 die("Source file is shorter than expected."); 765 else 766 die("File read error: %s", strerror(errno)); 767 } 768 769 void show_line_range(struct line_range *lr) 770 { 771 unsigned int l = 1; 772 struct line_node *ln; 773 FILE *fp; 774 775 setup_pager(); 776 777 if (lr->function) 778 fprintf(stdout, "<%s:%d>\n", lr->function, 779 lr->start - lr->offset); 780 else 781 fprintf(stdout, "<%s:%d>\n", lr->file, lr->start); 782 783 fp = fopen(lr->path, "r"); 784 if (fp == NULL) 785 die("Failed to open %s: %s", lr->path, strerror(errno)); 786 /* Skip to starting line number */ 787 while (l < lr->start) 788 show_one_line(fp, l++, true, false); 789 790 list_for_each_entry(ln, &lr->line_list, list) { 791 while (ln->line > l) 792 show_one_line(fp, (l++) - lr->offset, false, false); 793 show_one_line(fp, (l++) - lr->offset, false, true); 794 } 795 796 if (lr->end == INT_MAX) 797 lr->end = l + NR_ADDITIONAL_LINES; 798 while (l < lr->end && !feof(fp)) 799 show_one_line(fp, (l++) - lr->offset, false, false); 800 801 fclose(fp); 802 } 803