diff options
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r-- | tools/perf/builtin-trace.c | 135 |
1 files changed, 92 insertions, 43 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index a5201de1a191..6052eb057821 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -86,6 +86,34 @@ # define F_LINUX_SPECIFIC_BASE 1024 #endif +#define RAW_SYSCALL_ARGS_NUM 6 + +/* + * strtoul: Go from a string to a value, i.e. for msr: MSR_FS_BASE to 0xc0000100 + */ +struct syscall_arg_fmt { + size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg); + bool (*strtoul)(char *bf, size_t size, struct syscall_arg *arg, u64 *val); + unsigned long (*mask_val)(struct syscall_arg *arg, unsigned long val); + void *parm; + const char *name; + bool show_zero; +}; + +struct syscall_fmt { + const char *name; + const char *alias; + struct { + const char *sys_enter, + *sys_exit; + } bpf_prog_name; + struct syscall_arg_fmt arg[RAW_SYSCALL_ARGS_NUM]; + u8 nr_args; + bool errpid; + bool timeout; + bool hexret; +}; + struct trace { struct perf_tool tool; struct syscalltbl *sctbl; @@ -694,27 +722,7 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size, #include "trace/beauty/socket_type.c" #include "trace/beauty/waitid_options.c" -struct syscall_arg_fmt { - size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg); - unsigned long (*mask_val)(struct syscall_arg *arg, unsigned long val); - void *parm; - const char *name; - bool show_zero; -}; - -static struct syscall_fmt { - const char *name; - const char *alias; - struct { - const char *sys_enter, - *sys_exit; - } bpf_prog_name; - struct syscall_arg_fmt arg[6]; - u8 nr_args; - bool errpid; - bool timeout; - bool hexret; -} syscall_fmts[] = { +static struct syscall_fmt syscall_fmts[] = { { .name = "access", .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, }, { .name = "arch_prctl", @@ -1012,7 +1020,7 @@ struct syscall { */ struct bpf_map_syscall_entry { bool enabled; - u16 string_args_len[6]; + u16 string_args_len[RAW_SYSCALL_ARGS_NUM]; }; /* @@ -1437,7 +1445,7 @@ static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args) { int idx; - if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0) + if (nr_args == RAW_SYSCALL_ARGS_NUM && sc->fmt && sc->fmt->nr_args != 0) nr_args = sc->fmt->nr_args; sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt)); @@ -1453,15 +1461,37 @@ static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args) return 0; } -static int syscall__set_arg_fmts(struct syscall *sc) +static struct syscall_arg_fmt syscall_arg_fmts__by_name[] = { +}; + +static int syscall_arg_fmt__cmp(const void *name, const void *fmtp) +{ + const struct syscall_arg_fmt *fmt = fmtp; + return strcmp(name, fmt->name); +} + +static struct syscall_arg_fmt * +__syscall_arg_fmt__find_by_name(struct syscall_arg_fmt *fmts, const int nmemb, const char *name) { - struct tep_format_field *field, *last_field = NULL; - int idx = 0, len; + return bsearch(name, fmts, nmemb, sizeof(struct syscall_arg_fmt), syscall_arg_fmt__cmp); +} + +static struct syscall_arg_fmt *syscall_arg_fmt__find_by_name(const char *name) +{ + const int nmemb = ARRAY_SIZE(syscall_arg_fmts__by_name); + return __syscall_arg_fmt__find_by_name(syscall_arg_fmts__by_name, nmemb, name); +} - for (field = sc->args; field; field = field->next, ++idx) { +static struct tep_format_field * +syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field *field) +{ + struct tep_format_field *last_field = NULL; + int len; + + for (; field; field = field->next, ++arg) { last_field = field; - if (sc->fmt && sc->fmt->arg[idx].scnprintf) + if (arg->scnprintf) continue; len = strlen(field->name); @@ -1469,13 +1499,13 @@ static int syscall__set_arg_fmts(struct syscall *sc) if (strcmp(field->type, "const char *") == 0 && ((len >= 4 && strcmp(field->name + len - 4, "name") == 0) || strstr(field->name, "path") != NULL)) - sc->arg_fmt[idx].scnprintf = SCA_FILENAME; + arg->scnprintf = SCA_FILENAME; else if ((field->flags & TEP_FIELD_IS_POINTER) || strstr(field->name, "addr")) - sc->arg_fmt[idx].scnprintf = SCA_PTR; + arg->scnprintf = SCA_PTR; else if (strcmp(field->type, "pid_t") == 0) - sc->arg_fmt[idx].scnprintf = SCA_PID; + arg->scnprintf = SCA_PID; else if (strcmp(field->type, "umode_t") == 0) - sc->arg_fmt[idx].scnprintf = SCA_MODE_T; + arg->scnprintf = SCA_MODE_T; else if ((strcmp(field->type, "int") == 0 || strcmp(field->type, "unsigned int") == 0 || strcmp(field->type, "long") == 0) && @@ -1487,10 +1517,24 @@ static int syscall__set_arg_fmts(struct syscall *sc) * 23 unsigned int * 7 unsigned long */ - sc->arg_fmt[idx].scnprintf = SCA_FD; + arg->scnprintf = SCA_FD; + } else { + struct syscall_arg_fmt *fmt = syscall_arg_fmt__find_by_name(field->name); + + if (fmt) { + arg->scnprintf = fmt->scnprintf; + arg->strtoul = fmt->strtoul; + } } } + return last_field; +} + +static int syscall__set_arg_fmts(struct syscall *sc) +{ + struct tep_format_field *last_field = syscall_arg_fmt__init_array(sc->arg_fmt, sc->args); + if (last_field) sc->args_size = last_field->offset + last_field->size; @@ -1511,11 +1555,11 @@ static int trace__read_syscall_info(struct trace *trace, int id) sc = trace->syscalls.table + id; if (sc->nonexistent) - return 0; + return -EEXIST; if (name == NULL) { sc->nonexistent = true; - return 0; + return -EEXIST; } sc->name = name; @@ -1529,11 +1573,18 @@ static int trace__read_syscall_info(struct trace *trace, int id) sc->tp_format = trace_event__tp_format("syscalls", tp_name); } - if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields)) - return -ENOMEM; - - if (IS_ERR(sc->tp_format)) + /* + * Fails to read trace point format via sysfs node, so the trace point + * doesn't exist. Set the 'nonexistent' flag as true. + */ + if (IS_ERR(sc->tp_format)) { + sc->nonexistent = true; return PTR_ERR(sc->tp_format); + } + + if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? + RAW_SYSCALL_ARGS_NUM : sc->tp_format->format.nr_fields)) + return -ENOMEM; sc->args = sc->tp_format->format.fields; /* @@ -1736,6 +1787,7 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, if (arg.mask & bit) continue; + arg.fmt = &sc->arg_fmt[arg.idx]; val = syscall_arg__val(&arg, arg.idx); /* * Some syscall args need some mask, most don't and @@ -1825,11 +1877,8 @@ static struct syscall *trace__syscall_info(struct trace *trace, (err = trace__read_syscall_info(trace, id)) != 0) goto out_cant_read; - if (trace->syscalls.table[id].name == NULL) { - if (trace->syscalls.table[id].nonexistent) - return NULL; + if (trace->syscalls.table && trace->syscalls.table[id].nonexistent) goto out_cant_read; - } return &trace->syscalls.table[id]; |