tracing/probes: support '%pd' type for print struct dentry's name
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: Ye Bin <yebin10@huawei.com> Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
This commit is contained in:
parent
cdf355cc60
commit
d9b15224dd
@ -5540,7 +5540,7 @@ static const char readme_msg[] =
|
|||||||
"\t kernel return probes support: $retval, $arg<N>, $comm\n"
|
"\t kernel return probes support: $retval, $arg<N>, $comm\n"
|
||||||
"\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, char, string, symbol,\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 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
|
#ifdef CONFIG_HIST_TRIGGERS
|
||||||
"\t field: <stype> <name>;\n"
|
"\t field: <stype> <name>;\n"
|
||||||
"\t stype: u8/u16/u32/u64, s8/s16/s32/s64, pid_t,\n"
|
"\t stype: u8/u16/u32/u64, s8/s16/s32/s64, pid_t,\n"
|
||||||
|
@ -994,6 +994,7 @@ static int __trace_fprobe_create(int argc, const char *argv[])
|
|||||||
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];
|
char abuf[MAX_BTF_ARGS_LEN];
|
||||||
|
char *dbuf = NULL;
|
||||||
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 = {
|
||||||
@ -1104,6 +1105,10 @@ static int __trace_fprobe_create(int argc, const char *argv[])
|
|||||||
argv = new_argv;
|
argv = new_argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = traceprobe_expand_dentry_args(argc, argv, &dbuf);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
/* 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, is_return);
|
argc, is_return);
|
||||||
@ -1154,6 +1159,7 @@ out:
|
|||||||
trace_probe_log_clear();
|
trace_probe_log_clear();
|
||||||
kfree(new_argv);
|
kfree(new_argv);
|
||||||
kfree(symbol);
|
kfree(symbol);
|
||||||
|
kfree(dbuf);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
parse_error:
|
parse_error:
|
||||||
|
@ -782,6 +782,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
|
|||||||
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];
|
char abuf[MAX_BTF_ARGS_LEN];
|
||||||
|
char *dbuf = NULL;
|
||||||
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]) {
|
||||||
@ -933,6 +934,10 @@ static int __trace_kprobe_create(int argc, const char *argv[])
|
|||||||
argv = new_argv;
|
argv = new_argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = traceprobe_expand_dentry_args(argc, argv, &dbuf);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
/* 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, is_return);
|
argc, is_return);
|
||||||
@ -979,6 +984,7 @@ out:
|
|||||||
trace_probe_log_clear();
|
trace_probe_log_clear();
|
||||||
kfree(new_argv);
|
kfree(new_argv);
|
||||||
kfree(symbol);
|
kfree(symbol);
|
||||||
|
kfree(dbuf);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
parse_error:
|
parse_error:
|
||||||
|
@ -1739,6 +1739,56 @@ error:
|
|||||||
return ERR_PTR(ret);
|
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)
|
void traceprobe_finish_parse(struct traceprobe_parse_context *ctx)
|
||||||
{
|
{
|
||||||
clear_btf_context(ctx);
|
clear_btf_context(ctx);
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#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_BTF_ARGS_LEN 128
|
||||||
|
#define MAX_DENTRY_ARGS_LEN 256
|
||||||
#define MAX_STRING_SIZE PATH_MAX
|
#define MAX_STRING_SIZE PATH_MAX
|
||||||
#define MAX_ARG_BUF_LEN (MAX_TRACE_ARGS * MAX_ARG_NAME_LEN)
|
#define MAX_ARG_BUF_LEN (MAX_TRACE_ARGS * MAX_ARG_NAME_LEN)
|
||||||
|
|
||||||
@ -428,6 +429,7 @@ extern int traceprobe_parse_probe_arg(struct trace_probe *tp, int i,
|
|||||||
const char **traceprobe_expand_meta_args(int argc, const char *argv[],
|
const char **traceprobe_expand_meta_args(int argc, const char *argv[],
|
||||||
int *new_argc, char *buf, int bufsize,
|
int *new_argc, char *buf, int bufsize,
|
||||||
struct traceprobe_parse_context *ctx);
|
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 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);
|
||||||
|
Loading…
Reference in New Issue
Block a user