Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 21dd9ae5 authored by Franck Bui-Huu's avatar Franck Bui-Huu Committed by Arnaldo Carvalho de Melo
Browse files

perf probe: Handle gracefully some stupid and buggy line syntaxes



Currently perf probe doesn't handle those incorrect syntaxes:

   $ perf probe -L sched.c:++13
   $ perf probe -L sched.c:-+13
   $ perf probe -L sched.c:10000000000000000000000000000+13

This patches rewrites parse_line_range_desc() to handle them.

As a bonus, it reports more useful error messages instead of: "Tailing
with invalid character...".

Acked-by: default avatarMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
LKML-Reference: <1292854685-8230-7-git-send-email-fbuihuu@gmail.com>
Signed-off-by: default avatarFranck Bui-Huu <fbuihuu@gmail.com>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent fde52dbd
Loading
Loading
Loading
Loading
+60 −32
Original line number Original line Diff line number Diff line
@@ -529,6 +529,19 @@ int show_available_vars(struct perf_probe_event *pevs __unused,
}
}
#endif
#endif


static int parse_line_num(char **ptr, int *val, const char *what)
{
	const char *start = *ptr;

	errno = 0;
	*val = strtol(*ptr, ptr, 0);
	if (errno || *ptr == start) {
		semantic_error("'%s' is not a valid number.\n", what);
		return -EINVAL;
	}
	return 0;
}

/*
/*
 * Stuff 'lr' according to the line range described by 'arg'.
 * Stuff 'lr' according to the line range described by 'arg'.
 * The line range syntax is described by:
 * The line range syntax is described by:
@@ -538,50 +551,65 @@ int show_available_vars(struct perf_probe_event *pevs __unused,
 */
 */
int parse_line_range_desc(const char *arg, struct line_range *lr)
int parse_line_range_desc(const char *arg, struct line_range *lr)
{
{
	const char *ptr;
	char *range, *name = strdup(arg);
	char *tmp;
	int err;


	ptr = strchr(arg, ':');
	if (!name)
	if (ptr) {
		return -ENOMEM;
		lr->start = (int)strtoul(ptr + 1, &tmp, 0);

		if (*tmp == '+') {
	lr->start = 0;
			lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0);
	lr->end = INT_MAX;
			lr->end--;	/*

	range = strchr(name, ':');
	if (range) {
		*range++ = '\0';

		err = parse_line_num(&range, &lr->start, "start line");
		if (err)
			goto err;

		if (*range == '+' || *range == '-') {
			const char c = *range++;

			err = parse_line_num(&range, &lr->end, "end line");
			if (err)
				goto err;

			if (c == '+') {
				lr->end += lr->start;
				/*
				 * Adjust the number of lines here.
				 * Adjust the number of lines here.
				 * If the number of lines == 1, the
				 * If the number of lines == 1, the
				 * the end of line should be equal to
				 * the end of line should be equal to
				 * the start of line.
				 * the start of line.
				 */
				 */
		} else if (*tmp == '-')
				lr->end--;
			lr->end = (int)strtoul(tmp + 1, &tmp, 0);
			}
		else
		}
			lr->end = INT_MAX;

		pr_debug("Line range is %d to %d\n", lr->start, lr->end);
		pr_debug("Line range is %d to %d\n", lr->start, lr->end);

		err = -EINVAL;
		if (lr->start > lr->end) {
		if (lr->start > lr->end) {
			semantic_error("Start line must be smaller"
			semantic_error("Start line must be smaller"
				       " than end line.\n");
				       " than end line.\n");
			return -EINVAL;
			goto err;
		}
		}
		if (*tmp != '\0') {
		if (*range != '\0') {
			semantic_error("Tailing with invalid character '%d'.\n",
			semantic_error("Tailing with invalid str '%s'.\n", range);
				       *tmp);
			goto err;
			return -EINVAL;
		}
		}
		tmp = strndup(arg, (ptr - arg));
	} else {
		tmp = strdup(arg);
		lr->end = INT_MAX;
	}
	}


	if (tmp == NULL)
	if (strchr(name, '.'))
		return -ENOMEM;
		lr->file = name;

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


	return 0;
	return 0;
err:
	free(name);
	return err;
}
}


/* Check the name is good for event/group */
/* Check the name is good for event/group */