mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	tracing/probes: Add $arg* meta argument for all function args
Add the '$arg*' meta fetch argument for function-entry probe events. This will be expanded to the all arguments of the function and the tracepoint using BTF function argument information. e.g. # echo 'p vfs_read $arg*' >> dynamic_events # echo 'f vfs_write $arg*' >> dynamic_events # echo 't sched_overutilized_tp $arg*' >> dynamic_events # cat dynamic_events p:kprobes/p_vfs_read_0 vfs_read file=file buf=buf count=count pos=pos f:fprobes/vfs_write__entry vfs_write file=file buf=buf count=count pos=pos t:tracepoints/sched_overutilized_tp sched_overutilized_tp rd=rd overutilized=overutilized Also, single '$arg[0-9]*' will be converted to the BTF function argument. NOTE: This seems like a wildcard, but a fake one at this moment. This is just for telling user that this can be expanded to several arguments. And it is not like other $-vars, you can not use this $arg* as a part of fetch args, e.g. specifying name "foo=$arg*" and using it in dereferences "+0($arg*)" will lead a parse error. Link: https://lore.kernel.org/all/168507475126.913472.18329684401466211816.stgit@mhiramat.roam.corp.google.com/ Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
This commit is contained in:
		
							parent
							
								
									b576e09701
								
							
						
					
					
						commit
						18b1e870a4
					
				
					 4 changed files with 212 additions and 12 deletions
				
			
		| 
						 | 
					@ -925,14 +925,16 @@ static int __trace_fprobe_create(int argc, const char *argv[])
 | 
				
			||||||
	 *  FETCHARG:TYPE : use TYPE instead of unsigned long.
 | 
						 *  FETCHARG:TYPE : use TYPE instead of unsigned long.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	struct trace_fprobe *tf = NULL;
 | 
						struct trace_fprobe *tf = NULL;
 | 
				
			||||||
	int i, len, ret = 0;
 | 
						int i, len, new_argc = 0, ret = 0;
 | 
				
			||||||
	bool is_return = false;
 | 
						bool is_return = false;
 | 
				
			||||||
	char *symbol = NULL, *tmp = NULL;
 | 
						char *symbol = NULL, *tmp = NULL;
 | 
				
			||||||
	const char *event = NULL, *group = FPROBE_EVENT_SYSTEM;
 | 
						const char *event = NULL, *group = FPROBE_EVENT_SYSTEM;
 | 
				
			||||||
 | 
						const char **new_argv = NULL;
 | 
				
			||||||
	int maxactive = 0;
 | 
						int maxactive = 0;
 | 
				
			||||||
	char buf[MAX_EVENT_NAME_LEN];
 | 
						char buf[MAX_EVENT_NAME_LEN];
 | 
				
			||||||
	char gbuf[MAX_EVENT_NAME_LEN];
 | 
						char gbuf[MAX_EVENT_NAME_LEN];
 | 
				
			||||||
	char sbuf[KSYM_NAME_LEN];
 | 
						char sbuf[KSYM_NAME_LEN];
 | 
				
			||||||
 | 
						char abuf[MAX_BTF_ARGS_LEN];
 | 
				
			||||||
	bool is_tracepoint = false;
 | 
						bool is_tracepoint = false;
 | 
				
			||||||
	struct tracepoint *tpoint = NULL;
 | 
						struct tracepoint *tpoint = NULL;
 | 
				
			||||||
	struct traceprobe_parse_context ctx = {
 | 
						struct traceprobe_parse_context ctx = {
 | 
				
			||||||
| 
						 | 
					@ -1040,9 +1042,22 @@ static int __trace_fprobe_create(int argc, const char *argv[])
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		ctx.funcname = symbol;
 | 
							ctx.funcname = symbol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						argc -= 2; argv += 2;
 | 
				
			||||||
 | 
						new_argv = traceprobe_expand_meta_args(argc, argv, &new_argc,
 | 
				
			||||||
 | 
										       abuf, MAX_BTF_ARGS_LEN, &ctx);
 | 
				
			||||||
 | 
						if (IS_ERR(new_argv)) {
 | 
				
			||||||
 | 
							ret = PTR_ERR(new_argv);
 | 
				
			||||||
 | 
							new_argv = NULL;
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (new_argv) {
 | 
				
			||||||
 | 
							argc = new_argc;
 | 
				
			||||||
 | 
							argv = new_argv;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* setup a probe */
 | 
						/* setup a probe */
 | 
				
			||||||
	tf = alloc_trace_fprobe(group, event, symbol, tpoint, maxactive,
 | 
						tf = alloc_trace_fprobe(group, event, symbol, tpoint, maxactive,
 | 
				
			||||||
				argc - 2, is_return);
 | 
									argc, is_return);
 | 
				
			||||||
	if (IS_ERR(tf)) {
 | 
						if (IS_ERR(tf)) {
 | 
				
			||||||
		ret = PTR_ERR(tf);
 | 
							ret = PTR_ERR(tf);
 | 
				
			||||||
		/* This must return -ENOMEM, else there is a bug */
 | 
							/* This must return -ENOMEM, else there is a bug */
 | 
				
			||||||
| 
						 | 
					@ -1054,7 +1069,6 @@ static int __trace_fprobe_create(int argc, const char *argv[])
 | 
				
			||||||
		tf->mod = __module_text_address(
 | 
							tf->mod = __module_text_address(
 | 
				
			||||||
				(unsigned long)tf->tpoint->probestub);
 | 
									(unsigned long)tf->tpoint->probestub);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	argc -= 2; argv += 2;
 | 
					 | 
				
			||||||
	/* parse arguments */
 | 
						/* parse arguments */
 | 
				
			||||||
	for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
 | 
						for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
 | 
				
			||||||
		trace_probe_log_set_index(i + 2);
 | 
							trace_probe_log_set_index(i + 2);
 | 
				
			||||||
| 
						 | 
					@ -1083,6 +1097,7 @@ static int __trace_fprobe_create(int argc, const char *argv[])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	trace_probe_log_clear();
 | 
						trace_probe_log_clear();
 | 
				
			||||||
 | 
						kfree(new_argv);
 | 
				
			||||||
	kfree(symbol);
 | 
						kfree(symbol);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -732,9 +732,10 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 | 
				
			||||||
	 *  FETCHARG:TYPE : use TYPE instead of unsigned long.
 | 
						 *  FETCHARG:TYPE : use TYPE instead of unsigned long.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	struct trace_kprobe *tk = NULL;
 | 
						struct trace_kprobe *tk = NULL;
 | 
				
			||||||
	int i, len, ret = 0;
 | 
						int i, len, new_argc = 0, ret = 0;
 | 
				
			||||||
	bool is_return = false;
 | 
						bool is_return = false;
 | 
				
			||||||
	char *symbol = NULL, *tmp = NULL;
 | 
						char *symbol = NULL, *tmp = NULL;
 | 
				
			||||||
 | 
						const char **new_argv = NULL;
 | 
				
			||||||
	const char *event = NULL, *group = KPROBE_EVENT_SYSTEM;
 | 
						const char *event = NULL, *group = KPROBE_EVENT_SYSTEM;
 | 
				
			||||||
	enum probe_print_type ptype;
 | 
						enum probe_print_type ptype;
 | 
				
			||||||
	int maxactive = 0;
 | 
						int maxactive = 0;
 | 
				
			||||||
| 
						 | 
					@ -742,6 +743,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 | 
				
			||||||
	void *addr = NULL;
 | 
						void *addr = NULL;
 | 
				
			||||||
	char buf[MAX_EVENT_NAME_LEN];
 | 
						char buf[MAX_EVENT_NAME_LEN];
 | 
				
			||||||
	char gbuf[MAX_EVENT_NAME_LEN];
 | 
						char gbuf[MAX_EVENT_NAME_LEN];
 | 
				
			||||||
 | 
						char abuf[MAX_BTF_ARGS_LEN];
 | 
				
			||||||
	struct traceprobe_parse_context ctx = { .flags = TPARG_FL_KERNEL };
 | 
						struct traceprobe_parse_context ctx = { .flags = TPARG_FL_KERNEL };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (argv[0][0]) {
 | 
						switch (argv[0][0]) {
 | 
				
			||||||
| 
						 | 
					@ -854,19 +856,31 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 | 
				
			||||||
		event = buf;
 | 
							event = buf;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						argc -= 2; argv += 2;
 | 
				
			||||||
 | 
						ctx.funcname = symbol;
 | 
				
			||||||
 | 
						new_argv = traceprobe_expand_meta_args(argc, argv, &new_argc,
 | 
				
			||||||
 | 
										       abuf, MAX_BTF_ARGS_LEN, &ctx);
 | 
				
			||||||
 | 
						if (IS_ERR(new_argv)) {
 | 
				
			||||||
 | 
							ret = PTR_ERR(new_argv);
 | 
				
			||||||
 | 
							new_argv = NULL;
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (new_argv) {
 | 
				
			||||||
 | 
							argc = new_argc;
 | 
				
			||||||
 | 
							argv = new_argv;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* setup a probe */
 | 
						/* setup a probe */
 | 
				
			||||||
	tk = alloc_trace_kprobe(group, event, addr, symbol, offset, maxactive,
 | 
						tk = alloc_trace_kprobe(group, event, addr, symbol, offset, maxactive,
 | 
				
			||||||
				argc - 2, is_return);
 | 
									argc, is_return);
 | 
				
			||||||
	if (IS_ERR(tk)) {
 | 
						if (IS_ERR(tk)) {
 | 
				
			||||||
		ret = PTR_ERR(tk);
 | 
							ret = PTR_ERR(tk);
 | 
				
			||||||
		/* This must return -ENOMEM, else there is a bug */
 | 
							/* This must return -ENOMEM, else there is a bug */
 | 
				
			||||||
		WARN_ON_ONCE(ret != -ENOMEM);
 | 
							WARN_ON_ONCE(ret != -ENOMEM);
 | 
				
			||||||
		goto out;	/* We know tk is not allocated */
 | 
							goto out;	/* We know tk is not allocated */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	argc -= 2; argv += 2;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* parse arguments */
 | 
						/* parse arguments */
 | 
				
			||||||
	ctx.funcname = symbol;
 | 
					 | 
				
			||||||
	for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
 | 
						for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
 | 
				
			||||||
		trace_probe_log_set_index(i + 2);
 | 
							trace_probe_log_set_index(i + 2);
 | 
				
			||||||
		ctx.offset = 0;
 | 
							ctx.offset = 0;
 | 
				
			||||||
| 
						 | 
					@ -894,6 +908,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	trace_probe_log_clear();
 | 
						trace_probe_log_clear();
 | 
				
			||||||
 | 
						kfree(new_argv);
 | 
				
			||||||
	kfree(symbol);
 | 
						kfree(symbol);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -371,9 +371,11 @@ static const char *type_from_btf_id(struct btf *btf, s32 id)
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr)
 | 
					static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr,
 | 
				
			||||||
 | 
											   bool tracepoint)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct btf *btf = traceprobe_get_btf();
 | 
						struct btf *btf = traceprobe_get_btf();
 | 
				
			||||||
 | 
						const struct btf_param *param;
 | 
				
			||||||
	const struct btf_type *t;
 | 
						const struct btf_type *t;
 | 
				
			||||||
	s32 id;
 | 
						s32 id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -395,9 +397,16 @@ static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr
 | 
				
			||||||
		return ERR_PTR(-ENOENT);
 | 
							return ERR_PTR(-ENOENT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*nr = btf_type_vlen(t);
 | 
						*nr = btf_type_vlen(t);
 | 
				
			||||||
 | 
						param = (const struct btf_param *)(t + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (*nr)
 | 
						/* Hide the first 'data' argument of tracepoint */
 | 
				
			||||||
		return (const struct btf_param *)(t + 1);
 | 
						if (tracepoint) {
 | 
				
			||||||
 | 
							(*nr)--;
 | 
				
			||||||
 | 
							param++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (*nr > 0)
 | 
				
			||||||
 | 
							return param;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -418,7 +427,8 @@ static int parse_btf_arg(const char *varname, struct fetch_insn *code,
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!ctx->params) {
 | 
						if (!ctx->params) {
 | 
				
			||||||
		params = find_btf_func_param(ctx->funcname, &ctx->nr_params);
 | 
							params = find_btf_func_param(ctx->funcname, &ctx->nr_params,
 | 
				
			||||||
 | 
										     ctx->flags & TPARG_FL_TPOINT);
 | 
				
			||||||
		if (IS_ERR(params)) {
 | 
							if (IS_ERR(params)) {
 | 
				
			||||||
			trace_probe_log_err(ctx->offset, NO_BTF_ENTRY);
 | 
								trace_probe_log_err(ctx->offset, NO_BTF_ENTRY);
 | 
				
			||||||
			return PTR_ERR(params);
 | 
								return PTR_ERR(params);
 | 
				
			||||||
| 
						 | 
					@ -451,12 +461,19 @@ static const struct fetch_type *parse_btf_arg_type(int arg_idx,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return find_fetch_type(typestr, ctx->flags);
 | 
						return find_fetch_type(typestr, ctx->flags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
static struct btf *traceprobe_get_btf(void)
 | 
					static struct btf *traceprobe_get_btf(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr,
 | 
				
			||||||
 | 
											   bool tracepoint)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return ERR_PTR(-EOPNOTSUPP);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int parse_btf_arg(const char *varname, struct fetch_insn *code,
 | 
					static int parse_btf_arg(const char *varname, struct fetch_insn *code,
 | 
				
			||||||
			 struct traceprobe_parse_context *ctx)
 | 
								 struct traceprobe_parse_context *ctx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -1114,6 +1131,150 @@ void traceprobe_free_probe_arg(struct probe_arg *arg)
 | 
				
			||||||
	kfree(arg->fmt);
 | 
						kfree(arg->fmt);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int argv_has_var_arg(int argc, const char *argv[], int *args_idx,
 | 
				
			||||||
 | 
								    struct traceprobe_parse_context *ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i, found = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < argc; i++)
 | 
				
			||||||
 | 
							if (str_has_prefix(argv[i], "$arg")) {
 | 
				
			||||||
 | 
								trace_probe_log_set_index(i + 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!tparg_is_function_entry(ctx->flags)) {
 | 
				
			||||||
 | 
									trace_probe_log_err(0, NOFENTRY_ARGS);
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (isdigit(argv[i][4])) {
 | 
				
			||||||
 | 
									found = 1;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (argv[i][4] != '*') {
 | 
				
			||||||
 | 
									trace_probe_log_err(0, BAD_VAR);
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (*args_idx >= 0 && *args_idx < argc) {
 | 
				
			||||||
 | 
									trace_probe_log_err(0, DOUBLE_ARGS);
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								found = 1;
 | 
				
			||||||
 | 
								*args_idx = i;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return found;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int sprint_nth_btf_arg(int idx, const char *type,
 | 
				
			||||||
 | 
								      char *buf, int bufsize,
 | 
				
			||||||
 | 
								      struct traceprobe_parse_context *ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct btf *btf = traceprobe_get_btf();
 | 
				
			||||||
 | 
						const char *name;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (idx >= ctx->nr_params) {
 | 
				
			||||||
 | 
							trace_probe_log_err(0, NO_BTFARG);
 | 
				
			||||||
 | 
							return -ENOENT;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						name = btf_name_by_offset(btf, ctx->params[idx].name_off);
 | 
				
			||||||
 | 
						if (!name) {
 | 
				
			||||||
 | 
							trace_probe_log_err(0, NO_BTF_ENTRY);
 | 
				
			||||||
 | 
							return -ENOENT;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ret = snprintf(buf, bufsize, "%s%s", name, type);
 | 
				
			||||||
 | 
						if (ret >= bufsize) {
 | 
				
			||||||
 | 
							trace_probe_log_err(0, ARGS_2LONG);
 | 
				
			||||||
 | 
							return -E2BIG;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Return new_argv which must be freed after use */
 | 
				
			||||||
 | 
					const char **traceprobe_expand_meta_args(int argc, const char *argv[],
 | 
				
			||||||
 | 
										 int *new_argc, char *buf, int bufsize,
 | 
				
			||||||
 | 
										 struct traceprobe_parse_context *ctx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct btf_param *params = NULL;
 | 
				
			||||||
 | 
						int i, j, n, used, ret, args_idx = -1;
 | 
				
			||||||
 | 
						const char **new_argv = NULL;
 | 
				
			||||||
 | 
						int nr_params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = argv_has_var_arg(argc, argv, &args_idx, ctx);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ERR_PTR(ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ret) {
 | 
				
			||||||
 | 
							*new_argc = argc;
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						params = find_btf_func_param(ctx->funcname, &nr_params,
 | 
				
			||||||
 | 
									     ctx->flags & TPARG_FL_TPOINT);
 | 
				
			||||||
 | 
						if (IS_ERR(params)) {
 | 
				
			||||||
 | 
							if (args_idx != -1) {
 | 
				
			||||||
 | 
								/* $arg* requires BTF info */
 | 
				
			||||||
 | 
								trace_probe_log_err(0, NOSUP_BTFARG);
 | 
				
			||||||
 | 
								return (const char **)params;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctx->params = params;
 | 
				
			||||||
 | 
						ctx->nr_params = nr_params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (args_idx >= 0)
 | 
				
			||||||
 | 
							*new_argc = argc + ctx->nr_params - 1;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							*new_argc = argc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						new_argv = kcalloc(*new_argc, sizeof(char *), GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!new_argv)
 | 
				
			||||||
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						used = 0;
 | 
				
			||||||
 | 
						for (i = 0, j = 0; i < argc; i++) {
 | 
				
			||||||
 | 
							trace_probe_log_set_index(i + 2);
 | 
				
			||||||
 | 
							if (i == args_idx) {
 | 
				
			||||||
 | 
								for (n = 0; n < nr_params; n++) {
 | 
				
			||||||
 | 
									ret = sprint_nth_btf_arg(n, "", buf + used,
 | 
				
			||||||
 | 
												 bufsize - used, ctx);
 | 
				
			||||||
 | 
									if (ret < 0)
 | 
				
			||||||
 | 
										goto error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									new_argv[j++] = buf + used;
 | 
				
			||||||
 | 
									used += ret + 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (str_has_prefix(argv[i], "$arg")) {
 | 
				
			||||||
 | 
								char *type = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								n = simple_strtoul(argv[i] + 4, &type, 10);
 | 
				
			||||||
 | 
								if (type && !(*type == ':' || *type == '\0')) {
 | 
				
			||||||
 | 
									trace_probe_log_err(0, BAD_VAR);
 | 
				
			||||||
 | 
									ret = -ENOENT;
 | 
				
			||||||
 | 
									goto error;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								/* Note: $argN starts from $arg1 */
 | 
				
			||||||
 | 
								ret = sprint_nth_btf_arg(n - 1, type, buf + used,
 | 
				
			||||||
 | 
											 bufsize - used, ctx);
 | 
				
			||||||
 | 
								if (ret < 0)
 | 
				
			||||||
 | 
									goto error;
 | 
				
			||||||
 | 
								new_argv[j++] = buf + used;
 | 
				
			||||||
 | 
								used += ret + 1;
 | 
				
			||||||
 | 
							} else
 | 
				
			||||||
 | 
								new_argv[j++] = argv[i];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return new_argv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
 | 
						kfree(new_argv);
 | 
				
			||||||
 | 
						return ERR_PTR(ret);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int traceprobe_update_arg(struct probe_arg *arg)
 | 
					int traceprobe_update_arg(struct probe_arg *arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct fetch_insn *code = arg->code;
 | 
						struct fetch_insn *code = arg->code;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,9 @@
 | 
				
			||||||
#define MAX_ARGSTR_LEN		63
 | 
					#define MAX_ARGSTR_LEN		63
 | 
				
			||||||
#define MAX_ARRAY_LEN		64
 | 
					#define MAX_ARRAY_LEN		64
 | 
				
			||||||
#define MAX_ARG_NAME_LEN	32
 | 
					#define MAX_ARG_NAME_LEN	32
 | 
				
			||||||
 | 
					#define MAX_BTF_ARGS_LEN	128
 | 
				
			||||||
#define MAX_STRING_SIZE		PATH_MAX
 | 
					#define MAX_STRING_SIZE		PATH_MAX
 | 
				
			||||||
 | 
					#define MAX_ARG_BUF_LEN		(MAX_TRACE_ARGS * MAX_ARG_NAME_LEN)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Reserved field names */
 | 
					/* Reserved field names */
 | 
				
			||||||
#define FIELD_STRING_IP		"__probe_ip"
 | 
					#define FIELD_STRING_IP		"__probe_ip"
 | 
				
			||||||
| 
						 | 
					@ -391,6 +393,9 @@ struct traceprobe_parse_context {
 | 
				
			||||||
extern int traceprobe_parse_probe_arg(struct trace_probe *tp, int i,
 | 
					extern int traceprobe_parse_probe_arg(struct trace_probe *tp, int i,
 | 
				
			||||||
				      const char *argv,
 | 
									      const char *argv,
 | 
				
			||||||
				      struct traceprobe_parse_context *ctx);
 | 
									      struct traceprobe_parse_context *ctx);
 | 
				
			||||||
 | 
					const char **traceprobe_expand_meta_args(int argc, const char *argv[],
 | 
				
			||||||
 | 
										 int *new_argc, char *buf, int bufsize,
 | 
				
			||||||
 | 
										 struct traceprobe_parse_context *ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int traceprobe_update_arg(struct probe_arg *arg);
 | 
					extern int traceprobe_update_arg(struct probe_arg *arg);
 | 
				
			||||||
extern void traceprobe_free_probe_arg(struct probe_arg *arg);
 | 
					extern void traceprobe_free_probe_arg(struct probe_arg *arg);
 | 
				
			||||||
| 
						 | 
					@ -485,7 +490,11 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
 | 
				
			||||||
	C(NO_EP_FILTER,		"No filter rule after 'if'"),		\
 | 
						C(NO_EP_FILTER,		"No filter rule after 'if'"),		\
 | 
				
			||||||
	C(NOSUP_BTFARG,		"BTF is not available or not supported"),	\
 | 
						C(NOSUP_BTFARG,		"BTF is not available or not supported"),	\
 | 
				
			||||||
	C(NO_BTFARG,		"This variable is not found at this probe point"),\
 | 
						C(NO_BTFARG,		"This variable is not found at this probe point"),\
 | 
				
			||||||
	C(NO_BTF_ENTRY,		"No BTF entry for this probe point"),
 | 
						C(NO_BTF_ENTRY,		"No BTF entry for this probe point"),	\
 | 
				
			||||||
 | 
						C(BAD_VAR_ARGS,		"$arg* must be an independent parameter without name etc."),\
 | 
				
			||||||
 | 
						C(NOFENTRY_ARGS,	"$arg* can be used only on function entry"),	\
 | 
				
			||||||
 | 
						C(DOUBLE_ARGS,		"$arg* can be used only once in the parameters"),	\
 | 
				
			||||||
 | 
						C(ARGS_2LONG,		"$arg* failed because the argument list is too long"),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#undef C
 | 
					#undef C
 | 
				
			||||||
#define C(a, b)		TP_ERR_##a
 | 
					#define C(a, b)		TP_ERR_##a
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue