builtin-probe.c 10.3 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 32 33 34 35 36 37
/*
 * builtin-probe.c
 *
 * Builtin probe command: Set up probe events by C expression
 *
 * 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>

#undef _GNU_SOURCE
#include "perf.h"
#include "builtin.h"
#include "util/util.h"
38 39
#include "util/event.h"
#include "util/debug.h"
40 41 42 43 44 45 46 47 48 49 50 51 52 53
#include "util/parse-options.h"
#include "util/parse-events.h"	/* For debugfs_path */
#include "util/probe-finder.h"

/* Default vmlinux search paths */
#define NR_SEARCH_PATH 3
const char *default_search_path[NR_SEARCH_PATH] = {
"/lib/modules/%s/build/vmlinux",		/* Custom build kernel */
"/usr/lib/debug/lib/modules/%s/vmlinux",	/* Red Hat debuginfo */
"/boot/vmlinux-debug-%s",			/* Ubuntu */
};

#define MAX_PATH_LEN 256
#define MAX_PROBES 128
54
#define MAX_PROBE_ARGS 128
55
#define PERFPROBE_GROUP "perfprobe"
56 57 58 59 60

/* Session management structure */
static struct {
	char *vmlinux;
	char *release;
61
	int need_dwarf;
62 63 64 65
	int nr_probe;
	struct probe_point probes[MAX_PROBES];
} session;

66
#define semantic_error(msg ...) die("Semantic error :" msg)
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 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
/* Parse probe point. Return 1 if return probe */
static void parse_probe_point(char *arg, struct probe_point *pp)
{
	char *ptr, *tmp;
	char c, nc;
	/*
	 * <Syntax>
	 * perf probe SRC:LN
	 * perf probe FUNC[+OFFS|%return][@SRC]
	 */

	ptr = strpbrk(arg, ":+@%");
	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;
		ptr = strpbrk(arg, ":+@%");
		if (ptr) {
			nc = *ptr;
			*ptr++ = '\0';
		}
		switch (c) {
		case ':':	/* Line number */
			pp->line = strtoul(arg, &tmp, 0);
			if (*tmp != '\0')
				semantic_error("There is non-digit charactor"
						" in line number.");
			break;
		case '+':	/* Byte offset from a symbol */
			pp->offset = strtoul(arg, &tmp, 0);
			if (*tmp != '\0')
				semantic_error("There is non-digit charactor"
						" 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);
			if (ptr)
				semantic_error("@SRC must be the last "
					       "option.");
			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 */
	if (pp->line && pp->function)
		semantic_error("Function-relative line number is not"
				" supported yet.");
	if (!pp->line && pp->file && !pp->function)
		semantic_error("File always requires line number.");
	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.");
	if (pp->offset && pp->retprobe)
		semantic_error("Offset can't be used with return probe.");

	pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n",
		 pp->function, pp->file, pp->line, pp->offset, pp->retprobe);
}

/* Parse an event definition. Note that any error must die. */
static void parse_probe_event(const char *str)
154 155 156 157 158
{
	char *argv[MAX_PROBE_ARGS + 2];	/* Event + probe + args */
	int argc, i;
	struct probe_point *pp = &session.probes[session.nr_probe];

159
	pr_debug("probe-definition(%d): %s\n", session.nr_probe, str);
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
	if (++session.nr_probe == MAX_PROBES)
		semantic_error("Too many probes");

	/* Separate arguments, similar to argv_split */
	argc = 0;
	do {
		/* Skip separators */
		while (isspace(*str))
			str++;

		/* Add an argument */
		if (*str != '\0') {
			const char *s = str;

			/* Skip the argument */
			while (!isspace(*str) && *str != '\0')
				str++;

			/* Duplicate the argument */
			argv[argc] = strndup(s, str - s);
			if (argv[argc] == NULL)
181
				die("strndup");
182 183
			if (++argc == MAX_PROBE_ARGS)
				semantic_error("Too many arguments");
184
			pr_debug("argv[%d]=%s\n", argc, argv[argc - 1]);
185 186
		}
	} while (*str != '\0');
187 188
	if (!argc)
		semantic_error("An empty argument.");
189 190

	/* Parse probe point */
191 192
	parse_probe_point(argv[0], pp);
	free(argv[0]);
193 194
	if (pp->file)
		session.need_dwarf = 1;
195 196

	/* Copy arguments */
197
	pp->nr_args = argc - 1;
198 199 200
	if (pp->nr_args > 0) {
		pp->args = (char **)malloc(sizeof(char *) * pp->nr_args);
		if (!pp->args)
201
			die("malloc");
202
		memcpy(pp->args, &argv[1], sizeof(char *) * pp->nr_args);
203 204 205
	}

	/* Ensure return probe has no C argument */
206 207
	for (i = 0; i < pp->nr_args; i++)
		if (is_c_varname(pp->args[i])) {
208
			if (pp->retprobe)
209 210
				semantic_error("You can't specify local"
						" variable for kretprobe");
211 212 213
			session.need_dwarf = 1;
		}

214
	pr_debug("%d arguments\n", pp->nr_args);
215 216
}

217
static int opt_add_probe_event(const struct option *opt __used,
218 219 220
			      const char *str, int unset __used)
{
	if (str)
221
		parse_probe_event(str);
222 223 224
	return 0;
}

225
#ifndef NO_LIBDWARF
226 227 228 229 230 231 232 233
static int open_default_vmlinux(void)
{
	struct utsname uts;
	char fname[MAX_PATH_LEN];
	int fd, ret, i;

	ret = uname(&uts);
	if (ret) {
234
		pr_debug("uname() failed.\n");
235 236 237 238 239 240 241
		return -errno;
	}
	session.release = uts.release;
	for (i = 0; i < NR_SEARCH_PATH; i++) {
		ret = snprintf(fname, MAX_PATH_LEN,
			       default_search_path[i], session.release);
		if (ret >= MAX_PATH_LEN || ret < 0) {
242
			pr_debug("Filename(%d,%s) is too long.\n", i,
243
				uts.release);
244 245 246
			errno = E2BIG;
			return -E2BIG;
		}
247
		pr_debug("try to open %s\n", fname);
248 249 250 251 252 253
		fd = open(fname, O_RDONLY);
		if (fd >= 0)
			break;
	}
	return fd;
}
254
#endif
255 256

static const char * const probe_usage[] = {
257 258
	"perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
	"perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
259 260 261 262
	NULL
};

static const struct option options[] = {
263 264
	OPT_BOOLEAN('v', "verbose", &verbose,
		    "be more verbose (show parsed arguments, etc)"),
265
#ifndef NO_LIBDWARF
266 267
	OPT_STRING('k', "vmlinux", &session.vmlinux, "file",
		"vmlinux/module pathname"),
268
#endif
269
	OPT_CALLBACK('a', "add", NULL,
270
#ifdef NO_LIBDWARF
271
		"FUNC[+OFFS|%return] [ARG ...]",
272
#else
273
		"FUNC[+OFFS|%return][@SRC]|SRC:LINE [ARG ...]",
274
#endif
275 276 277 278 279
		"probe point definition, where\n"
		"\t\tGRP:\tGroup name (optional)\n"
		"\t\tNAME:\tEvent name\n"
		"\t\tFUNC:\tFunction name\n"
		"\t\tOFFS:\tOffset from function entry (in byte)\n"
280
		"\t\t%return:\tPut the probe at function return\n"
281 282 283
#ifdef NO_LIBDWARF
		"\t\tARG:\tProbe argument (only \n"
#else
284 285 286
		"\t\tSRC:\tSource code path\n"
		"\t\tLINE:\tLine number\n"
		"\t\tARG:\tProbe argument (local variable name or\n"
287
#endif
288
		"\t\t\tkprobe-tracer argument format is supported.)\n",
289
		opt_add_probe_event),
290 291 292 293 294 295 296 297 298 299
	OPT_END()
};

static int write_new_event(int fd, const char *buf)
{
	int ret;

	printf("Adding new event: %s\n", buf);
	ret = write(fd, buf, strlen(buf));
	if (ret <= 0)
300
		die("failed to create event.");
301 302 303 304 305 306

	return ret;
}

#define MAX_CMDLEN 256

307
static int synthesize_probe_event(struct probe_point *pp)
308 309 310 311 312
{
	char *buf;
	int i, len, ret;
	pp->probes[0] = buf = (char *)calloc(MAX_CMDLEN, sizeof(char));
	if (!buf)
313
		die("calloc");
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
	ret = snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset);
	if (ret <= 0 || ret >= MAX_CMDLEN)
		goto error;
	len = ret;

	for (i = 0; i < pp->nr_args; i++) {
		ret = snprintf(&buf[len], MAX_CMDLEN - len, " %s",
			       pp->args[i]);
		if (ret <= 0 || ret >= MAX_CMDLEN - len)
			goto error;
		len += ret;
	}
	pp->found = 1;
	return pp->found;
error:
	free(pp->probes[0]);
	if (ret > 0)
		ret = -E2BIG;
	return ret;
}

int cmd_probe(int argc, const char **argv, const char *prefix __used)
{
337
	int i, j, fd, ret;
338 339 340 341
	struct probe_point *pp;
	char buf[MAX_CMDLEN];

	argc = parse_options(argc, argv, options, probe_usage,
342 343 344 345 346
			     PARSE_OPT_STOP_AT_NON_OPTION);
	for (i = 0; i < argc; i++)
		parse_probe_event(argv[i]);

	if (session.nr_probe == 0)
347 348
		usage_with_options(probe_usage, options);

349 350 351 352 353 354
#ifdef NO_LIBDWARF
	if (session.need_dwarf)
		semantic_error("Dwarf-analysis is not supported");
#endif

	/* Synthesize probes without dwarf */
355
	for (j = 0; j < session.nr_probe; j++) {
356
#ifndef NO_LIBDWARF
357
		if (!session.probes[j].retprobe) {
358
			session.need_dwarf = 1;
359 360
			continue;
		}
361
#endif
362
		ret = synthesize_probe_event(&session.probes[j]);
363 364
		if (ret == -E2BIG)
			semantic_error("probe point is too long.");
365 366
		else if (ret < 0)
			die("snprintf");
367 368
	}

369 370
#ifndef NO_LIBDWARF
	if (!session.need_dwarf)
371 372 373 374 375 376
		goto setup_probes;

	if (session.vmlinux)
		fd = open(session.vmlinux, O_RDONLY);
	else
		fd = open_default_vmlinux();
377 378
	if (fd < 0)
		die("vmlinux/module file open");
379 380 381 382 383 384 385 386 387

	/* Searching probe points */
	for (j = 0; j < session.nr_probe; j++) {
		pp = &session.probes[j];
		if (pp->found)
			continue;

		lseek(fd, SEEK_SET, 0);
		ret = find_probepoint(fd, pp);
388 389
		if (ret <= 0)
			die("No probe point found.\n");
390 391 392 393
	}
	close(fd);

setup_probes:
394 395
#endif /* !NO_LIBDWARF */

396 397 398
	/* Settng up probe points */
	snprintf(buf, MAX_CMDLEN, "%s/../kprobe_events", debugfs_path);
	fd = open(buf, O_WRONLY, O_APPEND);
399 400
	if (fd < 0)
		die("kprobe_events open");
401 402 403
	for (j = 0; j < session.nr_probe; j++) {
		pp = &session.probes[j];
		if (pp->found == 1) {
404 405 406
			snprintf(buf, MAX_CMDLEN, "%c:%s/%s_%x %s\n",
				pp->retprobe ? 'r' : 'p', PERFPROBE_GROUP,
				pp->function, pp->offset, pp->probes[0]);
407 408 409
			write_new_event(fd, buf);
		} else
			for (i = 0; i < pp->found; i++) {
410 411 412 413 414
				snprintf(buf, MAX_CMDLEN, "%c:%s/%s_%x_%d %s\n",
					pp->retprobe ? 'r' : 'p',
					PERFPROBE_GROUP,
					pp->function, pp->offset, i,
					pp->probes[0]);
415 416 417 418 419 420 421
				write_new_event(fd, buf);
			}
	}
	close(fd);
	return 0;
}