Commit c69e430a authored by Ye Bin's avatar Ye Bin
Browse files

tracing/probes: support '%pd' type for print struct dentry's name

mainline inclusion
from mainline-v6.10-rc1
commit d9b15224dd8ff83b2aef87e4cd5ad10c875ef7d6
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IAMXDU

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d9b15224dd8ff83b2aef87e4cd5ad10c875ef7d6

--------------------------------

During fault locating, the file name needs to be printed based on the
dentry  address. The offset needs to be calculated each time, which
is troublesome. Similar to printk, kprobe support print type '%pd' for
print dentry's name. For example "name=$arg1:%pd" casts the `$arg1`
as (struct dentry *), dereferences the "d_name.name" field and stores
it to "name" argument as a kernel string.
Here is an example:
[tracing]# echo 'p:testprobe dput name=$arg1:%pd' > kprobe_events
[tracing]# echo 1 > events/kprobes/testprobe/enable
[tracing]# grep -q "1" events/kprobes/testprobe/enable
[tracing]# echo 0 > events/kprobes/testprobe/enable
[tracing]# cat trace | grep "enable"
	    bash-14844   [002] ..... 16912.889543: testprobe: (dput+0x4/0x30) name="enable"
            grep-15389   [003] ..... 16922.834182: testprobe: (dput+0x4/0x30) name="enable"
            grep-15389   [003] ..... 16922.836103: testprobe: (dput+0x4/0x30) name="enable"
            bash-14844   [001] ..... 16931.820909: testprobe: (dput+0x4/0x30) name="enable"

Note that this expects the given argument (e.g. $arg1) is an address of struct
dentry. User must ensure it.

Link: https://lore.kernel.org/all/20240322064308.284457-2-yebin10@huawei.com/



Signed-off-by: default avatarYe Bin <yebin10@huawei.com>
Acked-by: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
Conflicts:
	kernel/trace/trace.c
[Fix context diff]
Signed-off-by: default avatarYe Bin <yebin10@huawei.com>
parent e65c0786
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -5763,7 +5763,7 @@ static const char readme_msg[] =
	"\t           +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n"
	"\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, char, string, symbol,\n"
	"\t           b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
	"\t           symstr, <type>\\[<array-size>\\]\n"
	"\t           symstr, %pd, <type>\\[<array-size>\\]\n"
#ifdef CONFIG_HIST_TRIGGERS
	"\t    field: <stype> <name>;\n"
	"\t    stype: u8/u16/u32/u64, s8/s16/s32/s64, pid_t,\n"
+6 −0
Original line number Diff line number Diff line
@@ -976,6 +976,7 @@ static int __trace_fprobe_create(int argc, const char *argv[])
	char gbuf[MAX_EVENT_NAME_LEN];
	char sbuf[KSYM_NAME_LEN];
	char abuf[MAX_BTF_ARGS_LEN];
	char *dbuf = NULL;
	bool is_tracepoint = false;
	struct tracepoint *tpoint = NULL;
	struct traceprobe_parse_context ctx = {
@@ -1086,6 +1087,10 @@ static int __trace_fprobe_create(int argc, const char *argv[])
		argv = new_argv;
	}

	ret = traceprobe_expand_dentry_args(argc, argv, &dbuf);
	if (ret)
		goto out;

	/* setup a probe */
	tf = alloc_trace_fprobe(group, event, symbol, tpoint, maxactive,
				argc, is_return);
@@ -1131,6 +1136,7 @@ static int __trace_fprobe_create(int argc, const char *argv[])
	trace_probe_log_clear();
	kfree(new_argv);
	kfree(symbol);
	kfree(dbuf);
	return ret;

parse_error:
+6 −0
Original line number Diff line number Diff line
@@ -779,6 +779,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
	char buf[MAX_EVENT_NAME_LEN];
	char gbuf[MAX_EVENT_NAME_LEN];
	char abuf[MAX_BTF_ARGS_LEN];
	char *dbuf = NULL;
	struct traceprobe_parse_context ctx = { .flags = TPARG_FL_KERNEL };

	switch (argv[0][0]) {
@@ -930,6 +931,10 @@ static int __trace_kprobe_create(int argc, const char *argv[])
		argv = new_argv;
	}

	ret = traceprobe_expand_dentry_args(argc, argv, &dbuf);
	if (ret)
		goto out;

	/* setup a probe */
	tk = alloc_trace_kprobe(group, event, addr, symbol, offset, maxactive,
				argc, is_return);
@@ -971,6 +976,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
	trace_probe_log_clear();
	kfree(new_argv);
	kfree(symbol);
	kfree(dbuf);
	return ret;

parse_error:
+50 −0
Original line number Diff line number Diff line
@@ -1573,6 +1573,56 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[],
	return ERR_PTR(ret);
}

/* @buf: *buf must be equal to NULL. Caller must to free *buf */
int traceprobe_expand_dentry_args(int argc, const char *argv[], char **buf)
{
	int i, used, ret;
	const int bufsize = MAX_DENTRY_ARGS_LEN;
	char *tmpbuf = NULL;

	if (*buf)
		return -EINVAL;

	used = 0;
	for (i = 0; i < argc; i++) {
		if (glob_match("*:%pd", argv[i])) {
			char *tmp;
			char *equal;

			if (!tmpbuf) {
				tmpbuf = kmalloc(bufsize, GFP_KERNEL);
				if (!tmpbuf)
					return -ENOMEM;
			}

			tmp = kstrdup(argv[i], GFP_KERNEL);
			if (!tmp)
				goto nomem;

			equal = strchr(tmp, '=');
			if (equal)
				*equal = '\0';
			tmp[strlen(argv[i]) - 4] = '\0';
			ret = snprintf(tmpbuf + used, bufsize - used,
				       "%s%s+0x0(+0x%zx(%s)):string",
				       equal ? tmp : "", equal ? "=" : "",
				       offsetof(struct dentry, d_name.name),
				       equal ? equal + 1 : tmp);
			kfree(tmp);
			if (ret >= bufsize - used)
				goto nomem;
			argv[i] = tmpbuf + used;
			used += ret + 1;
		}
	}

	*buf = tmpbuf;
	return 0;
nomem:
	kfree(tmpbuf);
	return -ENOMEM;
}

void traceprobe_finish_parse(struct traceprobe_parse_context *ctx)
{
	clear_btf_context(ctx);
+2 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#define MAX_ARRAY_LEN		64
#define MAX_ARG_NAME_LEN	32
#define MAX_BTF_ARGS_LEN	128
#define MAX_DENTRY_ARGS_LEN	256
#define MAX_STRING_SIZE		PATH_MAX
#define MAX_ARG_BUF_LEN		(MAX_TRACE_ARGS * MAX_ARG_NAME_LEN)

@@ -402,6 +403,7 @@ extern int traceprobe_parse_probe_arg(struct trace_probe *tp, int i,
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_expand_dentry_args(int argc, const char *argv[], char **buf);

extern int traceprobe_update_arg(struct probe_arg *arg);
extern void traceprobe_free_probe_arg(struct probe_arg *arg);