probe-event.c 18.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*
 * probe-event.c : perf-probe definition to kprobe_events format converter
 *
 * Written by Masami Hiramatsu <mhiramat@redhat.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 */

#define _GNU_SOURCE
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
32 33
#include <stdarg.h>
#include <limits.h>
34 35 36

#undef _GNU_SOURCE
#include "event.h"
37
#include "string.h"
38
#include "strlist.h"
39
#include "debug.h"
40
#include "cache.h"
41
#include "color.h"
42 43 44 45 46 47 48 49 50
#include "parse-events.h"  /* For debugfs_path */
#include "probe-event.h"

#define MAX_CMDLEN 256
#define MAX_PROBE_ARGS 128
#define PERFPROBE_GROUP "probe"

#define semantic_error(msg ...) die("Semantic error :" msg)

51
/* If there is no space to write, returns -E2BIG. */
52 53 54
static int e_snprintf(char *str, size_t size, const char *format, ...)
	__attribute__((format(printf, 3, 4)));

55 56 57 58 59 60 61 62 63 64 65 66
static int e_snprintf(char *str, size_t size, const char *format, ...)
{
	int ret;
	va_list ap;
	va_start(ap, format);
	ret = vsnprintf(str, size, format, ap);
	va_end(ap);
	if (ret >= (int)size)
		ret = -E2BIG;
	return ret;
}

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
void parse_line_range_desc(const char *arg, struct line_range *lr)
{
	const char *ptr;
	char *tmp;
	/*
	 * <Syntax>
	 * SRC:SLN[+NUM|-ELN]
	 * FUNC[:SLN[+NUM|-ELN]]
	 */
	ptr = strchr(arg, ':');
	if (ptr) {
		lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0);
		if (*tmp == '+')
			lr->end = lr->start + (unsigned int)strtoul(tmp + 1,
								    &tmp, 0);
		else if (*tmp == '-')
			lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0);
		else
			lr->end = 0;
		pr_debug("Line range is %u to %u\n", lr->start, lr->end);
		if (lr->end && lr->start > lr->end)
			semantic_error("Start line must be smaller"
				       " than end line.");
		if (*tmp != '\0')
			semantic_error("Tailing with invalid character '%d'.",
				       *tmp);
		tmp = strndup(arg, (ptr - arg));
	} else
		tmp = strdup(arg);

	if (strchr(tmp, '.'))
		lr->file = tmp;
	else
		lr->function = tmp;
}

103 104 105 106 107 108 109 110 111 112 113 114
/* Check the name is good for event/group */
static bool check_event_name(const char *name)
{
	if (!isalpha(*name) && *name != '_')
		return false;
	while (*++name != '\0') {
		if (!isalpha(*name) && !isdigit(*name) && *name != '_')
			return false;
	}
	return true;
}

115 116 117 118 119 120 121
/* Parse probepoint definition. */
static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
{
	char *ptr, *tmp;
	char c, nc = 0;
	/*
	 * <Syntax>
122 123
	 * perf probe [EVENT=]SRC[:LN|;PTN]
	 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
124 125
	 *
	 * TODO:Group name support
126 127
	 */

128 129
	ptr = strpbrk(arg, ";=@+%");
	if (ptr && *ptr == '=') {	/* Event name */
130 131 132 133 134
		*ptr = '\0';
		tmp = ptr + 1;
		ptr = strchr(arg, ':');
		if (ptr)	/* Group name is not supported yet. */
			semantic_error("Group name is not supported yet.");
135 136 137
		if (!check_event_name(arg))
			semantic_error("%s is bad for event name -it must "
				       "follow C symbol-naming rule.", arg);
138 139 140 141
		pp->event = strdup(arg);
		arg = tmp;
	}

142
	ptr = strpbrk(arg, ";:+@%");
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
	if (ptr) {
		nc = *ptr;
		*ptr++ = '\0';
	}

	/* Check arg is function or file and copy it */
	if (strchr(arg, '.'))	/* File */
		pp->file = strdup(arg);
	else			/* Function */
		pp->function = strdup(arg);
	DIE_IF(pp->file == NULL && pp->function == NULL);

	/* Parse other options */
	while (ptr) {
		arg = ptr;
		c = nc;
159 160 161 162 163
		if (c == ';') {	/* Lazy pattern must be the last part */
			pp->lazy_line = strdup(arg);
			break;
		}
		ptr = strpbrk(arg, ";:+@%");
164 165 166 167 168 169 170 171
		if (ptr) {
			nc = *ptr;
			*ptr++ = '\0';
		}
		switch (c) {
		case ':':	/* Line number */
			pp->line = strtoul(arg, &tmp, 0);
			if (*tmp != '\0')
172 173
				semantic_error("There is non-digit char"
					       " in line number.");
174 175 176 177
			break;
		case '+':	/* Byte offset from a symbol */
			pp->offset = strtoul(arg, &tmp, 0);
			if (*tmp != '\0')
178
				semantic_error("There is non-digit character"
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
						" in offset.");
			break;
		case '@':	/* File name */
			if (pp->file)
				semantic_error("SRC@SRC is not allowed.");
			pp->file = strdup(arg);
			DIE_IF(pp->file == NULL);
			break;
		case '%':	/* Probe places */
			if (strcmp(arg, "return") == 0) {
				pp->retprobe = 1;
			} else	/* Others not supported yet */
				semantic_error("%%%s is not supported.", arg);
			break;
		default:
			DIE_IF("Program has a bug.");
			break;
		}
	}

	/* Exclusion check */
200 201 202 203 204 205
	if (pp->lazy_line && pp->line)
		semantic_error("Lazy pattern can't be used with line number.");

	if (pp->lazy_line && pp->offset)
		semantic_error("Lazy pattern can't be used with offset.");

206 207 208
	if (pp->line && pp->offset)
		semantic_error("Offset can't be used with line number.");

209 210 211
	if (!pp->line && !pp->lazy_line && pp->file && !pp->function)
		semantic_error("File always requires line number or "
			       "lazy pattern.");
212 213 214 215 216 217 218

	if (pp->offset && !pp->function)
		semantic_error("Offset requires an entry function.");

	if (pp->retprobe && !pp->function)
		semantic_error("Return probe requires an entry function.");

219 220 221
	if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe)
		semantic_error("Offset/Line/Lazy pattern can't be used with "
			       "return probe.");
222

223 224 225
	pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n",
		 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
		 pp->lazy_line);
226 227 228
}

/* Parse perf-probe event definition */
229 230
void parse_perf_probe_event(const char *str, struct probe_point *pp,
			    bool *need_dwarf)
231
{
232
	char **argv;
233 234 235
	int argc, i;

	*need_dwarf = false;
236

237 238 239 240 241
	argv = argv_split(str, &argc);
	if (!argv)
		die("argv_split failed.");
	if (argc > MAX_PROBE_ARGS + 1)
		semantic_error("Too many arguments");
242 243 244 245

	/* Parse probe point */
	parse_perf_probe_probepoint(argv[0], pp);
	if (pp->file || pp->line)
246
		*need_dwarf = true;
247

248
	/* Copy arguments and ensure return probe has no C argument */
249
	pp->nr_args = argc - 1;
250 251 252 253 254
	pp->args = zalloc(sizeof(char *) * pp->nr_args);
	for (i = 0; i < pp->nr_args; i++) {
		pp->args[i] = strdup(argv[i + 1]);
		if (!pp->args[i])
			die("Failed to copy argument.");
255 256 257 258
		if (is_c_varname(pp->args[i])) {
			if (pp->retprobe)
				semantic_error("You can't specify local"
						" 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 270 271 272 273 274 275 276 277 278 279 280 281
{
	char pr;
	char *p;
	int ret, i, argc;
	char **argv;

	pr_debug("Parsing kprobe_events: %s\n", str);
	argv = argv_split(str, &argc);
	if (!argv)
		die("argv_split failed.");
	if (argc < 2)
		semantic_error("Too less arguments.");

	/* Scan event and group name. */
282
	ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
283 284
		     &pr, (float *)(void *)&pp->group,
		     (float *)(void *)&pp->event);
285 286
	if (ret != 3)
		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 290 291

	pp->retprobe = (pr == 'r');

	/* Scan function name and offset */
292 293
	ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function,
		     &pp->offset);
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
	if (ret == 1)
		pp->offset = 0;

	/* kprobe_events doesn't have this information */
	pp->line = 0;
	pp->file = NULL;

	pp->nr_args = argc - 2;
	pp->args = zalloc(sizeof(char *) * pp->nr_args);
	for (i = 0; i < pp->nr_args; i++) {
		p = strchr(argv[i + 2], '=');
		if (p)	/* We don't need which register is assigned. */
			*p = '\0';
		pp->args[i] = strdup(argv[i + 2]);
		if (!pp->args[i])
			die("Failed to copy argument.");
	}

	argv_free(argv);
}

315 316
/* Synthesize only probe point (not argument) */
int synthesize_perf_probe_point(struct probe_point *pp)
317 318 319
{
	char *buf;
	char offs[64] = "", line[64] = "";
320
	int ret;
321 322

	pp->probes[0] = buf = zalloc(MAX_CMDLEN);
323
	pp->found = 1;
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
	if (!buf)
		die("Failed to allocate memory by zalloc.");
	if (pp->offset) {
		ret = e_snprintf(offs, 64, "+%d", pp->offset);
		if (ret <= 0)
			goto error;
	}
	if (pp->line) {
		ret = e_snprintf(line, 64, ":%d", pp->line);
		if (ret <= 0)
			goto error;
	}

	if (pp->function)
		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function,
				 offs, pp->retprobe ? "%return" : "", line);
	else
341
		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line);
342 343 344 345
	if (ret <= 0) {
error:
		free(pp->probes[0]);
		pp->probes[0] = NULL;
346
		pp->found = 0;
347 348 349 350 351 352 353 354 355 356 357 358
	}
	return ret;
}

int synthesize_perf_probe_event(struct probe_point *pp)
{
	char *buf;
	int i, len, ret;

	len = synthesize_perf_probe_point(pp);
	if (len < 0)
		return 0;
359

360
	buf = pp->probes[0];
361 362 363 364 365 366 367 368 369 370 371 372
	for (i = 0; i < pp->nr_args; i++) {
		ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
				 pp->args[i]);
		if (ret <= 0)
			goto error;
		len += ret;
	}
	pp->found = 1;

	return pp->found;
error:
	free(pp->probes[0]);
373
	pp->probes[0] = NULL;
374 375 376 377

	return ret;
}

378 379 380 381 382 383 384 385
int synthesize_trace_kprobe_event(struct probe_point *pp)
{
	char *buf;
	int i, len, ret;

	pp->probes[0] = buf = zalloc(MAX_CMDLEN);
	if (!buf)
		die("Failed to allocate memory by zalloc.");
386 387
	ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
	if (ret <= 0)
388 389 390 391
		goto error;
	len = ret;

	for (i = 0; i < pp->nr_args; i++) {
392 393 394
		ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
				 pp->args[i]);
		if (ret <= 0)
395 396 397 398 399 400 401 402
			goto error;
		len += ret;
	}
	pp->found = 1;

	return pp->found;
error:
	free(pp->probes[0]);
403
	pp->probes[0] = NULL;
404 405 406 407

	return ret;
}

408 409 410 411 412 413 414 415 416 417 418 419 420
static int open_kprobe_events(int flags, int mode)
{
	char buf[PATH_MAX];
	int ret;

	ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path);
	if (ret < 0)
		die("Failed to make kprobe_events path.");

	ret = open(buf, flags, mode);
	if (ret < 0) {
		if (errno == ENOENT)
			die("kprobe_events file does not exist -"
421
			    " please rebuild with CONFIG_KPROBE_EVENT.");
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
		else
			die("Could not open kprobe_events file: %s",
			    strerror(errno));
	}
	return ret;
}

/* Get raw string list of current kprobe_events */
static struct strlist *get_trace_kprobe_event_rawlist(int fd)
{
	int ret, idx;
	FILE *fp;
	char buf[MAX_CMDLEN];
	char *p;
	struct strlist *sl;

	sl = strlist__new(true, NULL);

	fp = fdopen(dup(fd), "r");
	while (!feof(fp)) {
		p = fgets(buf, MAX_CMDLEN, fp);
		if (!p)
			break;

		idx = strlen(p) - 1;
		if (p[idx] == '\n')
			p[idx] = '\0';
		ret = strlist__add(sl, buf);
		if (ret < 0)
			die("strlist__add failed: %s", strerror(-ret));
	}
	fclose(fp);

	return sl;
}

/* Free and zero clear probe_point */
static void clear_probe_point(struct probe_point *pp)
{
	int i;

463 464 465 466
	if (pp->event)
		free(pp->event);
	if (pp->group)
		free(pp->group);
467 468 469 470
	if (pp->function)
		free(pp->function);
	if (pp->file)
		free(pp->file);
471 472
	if (pp->lazy_line)
		free(pp->lazy_line);
473 474 475 476 477 478
	for (i = 0; i < pp->nr_args; i++)
		free(pp->args[i]);
	if (pp->args)
		free(pp->args);
	for (i = 0; i < pp->found; i++)
		free(pp->probes[i]);
479
	memset(pp, 0, sizeof(*pp));
480 481
}

482
/* Show an event */
483 484
static void show_perf_probe_event(const char *event, const char *place,
				  struct probe_point *pp)
485
{
486
	int i, ret;
487 488
	char buf[128];

489
	ret = e_snprintf(buf, 128, "%s:%s", pp->group, event);
490 491
	if (ret < 0)
		die("Failed to copy event: %s", strerror(-ret));
492 493 494 495 496 497 498 499 500 501
	printf("  %-40s (on %s", buf, place);

	if (pp->nr_args > 0) {
		printf(" with");
		for (i = 0; i < pp->nr_args; i++)
			printf(" %s", pp->args[i]);
	}
	printf(")\n");
}

502 503 504
/* List up current perf-probe events */
void show_perf_probe_events(void)
{
505
	int fd;
506 507 508 509
	struct probe_point pp;
	struct strlist *rawlist;
	struct str_node *ent;

510
	setup_pager();
511
	memset(&pp, 0, sizeof(pp));
512

513 514 515 516
	fd = open_kprobe_events(O_RDONLY, 0);
	rawlist = get_trace_kprobe_event_rawlist(fd);
	close(fd);

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 524 525 526 527 528
		clear_probe_point(&pp);
	}

	strlist__delete(rawlist);
}

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 534
	struct strlist *sl, *rawlist;
	struct str_node *ent;
535
	struct probe_point pp;
536

537
	memset(&pp, 0, sizeof(pp));
538 539
	rawlist = get_trace_kprobe_event_rawlist(fd);

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 545
			if (e_snprintf(buf, 128, "%s:%s", pp.group,
				       pp.event) < 0)
546 547 548
				die("Failed to copy group:event name.");
			strlist__add(sl, buf);
		} else
549 550
			strlist__add(sl, pp.event);
		clear_probe_point(&pp);
551 552 553 554 555 556 557
	}

	strlist__delete(rawlist);

	return sl;
}

558
static void write_trace_kprobe_event(int fd, const char *buf)
559 560 561
{
	int ret;

562
	pr_debug("Writing event: %s\n", buf);
563 564
	ret = write(fd, buf, strlen(buf));
	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 574 575 576 577 578 579

	/* Try no suffix */
	ret = e_snprintf(buf, len, "%s", base);
	if (ret < 0)
		die("snprintf() failed: %s", strerror(-ret));
	if (!strlist__has_entry(namelist, buf))
		return;

580 581 582 583 584 585
	if (!allow_suffix) {
		pr_warning("Error: event \"%s\" already exists. "
			   "(Use -f to force duplicates.)\n", base);
		die("Can't add new event.");
	}

586 587
	/* Try to add suffix */
	for (i = 1; i < MAX_EVENT_INDEX; i++) {
588 589 590 591 592 593 594 595 596 597
		ret = e_snprintf(buf, len, "%s_%d", base, i);
		if (ret < 0)
			die("snprintf() failed: %s", strerror(-ret));
		if (!strlist__has_entry(namelist, buf))
			break;
	}
	if (i == MAX_EVENT_INDEX)
		die("Too many events are on the same function.");
}

598 599
void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
			     bool force_add)
600 601 602 603
{
	int i, j, fd;
	struct probe_point *pp;
	char buf[MAX_CMDLEN];
604 605
	char event[64];
	struct strlist *namelist;
606
	bool allow_suffix;
607

608 609
	fd = open_kprobe_events(O_RDWR, O_APPEND);
	/* Get current event names */
610
	namelist = get_perf_event_names(fd, false);
611 612 613

	for (j = 0; j < nr_probes; j++) {
		pp = probes + j;
614 615 616 617 618
		if (!pp->event)
			pp->event = strdup(pp->function);
		if (!pp->group)
			pp->group = strdup(PERFPROBE_GROUP);
		DIE_IF(!pp->event || !pp->group);
619 620
		/* If force_add is true, suffix search is allowed */
		allow_suffix = force_add;
621 622
		for (i = 0; i < pp->found; i++) {
			/* Get an unused new event name */
623 624
			get_new_event_name(event, 64, pp->event, namelist,
					   allow_suffix);
625 626
			snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n",
				 pp->retprobe ? 'r' : 'p',
627
				 pp->group, event,
628
				 pp->probes[i]);
629
			write_trace_kprobe_event(fd, buf);
630 631 632
			printf("Added new event:\n");
			/* Get the first parameter (probe-point) */
			sscanf(pp->probes[i], "%s", buf);
633
			show_perf_probe_event(event, buf, pp);
634 635
			/* Add added event name to namelist */
			strlist__add(namelist, event);
636 637 638 639 640 641 642
			/*
			 * Probes after the first probe which comes from same
			 * user input are always allowed to add suffix, because
			 * there might be several addresses corresponding to
			 * one code line.
			 */
			allow_suffix = true;
643
		}
644
	}
645 646 647 648
	/* Show how to use the event. */
	printf("\nYou can now use it on all perf tools, such as:\n\n");
	printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event);

649
	strlist__delete(namelist);
650 651
	close(fd);
}
652

653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
static void __del_trace_kprobe_event(int fd, struct str_node *ent)
{
	char *p;
	char buf[128];

	/* Convert from perf-probe event to trace-kprobe event */
	if (e_snprintf(buf, 128, "-:%s", ent->s) < 0)
		die("Failed to copy event.");
	p = strchr(buf + 2, ':');
	if (!p)
		die("Internal error: %s should have ':' but not.", ent->s);
	*p = '/';

	write_trace_kprobe_event(fd, buf);
	printf("Remove event: %s\n", ent->s);
}

670 671 672 673
static void del_trace_kprobe_event(int fd, const char *group,
				   const char *event, struct strlist *namelist)
{
	char buf[128];
674 675
	struct str_node *ent, *n;
	int found = 0;
676 677 678 679

	if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
		die("Failed to copy event.");

680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
	if (strpbrk(buf, "*?")) { /* Glob-exp */
		strlist__for_each_safe(ent, n, namelist)
			if (strglobmatch(ent->s, buf)) {
				found++;
				__del_trace_kprobe_event(fd, ent);
				strlist__remove(namelist, ent);
			}
	} else {
		ent = strlist__find(namelist, buf);
		if (ent) {
			found++;
			__del_trace_kprobe_event(fd, ent);
			strlist__remove(namelist, ent);
		}
	}
	if (found == 0)
		pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
697 698 699 700 701 702 703 704 705 706 707 708 709 710
}

void del_trace_kprobe_events(struct strlist *dellist)
{
	int fd;
	const char *group, *event;
	char *p, *str;
	struct str_node *ent;
	struct strlist *namelist;

	fd = open_kprobe_events(O_RDWR, O_APPEND);
	/* Get current event names */
	namelist = get_perf_event_names(fd, true);

711
	strlist__for_each(ent, dellist) {
712 713 714
		str = strdup(ent->s);
		if (!str)
			die("Failed to copy event.");
715
		pr_debug("Parsing: %s\n", str);
716 717 718 719 720 721
		p = strchr(str, ':');
		if (p) {
			group = str;
			*p = '\0';
			event = p + 1;
		} else {
722
			group = "*";
723 724
			event = str;
		}
725
		pr_debug("Group: %s, Event: %s\n", group, event);
726 727 728 729 730 731 732
		del_trace_kprobe_event(fd, group, event, namelist);
		free(str);
	}
	strlist__delete(namelist);
	close(fd);
}

733
#define LINEBUF_SIZE 256
734
#define NR_ADDITIONAL_LINES 2
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794

static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
{
	char buf[LINEBUF_SIZE];
	const char *color = PERF_COLOR_BLUE;

	if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
		goto error;
	if (!skip) {
		if (show_num)
			fprintf(stdout, "%7u  %s", l, buf);
		else
			color_fprintf(stdout, color, "         %s", buf);
	}

	while (strlen(buf) == LINEBUF_SIZE - 1 &&
	       buf[LINEBUF_SIZE - 2] != '\n') {
		if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
			goto error;
		if (!skip) {
			if (show_num)
				fprintf(stdout, "%s", buf);
			else
				color_fprintf(stdout, color, "%s", buf);
		}
	}
	return;
error:
	if (feof(fp))
		die("Source file is shorter than expected.");
	else
		die("File read error: %s", strerror(errno));
}

void show_line_range(struct line_range *lr)
{
	unsigned int l = 1;
	struct line_node *ln;
	FILE *fp;

	setup_pager();

	if (lr->function)
		fprintf(stdout, "<%s:%d>\n", lr->function,
			lr->start - lr->offset);
	else
		fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);

	fp = fopen(lr->path, "r");
	if (fp == NULL)
		die("Failed to open %s: %s", lr->path, strerror(errno));
	/* Skip to starting line number */
	while (l < lr->start)
		show_one_line(fp, l++, true, false);

	list_for_each_entry(ln, &lr->line_list, list) {
		while (ln->line > l)
			show_one_line(fp, (l++) - lr->offset, false, false);
		show_one_line(fp, (l++) - lr->offset, false, true);
	}
795 796 797 798 799 800

	if (lr->end == INT_MAX)
		lr->end = l + NR_ADDITIONAL_LINES;
	while (l < lr->end && !feof(fp))
		show_one_line(fp, (l++) - lr->offset, false, false);

801 802
	fclose(fp);
}