diff options
Diffstat (limited to 'tools/perf/trace')
69 files changed, 3326 insertions, 0 deletions
diff --git a/tools/perf/trace/beauty/Build b/tools/perf/trace/beauty/Build new file mode 100644 index 0000000000..d11ce256f5 --- /dev/null +++ b/tools/perf/trace/beauty/Build @@ -0,0 +1,21 @@ +perf-y += clone.o +perf-y += fcntl.o +perf-y += flock.o +perf-y += fsmount.o +perf-y += fspick.o +ifeq ($(SRCARCH),$(filter $(SRCARCH),x86)) +perf-y += ioctl.o +endif +perf-y += kcmp.o +perf-y += mount_flags.o +perf-y += move_mount.o +perf-y += pkey_alloc.o +perf-y += arch_prctl.o +perf-y += prctl.o +perf-y += renameat.o +perf-y += sockaddr.o +perf-y += socket.o +perf-y += statx.o +perf-y += sync_file_range.o +perf-y += timespec.o +perf-y += tracepoints/ diff --git a/tools/perf/trace/beauty/arch_errno_names.c b/tools/perf/trace/beauty/arch_errno_names.c new file mode 100644 index 0000000000..ede031c3a9 --- /dev/null +++ b/tools/perf/trace/beauty/arch_errno_names.c @@ -0,0 +1 @@ +#include "trace/beauty/generated/arch_errno_name_array.c" diff --git a/tools/perf/trace/beauty/arch_errno_names.sh b/tools/perf/trace/beauty/arch_errno_names.sh new file mode 100755 index 0000000000..cc09dcaa89 --- /dev/null +++ b/tools/perf/trace/beauty/arch_errno_names.sh @@ -0,0 +1,86 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Generate C file mapping errno codes to errno names. +# +# Copyright IBM Corp. 2018 +# Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> + +gcc="$1" +toolsdir="$2" +include_path="-I$toolsdir/include/uapi" + +arch_string() +{ + echo "$1" |sed -e 'y/- /__/' |tr '[[:upper:]]' '[[:lower:]]' +} + +asm_errno_file() +{ + arch="$1" + + header="$toolsdir/arch/$arch/include/uapi/asm/errno.h" + if test -r "$header"; then + echo "$header" + else + echo "$toolsdir/include/uapi/asm-generic/errno.h" + fi +} + +create_errno_lookup_func() +{ + arch=$(arch_string "$1") + + printf "static const char *errno_to_name__%s(int err)\n{\n\tswitch (err) {\n" $arch + + while read name nr; do + printf '\tcase %d: return "%s";\n' $nr $name + done + + printf '\tdefault: return "(unknown)";\n\t}\n}\n' +} + +process_arch() +{ + arch="$1" + asm_errno=$(asm_errno_file "$arch") + + $gcc $CFLAGS $include_path -E -dM -x c $asm_errno \ + |grep -hE '^#define[[:blank:]]+(E[^[:blank:]]+)[[:blank:]]+([[:digit:]]+).*' \ + |awk '{ print $2","$3; }' \ + |sort -t, -k2 -nu \ + |IFS=, create_errno_lookup_func "$arch" +} + +create_arch_errno_table_func() +{ + archlist="$1" + default="$2" + + printf 'const char *arch_syscalls__strerrno(const char *arch, int err)\n' + printf '{\n' + for arch in $archlist; do + printf '\tif (!strcmp(arch, "%s"))\n' $(arch_string "$arch") + printf '\t\treturn errno_to_name__%s(err);\n' $(arch_string "$arch") + done + printf '\treturn errno_to_name__%s(err);\n' $(arch_string "$default") + printf '}\n' +} + +cat <<EoHEADER +/* SPDX-License-Identifier: GPL-2.0 */ + +#include <string.h> + +EoHEADER + +# Create list of architectures that have a specific errno.h. +archlist="" +for arch in $(find $toolsdir/arch -maxdepth 1 -mindepth 1 -type d -printf "%f\n" | sort -r); do + test -f $toolsdir/arch/$arch/include/uapi/asm/errno.h && archlist="$archlist $arch" +done + +for arch in generic $archlist; do + process_arch "$arch" +done +create_arch_errno_table_func "$archlist" "generic" diff --git a/tools/perf/trace/beauty/arch_prctl.c b/tools/perf/trace/beauty/arch_prctl.c new file mode 100644 index 0000000000..a211348d32 --- /dev/null +++ b/tools/perf/trace/beauty/arch_prctl.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/arch_prctl.c + * + * Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" +#include <linux/kernel.h> + +#include "trace/beauty/generated/x86_arch_prctl_code_array.c" + +static DEFINE_STRARRAY_OFFSET(x86_arch_prctl_codes_1, "ARCH_", x86_arch_prctl_codes_1_offset); +static DEFINE_STRARRAY_OFFSET(x86_arch_prctl_codes_2, "ARCH_", x86_arch_prctl_codes_2_offset); +static DEFINE_STRARRAY_OFFSET(x86_arch_prctl_codes_3, "ARCH_", x86_arch_prctl_codes_3_offset); + +static struct strarray *x86_arch_prctl_codes[] = { + &strarray__x86_arch_prctl_codes_1, + &strarray__x86_arch_prctl_codes_2, + &strarray__x86_arch_prctl_codes_3, +}; + +static DEFINE_STRARRAYS(x86_arch_prctl_codes); + +static size_t x86_arch_prctl__scnprintf_code(int option, char *bf, size_t size, bool show_prefix) +{ + return strarrays__scnprintf(&strarrays__x86_arch_prctl_codes, bf, size, "%#x", show_prefix, option); +} + +size_t syscall_arg__scnprintf_x86_arch_prctl_code(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long code = arg->val; + + return x86_arch_prctl__scnprintf_code(code, bf, size, arg->show_string_prefix); +} diff --git a/tools/perf/trace/beauty/beauty.h b/tools/perf/trace/beauty/beauty.h new file mode 100644 index 0000000000..788e8f6bd9 --- /dev/null +++ b/tools/perf/trace/beauty/beauty.h @@ -0,0 +1,256 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _PERF_TRACE_BEAUTY_H +#define _PERF_TRACE_BEAUTY_H + +#include <linux/kernel.h> +#include <linux/types.h> +#include <sys/types.h> +#include <stdbool.h> + +struct strarray { + u64 offset; + int nr_entries; + const char *prefix; + const char * const *entries; +}; + +#define DEFINE_STRARRAY(array, _prefix) struct strarray strarray__##array = { \ + .nr_entries = ARRAY_SIZE(array), \ + .entries = array, \ + .prefix = _prefix, \ +} + +#define DEFINE_STRARRAY_OFFSET(array, _prefix, off) struct strarray strarray__##array = { \ + .offset = off, \ + .nr_entries = ARRAY_SIZE(array), \ + .entries = array, \ + .prefix = _prefix, \ +} + +size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, bool show_prefix, int val); +size_t strarray__scnprintf_suffix(struct strarray *sa, char *bf, size_t size, const char *intfmt, bool show_suffix, int val); +size_t strarray__scnprintf_flags(struct strarray *sa, char *bf, size_t size, bool show_prefix, unsigned long flags); + +bool strarray__strtoul(struct strarray *sa, char *bf, size_t size, u64 *ret); +bool strarray__strtoul_flags(struct strarray *sa, char *bf, size_t size, u64 *ret); + +struct trace; +struct thread; + +struct file { + char *pathname; + int dev_maj; +}; + +struct file *thread__files_entry(struct thread *thread, int fd); + +struct strarrays { + int nr_entries; + struct strarray **entries; +}; + +#define DEFINE_STRARRAYS(array) struct strarrays strarrays__##array = { \ + .nr_entries = ARRAY_SIZE(array), \ + .entries = array, \ +} + +size_t strarrays__scnprintf(struct strarrays *sas, char *bf, size_t size, const char *intfmt, bool show_prefix, int val); + +bool strarrays__strtoul(struct strarrays *sas, char *bf, size_t size, u64 *ret); + +size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size); + +extern struct strarray strarray__socket_families; + +extern struct strarray strarray__socket_level; + +/** + * augmented_arg: extra payload for syscall pointer arguments + + * If perf_sample->raw_size is more than what a syscall sys_enter_FOO puts, then + * its the arguments contents, so that we can show more than just a + * pointer. This will be done initially with eBPF, the start of that is at the + * tools/perf/util/bpf_skel/augmented_syscalls.bpf.c that will eventually be + * done automagically caching the running kernel tracefs events data into an + * eBPF C script, that then gets compiled and its .o file cached for subsequent + * use. For char pointers like the ones for 'open' like syscalls its easy, for + * the rest we should use DWARF or better, BTF, much more compact. + * + * @size: 8 if all we need is an integer, otherwise all of the augmented arg. + * @int_arg: will be used for integer like pointer contents, like 'accept's 'upeer_addrlen' + * @value: u64 aligned, for structs, pathnames + */ +struct augmented_arg { + int size; + int int_arg; + u64 value[]; +}; + +struct syscall_arg_fmt; + +/** + * @val: value of syscall argument being formatted + * @len: for tracepoint dynamic arrays, if fmt->nr_entries == 0, then its not a fixed array, look at arg->len + * @args: All the args, use syscall_args__val(arg, nth) to access one + * @augmented_args: Extra data that can be collected, for instance, with eBPF for expanding the pathname for open, etc + * @augmented_args_size: augmented_args total payload size + * @thread: tid state (maps, pid, tid, etc) + * @trace: 'perf trace' internals: all threads, etc + * @parm: private area, may be an strarray, for instance + * @idx: syscall arg idx (is this the first?) + * @mask: a syscall arg may mask another arg, see syscall_arg__scnprintf_futex_op + * @show_string_prefix: When there is a common prefix in a string table, show it or not + */ + +struct syscall_arg { + unsigned long val; + unsigned char *args; + struct syscall_arg_fmt *fmt; + struct { + struct augmented_arg *args; + int size; + } augmented; + struct thread *thread; + struct trace *trace; + void *parm; + u16 len; + u8 idx; + u8 mask; + bool show_string_prefix; +}; + +unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx); + +size_t syscall_arg__scnprintf_strarray_flags(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_STRARRAY_FLAGS syscall_arg__scnprintf_strarray_flags + +bool syscall_arg__strtoul_strarray(char *bf, size_t size, struct syscall_arg *arg, u64 *ret); +#define STUL_STRARRAY syscall_arg__strtoul_strarray + +bool syscall_arg__strtoul_strarray_flags(char *bf, size_t size, struct syscall_arg *arg, u64 *ret); +#define STUL_STRARRAY_FLAGS syscall_arg__strtoul_strarray_flags + +bool syscall_arg__strtoul_strarrays(char *bf, size_t size, struct syscall_arg *arg, u64 *ret); +#define STUL_STRARRAYS syscall_arg__strtoul_strarrays + +size_t syscall_arg__scnprintf_x86_irq_vectors(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_X86_IRQ_VECTORS syscall_arg__scnprintf_x86_irq_vectors + +bool syscall_arg__strtoul_x86_irq_vectors(char *bf, size_t size, struct syscall_arg *arg, u64 *ret); +#define STUL_X86_IRQ_VECTORS syscall_arg__strtoul_x86_irq_vectors + +size_t syscall_arg__scnprintf_x86_MSR(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_X86_MSR syscall_arg__scnprintf_x86_MSR + +bool syscall_arg__strtoul_x86_MSR(char *bf, size_t size, struct syscall_arg *arg, u64 *ret); +#define STUL_X86_MSR syscall_arg__strtoul_x86_MSR + +size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_STRARRAYS syscall_arg__scnprintf_strarrays + +size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_FD syscall_arg__scnprintf_fd + +size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_HEX syscall_arg__scnprintf_hex + +size_t syscall_arg__scnprintf_ptr(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_PTR syscall_arg__scnprintf_ptr + +size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_INT syscall_arg__scnprintf_int + +size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_LONG syscall_arg__scnprintf_long + +size_t syscall_arg__scnprintf_pid(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_PID syscall_arg__scnprintf_pid + +size_t syscall_arg__scnprintf_clone_flags(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_CLONE_FLAGS syscall_arg__scnprintf_clone_flags + +size_t syscall_arg__scnprintf_fcntl_cmd(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_FCNTL_CMD syscall_arg__scnprintf_fcntl_cmd + +size_t syscall_arg__scnprintf_fcntl_arg(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_FCNTL_ARG syscall_arg__scnprintf_fcntl_arg + +size_t syscall_arg__scnprintf_flock(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_FLOCK syscall_arg__scnprintf_flock + +size_t syscall_arg__scnprintf_fsmount_attr_flags(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_FSMOUNT_ATTR_FLAGS syscall_arg__scnprintf_fsmount_attr_flags + +size_t syscall_arg__scnprintf_fspick_flags(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_FSPICK_FLAGS syscall_arg__scnprintf_fspick_flags + +size_t syscall_arg__scnprintf_ioctl_cmd(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_IOCTL_CMD syscall_arg__scnprintf_ioctl_cmd + +size_t syscall_arg__scnprintf_kcmp_type(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_KCMP_TYPE syscall_arg__scnprintf_kcmp_type + +size_t syscall_arg__scnprintf_kcmp_idx(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_KCMP_IDX syscall_arg__scnprintf_kcmp_idx + +unsigned long syscall_arg__mask_val_mount_flags(struct syscall_arg *arg, unsigned long flags); +#define SCAMV_MOUNT_FLAGS syscall_arg__mask_val_mount_flags + +size_t syscall_arg__scnprintf_mount_flags(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_MOUNT_FLAGS syscall_arg__scnprintf_mount_flags + +size_t syscall_arg__scnprintf_move_mount_flags(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_MOVE_MOUNT_FLAGS syscall_arg__scnprintf_move_mount_flags + +size_t syscall_arg__scnprintf_pkey_alloc_access_rights(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_PKEY_ALLOC_ACCESS_RIGHTS syscall_arg__scnprintf_pkey_alloc_access_rights + +size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags + +size_t syscall_arg__scnprintf_x86_arch_prctl_code(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_X86_ARCH_PRCTL_CODE syscall_arg__scnprintf_x86_arch_prctl_code + +size_t syscall_arg__scnprintf_prctl_option(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_PRCTL_OPTION syscall_arg__scnprintf_prctl_option + +extern struct strarray strarray__prctl_options; + +size_t syscall_arg__scnprintf_prctl_arg2(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_PRCTL_ARG2 syscall_arg__scnprintf_prctl_arg2 + +size_t syscall_arg__scnprintf_prctl_arg3(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_PRCTL_ARG3 syscall_arg__scnprintf_prctl_arg3 + +size_t syscall_arg__scnprintf_renameat2_flags(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_RENAMEAT2_FLAGS syscall_arg__scnprintf_renameat2_flags + +size_t syscall_arg__scnprintf_sockaddr(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_SOCKADDR syscall_arg__scnprintf_sockaddr + +size_t syscall_arg__scnprintf_socket_protocol(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_SK_PROTO syscall_arg__scnprintf_socket_protocol + +size_t syscall_arg__scnprintf_socket_level(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_SK_LEVEL syscall_arg__scnprintf_socket_level + +size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_STATX_FLAGS syscall_arg__scnprintf_statx_flags + +size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_STATX_MASK syscall_arg__scnprintf_statx_mask + +size_t syscall_arg__scnprintf_sync_file_range_flags(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_SYNC_FILE_RANGE_FLAGS syscall_arg__scnprintf_sync_file_range_flags + +size_t syscall_arg__scnprintf_timespec(char *bf, size_t size, struct syscall_arg *arg); +#define SCA_TIMESPEC syscall_arg__scnprintf_timespec + +size_t open__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix); + +void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg, + size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg)); + +const char *arch_syscalls__strerrno(const char *arch, int err); + +#endif /* _PERF_TRACE_BEAUTY_H */ diff --git a/tools/perf/trace/beauty/clone.c b/tools/perf/trace/beauty/clone.c new file mode 100644 index 0000000000..f4db894e0a --- /dev/null +++ b/tools/perf/trace/beauty/clone.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/cone.c + * + * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" +#include <linux/kernel.h> +#include <sys/types.h> +#include <uapi/linux/sched.h> + +static size_t clone__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix) +{ + const char *prefix = "CLONE_"; + int printed = 0; + +#define P_FLAG(n) \ + if (flags & CLONE_##n) { \ + printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ + flags &= ~CLONE_##n; \ + } + + P_FLAG(VM); + P_FLAG(FS); + P_FLAG(FILES); + P_FLAG(SIGHAND); + P_FLAG(PIDFD); + P_FLAG(PTRACE); + P_FLAG(VFORK); + P_FLAG(PARENT); + P_FLAG(THREAD); + P_FLAG(NEWNS); + P_FLAG(SYSVSEM); + P_FLAG(SETTLS); + P_FLAG(PARENT_SETTID); + P_FLAG(CHILD_CLEARTID); + P_FLAG(DETACHED); + P_FLAG(UNTRACED); + P_FLAG(CHILD_SETTID); + P_FLAG(NEWCGROUP); + P_FLAG(NEWUTS); + P_FLAG(NEWIPC); + P_FLAG(NEWUSER); + P_FLAG(NEWPID); + P_FLAG(NEWNET); + P_FLAG(IO); + P_FLAG(CLEAR_SIGHAND); + P_FLAG(INTO_CGROUP); +#undef P_FLAG + + if (flags) + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); + + return printed; +} + +size_t syscall_arg__scnprintf_clone_flags(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long flags = arg->val; + enum syscall_clone_args { + SCC_FLAGS = (1 << 0), + SCC_CHILD_STACK = (1 << 1), + SCC_PARENT_TIDPTR = (1 << 2), + SCC_CHILD_TIDPTR = (1 << 3), + SCC_TLS = (1 << 4), + }; + if (!(flags & CLONE_PARENT_SETTID)) + arg->mask |= SCC_PARENT_TIDPTR; + + if (!(flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID))) + arg->mask |= SCC_CHILD_TIDPTR; + + if (!(flags & CLONE_SETTLS)) + arg->mask |= SCC_TLS; + + return clone__scnprintf_flags(flags, bf, size, arg->show_string_prefix); +} diff --git a/tools/perf/trace/beauty/drm_ioctl.sh b/tools/perf/trace/beauty/drm_ioctl.sh new file mode 100755 index 0000000000..9aa94fd523 --- /dev/null +++ b/tools/perf/trace/beauty/drm_ioctl.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/drm/ + +printf "#ifndef DRM_COMMAND_BASE\n" +grep "#define DRM_COMMAND_BASE" $header_dir/drm.h +printf "#endif\n" + +printf "static const char *drm_ioctl_cmds[] = {\n" +grep "^#define DRM_IOCTL.*DRM_IO" $header_dir/drm.h | \ + sed -r 's/^#define +DRM_IOCTL_([A-Z0-9_]+)[ ]+DRM_IO[A-Z]* *\( *(0x[[:xdigit:]]+),*.*/ [\2] = "\1",/g' +grep "^#define DRM_I915_[A-Z_0-9]\+[ ]\+0x" $header_dir/i915_drm.h | \ + sed -r 's/^#define +DRM_I915_([A-Z0-9_]+)[ ]+(0x[[:xdigit:]]+)/\t[DRM_COMMAND_BASE + \2] = "I915_\1",/g' +printf "};\n" diff --git a/tools/perf/trace/beauty/eventfd.c b/tools/perf/trace/beauty/eventfd.c new file mode 100644 index 0000000000..4bab106213 --- /dev/null +++ b/tools/perf/trace/beauty/eventfd.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: LGPL-2.1 +#ifndef EFD_SEMAPHORE +#define EFD_SEMAPHORE 1 +#endif + +#ifndef EFD_NONBLOCK +#define EFD_NONBLOCK 00004000 +#endif + +#ifndef EFD_CLOEXEC +#define EFD_CLOEXEC 02000000 +#endif + +static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size, struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + const char *prefix = "EFD_"; + int printed = 0, flags = arg->val; + + if (flags == 0) + return scnprintf(bf, size, "NONE"); +#define P_FLAG(n) \ + if (flags & EFD_##n) { \ + printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ + flags &= ~EFD_##n; \ + } + + P_FLAG(SEMAPHORE); + P_FLAG(CLOEXEC); + P_FLAG(NONBLOCK); +#undef P_FLAG + + if (flags) + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); + + return printed; +} + +#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags diff --git a/tools/perf/trace/beauty/fadvise.sh b/tools/perf/trace/beauty/fadvise.sh new file mode 100755 index 0000000000..4d3dd6e56d --- /dev/null +++ b/tools/perf/trace/beauty/fadvise.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ + +printf "static const char *fadvise_advices[] = {\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+POSIX_FADV_(\w+)[[:space:]]+([[:digit:]]+)[[:space:]]+.*' + +grep -E $regex ${header_dir}/fadvise.h | \ + sed -r "s/$regex/\2 \1/g" | \ + sort | xargs printf "\t[%s] = \"%s\",\n" | \ + grep -v "[6].*DONTNEED" | grep -v "[7].*NOREUSE" +printf "};\n" + +# XXX Fix this properly: + +# The grep 6/7 DONTNEED/NOREUSE are a hack to filter out the s/390 oddity See +# tools/include/uapi/linux/fadvise.h for details. + +# Probably fix this when generating the string tables per arch so that We can +# reliably process on arch FOO a perf.data file collected by 'perf trace +# record' on arch BAR, e.g. collect on s/390 and process on x86. diff --git a/tools/perf/trace/beauty/fcntl.c b/tools/perf/trace/beauty/fcntl.c new file mode 100644 index 0000000000..56ef83b3d1 --- /dev/null +++ b/tools/perf/trace/beauty/fcntl.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/fcntl.c + * + * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" +#include <linux/kernel.h> +#include <uapi/linux/fcntl.h> + +static size_t fcntl__scnprintf_getfd(unsigned long val, char *bf, size_t size, bool show_prefix) +{ + return val ? scnprintf(bf, size, "%s", "0") : + scnprintf(bf, size, "%s%s", show_prefix ? "FD_" : "", "CLOEXEC"); +} + +static size_t syscall_arg__scnprintf_fcntl_getfd(char *bf, size_t size, struct syscall_arg *arg) +{ + return fcntl__scnprintf_getfd(arg->val, bf, size, arg->show_string_prefix); +} + +static size_t fcntl__scnprintf_getlease(unsigned long val, char *bf, size_t size, bool show_prefix) +{ + static const char *fcntl_setlease[] = { "RDLCK", "WRLCK", "UNLCK", }; + static DEFINE_STRARRAY(fcntl_setlease, "F_"); + + return strarray__scnprintf(&strarray__fcntl_setlease, bf, size, "%x", show_prefix, val); +} + +static size_t syscall_arg__scnprintf_fcntl_getlease(char *bf, size_t size, struct syscall_arg *arg) +{ + return fcntl__scnprintf_getlease(arg->val, bf, size, arg->show_string_prefix); +} + +size_t syscall_arg__scnprintf_fcntl_cmd(char *bf, size_t size, struct syscall_arg *arg) +{ + if (arg->val == F_GETFL) { + syscall_arg__set_ret_scnprintf(arg, syscall_arg__scnprintf_open_flags); + goto mask_arg; + } + if (arg->val == F_GETFD) { + syscall_arg__set_ret_scnprintf(arg, syscall_arg__scnprintf_fcntl_getfd); + goto mask_arg; + } + if (arg->val == F_DUPFD_CLOEXEC || arg->val == F_DUPFD) { + syscall_arg__set_ret_scnprintf(arg, syscall_arg__scnprintf_fd); + goto out; + } + if (arg->val == F_GETOWN) { + syscall_arg__set_ret_scnprintf(arg, syscall_arg__scnprintf_pid); + goto mask_arg; + } + if (arg->val == F_GETLEASE) { + syscall_arg__set_ret_scnprintf(arg, syscall_arg__scnprintf_fcntl_getlease); + goto mask_arg; + } + /* + * Some commands ignore the third fcntl argument, "arg", so mask it + */ + if (arg->val == F_GET_SEALS || + arg->val == F_GETSIG) { +mask_arg: + arg->mask |= (1 << 2); + } +out: + return syscall_arg__scnprintf_strarrays(bf, size, arg); +} + +size_t syscall_arg__scnprintf_fcntl_arg(char *bf, size_t size, struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + int cmd = syscall_arg__val(arg, 1); + + if (cmd == F_DUPFD) + return syscall_arg__scnprintf_fd(bf, size, arg); + + if (cmd == F_SETFD) + return fcntl__scnprintf_getfd(arg->val, bf, size, show_prefix); + + if (cmd == F_SETFL) + return open__scnprintf_flags(arg->val, bf, size, show_prefix); + + if (cmd == F_SETOWN) + return syscall_arg__scnprintf_pid(bf, size, arg); + + if (cmd == F_SETLEASE) + return fcntl__scnprintf_getlease(arg->val, bf, size, show_prefix); + /* + * We still don't grab the contents of pointers on entry or exit, + * so just print them as hex numbers + */ + if (cmd == F_SETLK || cmd == F_SETLKW || cmd == F_GETLK || + cmd == F_OFD_SETLK || cmd == F_OFD_SETLKW || cmd == F_OFD_GETLK || + cmd == F_GETOWN_EX || cmd == F_SETOWN_EX || + cmd == F_GET_RW_HINT || cmd == F_SET_RW_HINT || + cmd == F_GET_FILE_RW_HINT || cmd == F_SET_FILE_RW_HINT) + return syscall_arg__scnprintf_hex(bf, size, arg); + + return syscall_arg__scnprintf_long(bf, size, arg); +} diff --git a/tools/perf/trace/beauty/flock.c b/tools/perf/trace/beauty/flock.c new file mode 100644 index 0000000000..c14274edd6 --- /dev/null +++ b/tools/perf/trace/beauty/flock.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: LGPL-2.1 + +#include "trace/beauty/beauty.h" +#include <linux/kernel.h> +#include <uapi/linux/fcntl.h> + +#ifndef LOCK_MAND +#define LOCK_MAND 32 +#endif + +#ifndef LOCK_READ +#define LOCK_READ 64 +#endif + +#ifndef LOCK_WRITE +#define LOCK_WRITE 128 +#endif + +#ifndef LOCK_RW +#define LOCK_RW 192 +#endif + +size_t syscall_arg__scnprintf_flock(char *bf, size_t size, struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + const char *prefix = "LOCK_"; + int printed = 0, op = arg->val; + + if (op == 0) + return scnprintf(bf, size, "NONE"); +#define P_CMD(cmd) \ + if ((op & LOCK_##cmd) == LOCK_##cmd) { \ + printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #cmd); \ + op &= ~LOCK_##cmd; \ + } + + P_CMD(SH); + P_CMD(EX); + P_CMD(NB); + P_CMD(UN); + P_CMD(MAND); + P_CMD(RW); + P_CMD(READ); + P_CMD(WRITE); +#undef P_OP + + if (op) + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op); + + return printed; +} diff --git a/tools/perf/trace/beauty/fsconfig.sh b/tools/perf/trace/beauty/fsconfig.sh new file mode 100755 index 0000000000..bc6ef7bb7a --- /dev/null +++ b/tools/perf/trace/beauty/fsconfig.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +if [ $# -ne 1 ] ; then + linux_header_dir=tools/include/uapi/linux +else + linux_header_dir=$1 +fi + +linux_mount=${linux_header_dir}/mount.h + +printf "static const char *fsconfig_cmds[] = {\n" +ms='[[:space:]]*' +sed -nr "s/^${ms}FSCONFIG_([[:alnum:]_]+)${ms}=${ms}([[:digit:]]+)${ms},.*/\t[\2] = \"\1\",/p" \ + ${linux_mount} +printf "};\n" diff --git a/tools/perf/trace/beauty/fsmount.c b/tools/perf/trace/beauty/fsmount.c new file mode 100644 index 0000000000..30c8c082a3 --- /dev/null +++ b/tools/perf/trace/beauty/fsmount.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/fsmount.c + * + * Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" +#include <linux/log2.h> +#include <uapi/linux/mount.h> + +static size_t fsmount__scnprintf_attr_flags(unsigned long flags, char *bf, size_t size, bool show_prefix) +{ +#include "trace/beauty/generated/fsmount_arrays.c" + static DEFINE_STRARRAY(fsmount_attr_flags, "MOUNT_ATTR_"); + size_t printed = 0; + + if ((flags & ~MOUNT_ATTR__ATIME) != 0) + printed += strarray__scnprintf_flags(&strarray__fsmount_attr_flags, bf, size, show_prefix, flags); + + if ((flags & MOUNT_ATTR__ATIME) == MOUNT_ATTR_RELATIME) { + printed += scnprintf(bf + printed, size - printed, "%s%s%s", + printed ? "|" : "", show_prefix ? "MOUNT_ATTR_" : "", "RELATIME"); + } + + return printed; +} + +size_t syscall_arg__scnprintf_fsmount_attr_flags(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long flags = arg->val; + + return fsmount__scnprintf_attr_flags(flags, bf, size, arg->show_string_prefix); +} diff --git a/tools/perf/trace/beauty/fsmount.sh b/tools/perf/trace/beauty/fsmount.sh new file mode 100755 index 0000000000..cba8897a75 --- /dev/null +++ b/tools/perf/trace/beauty/fsmount.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +if [ $# -ne 1 ] ; then + linux_header_dir=tools/include/uapi/linux +else + linux_header_dir=$1 +fi + +linux_mount=${linux_header_dir}/mount.h + +# Remove MOUNT_ATTR_RELATIME as it is zeros, handle it a special way in the beautifier +# Only handle MOUNT_ATTR_ followed by a capital letter/num as __ is special case +# for things like MOUNT_ATTR__ATIME that is a mask for the possible ATIME handling +# bits. Special case it as well in the beautifier + +printf "static const char *fsmount_attr_flags[] = {\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MOUNT_ATTR_([[:alnum:]][[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*' +grep -E $regex ${linux_mount} | grep -v MOUNT_ATTR_RELATIME | \ + sed -r "s/$regex/\2 \1/g" | \ + xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/fspick.c b/tools/perf/trace/beauty/fspick.c new file mode 100644 index 0000000000..c402479c96 --- /dev/null +++ b/tools/perf/trace/beauty/fspick.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/fspick.c + * + * Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" +#include <linux/log2.h> + +static size_t fspick__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix) +{ +#include "trace/beauty/generated/fspick_arrays.c" + static DEFINE_STRARRAY(fspick_flags, "FSPICK_"); + + return strarray__scnprintf_flags(&strarray__fspick_flags, bf, size, show_prefix, flags); +} + +size_t syscall_arg__scnprintf_fspick_flags(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long flags = arg->val; + + return fspick__scnprintf_flags(flags, bf, size, arg->show_string_prefix); +} diff --git a/tools/perf/trace/beauty/fspick.sh b/tools/perf/trace/beauty/fspick.sh new file mode 100755 index 0000000000..1f088329b9 --- /dev/null +++ b/tools/perf/trace/beauty/fspick.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +if [ $# -ne 1 ] ; then + linux_header_dir=tools/include/uapi/linux +else + linux_header_dir=$1 +fi + +linux_mount=${linux_header_dir}/mount.h + +printf "static const char *fspick_flags[] = {\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+FSPICK_([[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*' +grep -E $regex ${linux_mount} | \ + sed -r "s/$regex/\2 \1/g" | \ + xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/futex_op.c b/tools/perf/trace/beauty/futex_op.c new file mode 100644 index 0000000000..0036515678 --- /dev/null +++ b/tools/perf/trace/beauty/futex_op.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: LGPL-2.1 +#include <linux/futex.h> + +#ifndef FUTEX_WAIT_BITSET +#define FUTEX_WAIT_BITSET 9 +#endif +#ifndef FUTEX_WAKE_BITSET +#define FUTEX_WAKE_BITSET 10 +#endif +#ifndef FUTEX_WAIT_REQUEUE_PI +#define FUTEX_WAIT_REQUEUE_PI 11 +#endif +#ifndef FUTEX_CMP_REQUEUE_PI +#define FUTEX_CMP_REQUEUE_PI 12 +#endif +#ifndef FUTEX_CLOCK_REALTIME +#define FUTEX_CLOCK_REALTIME 256 +#endif + +static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + const char *prefix = "FUTEX_"; + enum syscall_futex_args { + SCF_UADDR = (1 << 0), + SCF_OP = (1 << 1), + SCF_VAL = (1 << 2), + SCF_TIMEOUT = (1 << 3), + SCF_UADDR2 = (1 << 4), + SCF_VAL3 = (1 << 5), + }; + int op = arg->val; + int cmd = op & FUTEX_CMD_MASK; + size_t printed = 0; + + switch (cmd) { +#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, "%s%s", show_prefix ? prefix : "", #n); + P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break; + P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; + P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; + P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break; + P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break; + P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break; + P_FUTEX_OP(WAKE_OP); break; + P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; + P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; + P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break; + P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break; + P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break; + P_FUTEX_OP(WAIT_REQUEUE_PI); break; + default: printed = scnprintf(bf, size, "%#x", cmd); break; + } + + if (op & FUTEX_PRIVATE_FLAG) + printed += scnprintf(bf + printed, size - printed, "|%s%s", show_prefix ? prefix : "", "PRIVATE_FLAG"); + + if (op & FUTEX_CLOCK_REALTIME) + printed += scnprintf(bf + printed, size - printed, "|%s%s", show_prefix ? prefix : "", "CLOCK_REALTIME"); + + return printed; +} + +#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op diff --git a/tools/perf/trace/beauty/futex_val3.c b/tools/perf/trace/beauty/futex_val3.c new file mode 100644 index 0000000000..9114f76205 --- /dev/null +++ b/tools/perf/trace/beauty/futex_val3.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: LGPL-2.1 +#include <linux/futex.h> + +#ifndef FUTEX_BITSET_MATCH_ANY +#define FUTEX_BITSET_MATCH_ANY 0xffffffff +#endif + +static size_t syscall_arg__scnprintf_futex_val3(char *bf, size_t size, struct syscall_arg *arg) +{ + const char *prefix = "FUTEX_BITSET_"; + unsigned int bitset = arg->val; + + if (bitset == FUTEX_BITSET_MATCH_ANY) + return scnprintf(bf, size, "%s%s", arg->show_string_prefix ? prefix : "", "MATCH_ANY"); + + return scnprintf(bf, size, "%#xd", bitset); +} + +#define SCA_FUTEX_VAL3 syscall_arg__scnprintf_futex_val3 diff --git a/tools/perf/trace/beauty/include/linux/socket.h b/tools/perf/trace/beauty/include/linux/socket.h new file mode 100644 index 0000000000..39b74d83c7 --- /dev/null +++ b/tools/perf/trace/beauty/include/linux/socket.h @@ -0,0 +1,463 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_SOCKET_H +#define _LINUX_SOCKET_H + + +#include <asm/socket.h> /* arch-dependent defines */ +#include <linux/sockios.h> /* the SIOCxxx I/O controls */ +#include <linux/uio.h> /* iovec support */ +#include <linux/types.h> /* pid_t */ +#include <linux/compiler.h> /* __user */ +#include <uapi/linux/socket.h> + +struct file; +struct pid; +struct cred; +struct socket; +struct sock; +struct sk_buff; + +#define __sockaddr_check_size(size) \ + BUILD_BUG_ON(((size) > sizeof(struct __kernel_sockaddr_storage))) + +#ifdef CONFIG_PROC_FS +struct seq_file; +extern void socket_seq_show(struct seq_file *seq); +#endif + +typedef __kernel_sa_family_t sa_family_t; + +/* + * 1003.1g requires sa_family_t and that sa_data is char. + */ + +struct sockaddr { + sa_family_t sa_family; /* address family, AF_xxx */ + union { + char sa_data_min[14]; /* Minimum 14 bytes of protocol address */ + DECLARE_FLEX_ARRAY(char, sa_data); + }; +}; + +struct linger { + int l_onoff; /* Linger active */ + int l_linger; /* How long to linger for */ +}; + +#define sockaddr_storage __kernel_sockaddr_storage + +/* + * As we do 4.4BSD message passing we use a 4.4BSD message passing + * system, not 4.3. Thus msg_accrights(len) are now missing. They + * belong in an obscure libc emulation or the bin. + */ + +struct msghdr { + void *msg_name; /* ptr to socket address structure */ + int msg_namelen; /* size of socket address structure */ + + int msg_inq; /* output, data left in socket */ + + struct iov_iter msg_iter; /* data */ + + /* + * Ancillary data. msg_control_user is the user buffer used for the + * recv* side when msg_control_is_user is set, msg_control is the kernel + * buffer used for all other cases. + */ + union { + void *msg_control; + void __user *msg_control_user; + }; + bool msg_control_is_user : 1; + bool msg_get_inq : 1;/* return INQ after receive */ + unsigned int msg_flags; /* flags on received message */ + __kernel_size_t msg_controllen; /* ancillary data buffer length */ + struct kiocb *msg_iocb; /* ptr to iocb for async requests */ + struct ubuf_info *msg_ubuf; + int (*sg_from_iter)(struct sock *sk, struct sk_buff *skb, + struct iov_iter *from, size_t length); +}; + +struct user_msghdr { + void __user *msg_name; /* ptr to socket address structure */ + int msg_namelen; /* size of socket address structure */ + struct iovec __user *msg_iov; /* scatter/gather array */ + __kernel_size_t msg_iovlen; /* # elements in msg_iov */ + void __user *msg_control; /* ancillary data */ + __kernel_size_t msg_controllen; /* ancillary data buffer length */ + unsigned int msg_flags; /* flags on received message */ +}; + +/* For recvmmsg/sendmmsg */ +struct mmsghdr { + struct user_msghdr msg_hdr; + unsigned int msg_len; +}; + +/* + * POSIX 1003.1g - ancillary data object information + * Ancillary data consists of a sequence of pairs of + * (cmsghdr, cmsg_data[]) + */ + +struct cmsghdr { + __kernel_size_t cmsg_len; /* data byte count, including hdr */ + int cmsg_level; /* originating protocol */ + int cmsg_type; /* protocol-specific type */ +}; + +/* + * Ancillary data object information MACROS + * Table 5-14 of POSIX 1003.1g + */ + +#define __CMSG_NXTHDR(ctl, len, cmsg) __cmsg_nxthdr((ctl),(len),(cmsg)) +#define CMSG_NXTHDR(mhdr, cmsg) cmsg_nxthdr((mhdr), (cmsg)) + +#define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) ) + +#define CMSG_DATA(cmsg) \ + ((void *)(cmsg) + sizeof(struct cmsghdr)) +#define CMSG_USER_DATA(cmsg) \ + ((void __user *)(cmsg) + sizeof(struct cmsghdr)) +#define CMSG_SPACE(len) (sizeof(struct cmsghdr) + CMSG_ALIGN(len)) +#define CMSG_LEN(len) (sizeof(struct cmsghdr) + (len)) + +#define __CMSG_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr) ? \ + (struct cmsghdr *)(ctl) : \ + (struct cmsghdr *)NULL) +#define CMSG_FIRSTHDR(msg) __CMSG_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen) +#define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) && \ + (cmsg)->cmsg_len <= (unsigned long) \ + ((mhdr)->msg_controllen - \ + ((char *)(cmsg) - (char *)(mhdr)->msg_control))) +#define for_each_cmsghdr(cmsg, msg) \ + for (cmsg = CMSG_FIRSTHDR(msg); \ + cmsg; \ + cmsg = CMSG_NXTHDR(msg, cmsg)) + +/* + * Get the next cmsg header + * + * PLEASE, do not touch this function. If you think, that it is + * incorrect, grep kernel sources and think about consequences + * before trying to improve it. + * + * Now it always returns valid, not truncated ancillary object + * HEADER. But caller still MUST check, that cmsg->cmsg_len is + * inside range, given by msg->msg_controllen before using + * ancillary object DATA. --ANK (980731) + */ + +static inline struct cmsghdr * __cmsg_nxthdr(void *__ctl, __kernel_size_t __size, + struct cmsghdr *__cmsg) +{ + struct cmsghdr * __ptr; + + __ptr = (struct cmsghdr*)(((unsigned char *) __cmsg) + CMSG_ALIGN(__cmsg->cmsg_len)); + if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size) + return (struct cmsghdr *)0; + + return __ptr; +} + +static inline struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr *__cmsg) +{ + return __cmsg_nxthdr(__msg->msg_control, __msg->msg_controllen, __cmsg); +} + +static inline size_t msg_data_left(struct msghdr *msg) +{ + return iov_iter_count(&msg->msg_iter); +} + +/* "Socket"-level control message types: */ + +#define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */ +#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */ +#define SCM_SECURITY 0x03 /* rw: security label */ +#define SCM_PIDFD 0x04 /* ro: pidfd (int) */ + +struct ucred { + __u32 pid; + __u32 uid; + __u32 gid; +}; + +/* Supported address families. */ +#define AF_UNSPEC 0 +#define AF_UNIX 1 /* Unix domain sockets */ +#define AF_LOCAL 1 /* POSIX name for AF_UNIX */ +#define AF_INET 2 /* Internet IP Protocol */ +#define AF_AX25 3 /* Amateur Radio AX.25 */ +#define AF_IPX 4 /* Novell IPX */ +#define AF_APPLETALK 5 /* AppleTalk DDP */ +#define AF_NETROM 6 /* Amateur Radio NET/ROM */ +#define AF_BRIDGE 7 /* Multiprotocol bridge */ +#define AF_ATMPVC 8 /* ATM PVCs */ +#define AF_X25 9 /* Reserved for X.25 project */ +#define AF_INET6 10 /* IP version 6 */ +#define AF_ROSE 11 /* Amateur Radio X.25 PLP */ +#define AF_DECnet 12 /* Reserved for DECnet project */ +#define AF_NETBEUI 13 /* Reserved for 802.2LLC project*/ +#define AF_SECURITY 14 /* Security callback pseudo AF */ +#define AF_KEY 15 /* PF_KEY key management API */ +#define AF_NETLINK 16 +#define AF_ROUTE AF_NETLINK /* Alias to emulate 4.4BSD */ +#define AF_PACKET 17 /* Packet family */ +#define AF_ASH 18 /* Ash */ +#define AF_ECONET 19 /* Acorn Econet */ +#define AF_ATMSVC 20 /* ATM SVCs */ +#define AF_RDS 21 /* RDS sockets */ +#define AF_SNA 22 /* Linux SNA Project (nutters!) */ +#define AF_IRDA 23 /* IRDA sockets */ +#define AF_PPPOX 24 /* PPPoX sockets */ +#define AF_WANPIPE 25 /* Wanpipe API Sockets */ +#define AF_LLC 26 /* Linux LLC */ +#define AF_IB 27 /* Native InfiniBand address */ +#define AF_MPLS 28 /* MPLS */ +#define AF_CAN 29 /* Controller Area Network */ +#define AF_TIPC 30 /* TIPC sockets */ +#define AF_BLUETOOTH 31 /* Bluetooth sockets */ +#define AF_IUCV 32 /* IUCV sockets */ +#define AF_RXRPC 33 /* RxRPC sockets */ +#define AF_ISDN 34 /* mISDN sockets */ +#define AF_PHONET 35 /* Phonet sockets */ +#define AF_IEEE802154 36 /* IEEE802154 sockets */ +#define AF_CAIF 37 /* CAIF sockets */ +#define AF_ALG 38 /* Algorithm sockets */ +#define AF_NFC 39 /* NFC sockets */ +#define AF_VSOCK 40 /* vSockets */ +#define AF_KCM 41 /* Kernel Connection Multiplexor*/ +#define AF_QIPCRTR 42 /* Qualcomm IPC Router */ +#define AF_SMC 43 /* smc sockets: reserve number for + * PF_SMC protocol family that + * reuses AF_INET address family + */ +#define AF_XDP 44 /* XDP sockets */ +#define AF_MCTP 45 /* Management component + * transport protocol + */ + +#define AF_MAX 46 /* For now.. */ + +/* Protocol families, same as address families. */ +#define PF_UNSPEC AF_UNSPEC +#define PF_UNIX AF_UNIX +#define PF_LOCAL AF_LOCAL +#define PF_INET AF_INET +#define PF_AX25 AF_AX25 +#define PF_IPX AF_IPX +#define PF_APPLETALK AF_APPLETALK +#define PF_NETROM AF_NETROM +#define PF_BRIDGE AF_BRIDGE +#define PF_ATMPVC AF_ATMPVC +#define PF_X25 AF_X25 +#define PF_INET6 AF_INET6 +#define PF_ROSE AF_ROSE +#define PF_DECnet AF_DECnet +#define PF_NETBEUI AF_NETBEUI +#define PF_SECURITY AF_SECURITY +#define PF_KEY AF_KEY +#define PF_NETLINK AF_NETLINK +#define PF_ROUTE AF_ROUTE +#define PF_PACKET AF_PACKET +#define PF_ASH AF_ASH +#define PF_ECONET AF_ECONET +#define PF_ATMSVC AF_ATMSVC +#define PF_RDS AF_RDS +#define PF_SNA AF_SNA +#define PF_IRDA AF_IRDA +#define PF_PPPOX AF_PPPOX +#define PF_WANPIPE AF_WANPIPE +#define PF_LLC AF_LLC +#define PF_IB AF_IB +#define PF_MPLS AF_MPLS +#define PF_CAN AF_CAN +#define PF_TIPC AF_TIPC +#define PF_BLUETOOTH AF_BLUETOOTH +#define PF_IUCV AF_IUCV +#define PF_RXRPC AF_RXRPC +#define PF_ISDN AF_ISDN +#define PF_PHONET AF_PHONET +#define PF_IEEE802154 AF_IEEE802154 +#define PF_CAIF AF_CAIF +#define PF_ALG AF_ALG +#define PF_NFC AF_NFC +#define PF_VSOCK AF_VSOCK +#define PF_KCM AF_KCM +#define PF_QIPCRTR AF_QIPCRTR +#define PF_SMC AF_SMC +#define PF_XDP AF_XDP +#define PF_MCTP AF_MCTP +#define PF_MAX AF_MAX + +/* Maximum queue length specifiable by listen. */ +#define SOMAXCONN 4096 + +/* Flags we can use with send/ and recv. + Added those for 1003.1g not all are supported yet + */ + +#define MSG_OOB 1 +#define MSG_PEEK 2 +#define MSG_DONTROUTE 4 +#define MSG_TRYHARD 4 /* Synonym for MSG_DONTROUTE for DECnet */ +#define MSG_CTRUNC 8 +#define MSG_PROBE 0x10 /* Do not send. Only probe path f.e. for MTU */ +#define MSG_TRUNC 0x20 +#define MSG_DONTWAIT 0x40 /* Nonblocking io */ +#define MSG_EOR 0x80 /* End of record */ +#define MSG_WAITALL 0x100 /* Wait for a full request */ +#define MSG_FIN 0x200 +#define MSG_SYN 0x400 +#define MSG_CONFIRM 0x800 /* Confirm path validity */ +#define MSG_RST 0x1000 +#define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue */ +#define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */ +#define MSG_MORE 0x8000 /* Sender will send more */ +#define MSG_WAITFORONE 0x10000 /* recvmmsg(): block until 1+ packets avail */ +#define MSG_SENDPAGE_NOPOLICY 0x10000 /* sendpage() internal : do no apply policy */ +#define MSG_BATCH 0x40000 /* sendmmsg(): more messages coming */ +#define MSG_EOF MSG_FIN +#define MSG_NO_SHARED_FRAGS 0x80000 /* sendpage() internal : page frags are not shared */ +#define MSG_SENDPAGE_DECRYPTED 0x100000 /* sendpage() internal : page may carry + * plain text and require encryption + */ + +#define MSG_ZEROCOPY 0x4000000 /* Use user data in kernel path */ +#define MSG_SPLICE_PAGES 0x8000000 /* Splice the pages from the iterator in sendmsg() */ +#define MSG_FASTOPEN 0x20000000 /* Send data in TCP SYN */ +#define MSG_CMSG_CLOEXEC 0x40000000 /* Set close_on_exec for file + descriptor received through + SCM_RIGHTS */ +#if defined(CONFIG_COMPAT) +#define MSG_CMSG_COMPAT 0x80000000 /* This message needs 32 bit fixups */ +#else +#define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */ +#endif + +/* Flags to be cleared on entry by sendmsg and sendmmsg syscalls */ +#define MSG_INTERNAL_SENDMSG_FLAGS \ + (MSG_SPLICE_PAGES | MSG_SENDPAGE_NOPOLICY | MSG_SENDPAGE_DECRYPTED) + +/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */ +#define SOL_IP 0 +/* #define SOL_ICMP 1 No-no-no! Due to Linux :-) we cannot use SOL_ICMP=1 */ +#define SOL_TCP 6 +#define SOL_UDP 17 +#define SOL_IPV6 41 +#define SOL_ICMPV6 58 +#define SOL_SCTP 132 +#define SOL_UDPLITE 136 /* UDP-Lite (RFC 3828) */ +#define SOL_RAW 255 +#define SOL_IPX 256 +#define SOL_AX25 257 +#define SOL_ATALK 258 +#define SOL_NETROM 259 +#define SOL_ROSE 260 +#define SOL_DECNET 261 +#define SOL_X25 262 +#define SOL_PACKET 263 +#define SOL_ATM 264 /* ATM layer (cell level) */ +#define SOL_AAL 265 /* ATM Adaption Layer (packet level) */ +#define SOL_IRDA 266 +#define SOL_NETBEUI 267 +#define SOL_LLC 268 +#define SOL_DCCP 269 +#define SOL_NETLINK 270 +#define SOL_TIPC 271 +#define SOL_RXRPC 272 +#define SOL_PPPOL2TP 273 +#define SOL_BLUETOOTH 274 +#define SOL_PNPIPE 275 +#define SOL_RDS 276 +#define SOL_IUCV 277 +#define SOL_CAIF 278 +#define SOL_ALG 279 +#define SOL_NFC 280 +#define SOL_KCM 281 +#define SOL_TLS 282 +#define SOL_XDP 283 +#define SOL_MPTCP 284 +#define SOL_MCTP 285 +#define SOL_SMC 286 + +/* IPX options */ +#define IPX_TYPE 1 + +extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr); +extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); + +struct timespec64; +struct __kernel_timespec; +struct old_timespec32; + +struct scm_timestamping_internal { + struct timespec64 ts[3]; +}; + +extern void put_cmsg_scm_timestamping64(struct msghdr *msg, struct scm_timestamping_internal *tss); +extern void put_cmsg_scm_timestamping(struct msghdr *msg, struct scm_timestamping_internal *tss); + +/* The __sys_...msg variants allow MSG_CMSG_COMPAT iff + * forbid_cmsg_compat==false + */ +extern long __sys_recvmsg(int fd, struct user_msghdr __user *msg, + unsigned int flags, bool forbid_cmsg_compat); +extern long __sys_sendmsg(int fd, struct user_msghdr __user *msg, + unsigned int flags, bool forbid_cmsg_compat); +extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, + unsigned int vlen, unsigned int flags, + struct __kernel_timespec __user *timeout, + struct old_timespec32 __user *timeout32); +extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, + unsigned int vlen, unsigned int flags, + bool forbid_cmsg_compat); +extern long __sys_sendmsg_sock(struct socket *sock, struct msghdr *msg, + unsigned int flags); +extern long __sys_recvmsg_sock(struct socket *sock, struct msghdr *msg, + struct user_msghdr __user *umsg, + struct sockaddr __user *uaddr, + unsigned int flags); +extern int sendmsg_copy_msghdr(struct msghdr *msg, + struct user_msghdr __user *umsg, unsigned flags, + struct iovec **iov); +extern int recvmsg_copy_msghdr(struct msghdr *msg, + struct user_msghdr __user *umsg, unsigned flags, + struct sockaddr __user **uaddr, + struct iovec **iov); +extern int __copy_msghdr(struct msghdr *kmsg, + struct user_msghdr *umsg, + struct sockaddr __user **save_addr); + +/* helpers which do the actual work for syscalls */ +extern int __sys_recvfrom(int fd, void __user *ubuf, size_t size, + unsigned int flags, struct sockaddr __user *addr, + int __user *addr_len); +extern int __sys_sendto(int fd, void __user *buff, size_t len, + unsigned int flags, struct sockaddr __user *addr, + int addr_len); +extern struct file *do_accept(struct file *file, unsigned file_flags, + struct sockaddr __user *upeer_sockaddr, + int __user *upeer_addrlen, int flags); +extern int __sys_accept4(int fd, struct sockaddr __user *upeer_sockaddr, + int __user *upeer_addrlen, int flags); +extern int __sys_socket(int family, int type, int protocol); +extern struct file *__sys_socket_file(int family, int type, int protocol); +extern int __sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen); +extern int __sys_connect_file(struct file *file, struct sockaddr_storage *addr, + int addrlen, int file_flags); +extern int __sys_connect(int fd, struct sockaddr __user *uservaddr, + int addrlen); +extern int __sys_listen(int fd, int backlog); +extern int __sys_getsockname(int fd, struct sockaddr __user *usockaddr, + int __user *usockaddr_len); +extern int __sys_getpeername(int fd, struct sockaddr __user *usockaddr, + int __user *usockaddr_len); +extern int __sys_socketpair(int family, int type, int protocol, + int __user *usockvec); +extern int __sys_shutdown_sock(struct socket *sock, int how); +extern int __sys_shutdown(int fd, int how); +#endif /* _LINUX_SOCKET_H */ diff --git a/tools/perf/trace/beauty/ioctl.c b/tools/perf/trace/beauty/ioctl.c new file mode 100644 index 0000000000..e19eb6ea36 --- /dev/null +++ b/tools/perf/trace/beauty/ioctl.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/ioctl.c + * + * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" +#include <linux/kernel.h> + +/* + * FIXME: to support all arches we have to improve this, for + * now, to build on older systems without things like TIOCGEXCL, + * get it directly from our copy. + * + * Right now only x86 is being supported for beautifying ioctl args + * in 'perf trace', see tools/perf/trace/beauty/Build and builtin-trace.c + */ +#include <uapi/asm-generic/ioctls.h> + +static size_t ioctl__scnprintf_tty_cmd(int nr, int dir, char *bf, size_t size) +{ + static const char *ioctl_tty_cmd[] = { + [_IOC_NR(TCGETS)] = "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW", + "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL", "TIOCSCTTY", + "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI", "TIOCGWINSZ", "TIOCSWINSZ", + "TIOCMGET", "TIOCMBIS", "TIOCMBIC", "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", + "FIONREAD", "TIOCLINUX", "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", + "FIONBIO", "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", + [_IOC_NR(TIOCSBRK)] = "TIOCSBRK", "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", + "TCSETSW2", "TCSETSF2", "TIOCGRS48", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK", + "TIOCGDEV", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG", "TIOCVHANGUP", "TIOCGPKT", + "TIOCGPTLCK", [_IOC_NR(TIOCGEXCL)] = "TIOCGEXCL", "TIOCGPTPEER", + "TIOCGISO7816", "TIOCSISO7816", + [_IOC_NR(FIONCLEX)] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG", + "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS", + "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI", + "TIOCMIWAIT", "TIOCGICOUNT", }; + static DEFINE_STRARRAY(ioctl_tty_cmd, ""); + + if (nr < strarray__ioctl_tty_cmd.nr_entries && strarray__ioctl_tty_cmd.entries[nr] != NULL) + return scnprintf(bf, size, "%s", strarray__ioctl_tty_cmd.entries[nr]); + + return scnprintf(bf, size, "(%#x, %#x, %#x)", 'T', nr, dir); +} + +static size_t ioctl__scnprintf_drm_cmd(int nr, int dir, char *bf, size_t size) +{ +#include "trace/beauty/generated/ioctl/drm_ioctl_array.c" + static DEFINE_STRARRAY(drm_ioctl_cmds, ""); + + if (nr < strarray__drm_ioctl_cmds.nr_entries && strarray__drm_ioctl_cmds.entries[nr] != NULL) + return scnprintf(bf, size, "DRM_%s", strarray__drm_ioctl_cmds.entries[nr]); + + return scnprintf(bf, size, "(%#x, %#x, %#x)", 'd', nr, dir); +} + +static size_t ioctl__scnprintf_sndrv_pcm_cmd(int nr, int dir, char *bf, size_t size) +{ +#include "trace/beauty/generated/ioctl/sndrv_pcm_ioctl_array.c" + static DEFINE_STRARRAY(sndrv_pcm_ioctl_cmds, ""); + + if (nr < strarray__sndrv_pcm_ioctl_cmds.nr_entries && strarray__sndrv_pcm_ioctl_cmds.entries[nr] != NULL) + return scnprintf(bf, size, "SNDRV_PCM_%s", strarray__sndrv_pcm_ioctl_cmds.entries[nr]); + + return scnprintf(bf, size, "(%#x, %#x, %#x)", 'A', nr, dir); +} + +static size_t ioctl__scnprintf_sndrv_ctl_cmd(int nr, int dir, char *bf, size_t size) +{ +#include "trace/beauty/generated/ioctl/sndrv_ctl_ioctl_array.c" + static DEFINE_STRARRAY(sndrv_ctl_ioctl_cmds, ""); + + if (nr < strarray__sndrv_ctl_ioctl_cmds.nr_entries && strarray__sndrv_ctl_ioctl_cmds.entries[nr] != NULL) + return scnprintf(bf, size, "SNDRV_CTL_%s", strarray__sndrv_ctl_ioctl_cmds.entries[nr]); + + return scnprintf(bf, size, "(%#x, %#x, %#x)", 'U', nr, dir); +} + +static size_t ioctl__scnprintf_kvm_cmd(int nr, int dir, char *bf, size_t size) +{ +#include "trace/beauty/generated/ioctl/kvm_ioctl_array.c" + static DEFINE_STRARRAY(kvm_ioctl_cmds, ""); + + if (nr < strarray__kvm_ioctl_cmds.nr_entries && strarray__kvm_ioctl_cmds.entries[nr] != NULL) + return scnprintf(bf, size, "KVM_%s", strarray__kvm_ioctl_cmds.entries[nr]); + + return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAE, nr, dir); +} + +static size_t ioctl__scnprintf_vhost_virtio_cmd(int nr, int dir, char *bf, size_t size) +{ +#include "trace/beauty/generated/ioctl/vhost_virtio_ioctl_array.c" + static DEFINE_STRARRAY(vhost_virtio_ioctl_cmds, ""); + static DEFINE_STRARRAY(vhost_virtio_ioctl_read_cmds, ""); + struct strarray *s = (dir & _IOC_READ) ? &strarray__vhost_virtio_ioctl_read_cmds : &strarray__vhost_virtio_ioctl_cmds; + + if (nr < s->nr_entries && s->entries[nr] != NULL) + return scnprintf(bf, size, "VHOST_%s", s->entries[nr]); + + return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAF, nr, dir); +} + +static size_t ioctl__scnprintf_perf_cmd(int nr, int dir, char *bf, size_t size) +{ +#include "trace/beauty/generated/ioctl/perf_ioctl_array.c" + static DEFINE_STRARRAY(perf_ioctl_cmds, ""); + + if (nr < strarray__perf_ioctl_cmds.nr_entries && strarray__perf_ioctl_cmds.entries[nr] != NULL) + return scnprintf(bf, size, "PERF_%s", strarray__perf_ioctl_cmds.entries[nr]); + + return scnprintf(bf, size, "(%#x, %#x, %#x)", 0xAE, nr, dir); +} + +static size_t ioctl__scnprintf_usbdevfs_cmd(int nr, int dir, char *bf, size_t size) +{ +#include "trace/beauty/generated/ioctl/usbdevfs_ioctl_array.c" + static DEFINE_STRARRAY(usbdevfs_ioctl_cmds, ""); + + if (nr < strarray__usbdevfs_ioctl_cmds.nr_entries && strarray__usbdevfs_ioctl_cmds.entries[nr] != NULL) + return scnprintf(bf, size, "USBDEVFS_%s", strarray__usbdevfs_ioctl_cmds.entries[nr]); + + return scnprintf(bf, size, "(%c, %#x, %#x)", 'U', nr, dir); +} + +static size_t ioctl__scnprintf_cmd(unsigned long cmd, char *bf, size_t size, bool show_prefix) +{ + const char *prefix = "_IOC_"; + int dir = _IOC_DIR(cmd), + type = _IOC_TYPE(cmd), + nr = _IOC_NR(cmd), + sz = _IOC_SIZE(cmd); + int printed = 0; + static const struct ioctl_type { + int type; + size_t (*scnprintf)(int nr, int dir, char *bf, size_t size); + } ioctl_types[] = { /* Must be ordered by type */ + { .type = '$', .scnprintf = ioctl__scnprintf_perf_cmd, }, + ['A' - '$'] = { .type = 'A', .scnprintf = ioctl__scnprintf_sndrv_pcm_cmd, }, + ['T' - '$'] = { .type = 'T', .scnprintf = ioctl__scnprintf_tty_cmd, }, + ['U' - '$'] = { .type = 'U', .scnprintf = ioctl__scnprintf_sndrv_ctl_cmd, }, + ['d' - '$'] = { .type = 'd', .scnprintf = ioctl__scnprintf_drm_cmd, }, + [0xAE - '$'] = { .type = 0xAE, .scnprintf = ioctl__scnprintf_kvm_cmd, }, + [0xAF - '$'] = { .type = 0xAF, .scnprintf = ioctl__scnprintf_vhost_virtio_cmd, }, + }; + const int nr_types = ARRAY_SIZE(ioctl_types); + + if (type >= ioctl_types[0].type && type <= ioctl_types[nr_types - 1].type) { + const int index = type - ioctl_types[0].type; + + if (ioctl_types[index].scnprintf != NULL) + return ioctl_types[index].scnprintf(nr, dir, bf, size); + } + + printed += scnprintf(bf + printed, size - printed, "%c", '('); + + if (dir == _IOC_NONE) { + printed += scnprintf(bf + printed, size - printed, "%s%s", show_prefix ? prefix : "", "NONE"); + } else { + if (dir & _IOC_READ) + printed += scnprintf(bf + printed, size - printed, "%s%s", show_prefix ? prefix : "", "READ"); + if (dir & _IOC_WRITE) { + printed += scnprintf(bf + printed, size - printed, "%s%s%s", dir & _IOC_READ ? "|" : "", + show_prefix ? prefix : "", "WRITE"); + } + } + + return printed + scnprintf(bf + printed, size - printed, ", %#x, %#x, %#x)", type, nr, sz); +} + +#ifndef USB_DEVICE_MAJOR +#define USB_DEVICE_MAJOR 189 +#endif // USB_DEVICE_MAJOR + +size_t syscall_arg__scnprintf_ioctl_cmd(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long cmd = arg->val; + int fd = syscall_arg__val(arg, 0); + struct file *file = thread__files_entry(arg->thread, fd); + + if (file != NULL) { + if (file->dev_maj == USB_DEVICE_MAJOR) + return ioctl__scnprintf_usbdevfs_cmd(_IOC_NR(cmd), _IOC_DIR(cmd), bf, size); + } + + return ioctl__scnprintf_cmd(cmd, bf, size, arg->show_string_prefix); +} diff --git a/tools/perf/trace/beauty/kcmp.c b/tools/perf/trace/beauty/kcmp.c new file mode 100644 index 0000000000..9351f84390 --- /dev/null +++ b/tools/perf/trace/beauty/kcmp.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/kcmp.c + * + * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" +#include <linux/kernel.h> +#include <sys/types.h> +#include <machine.h> +#include <uapi/linux/kcmp.h> + +#include "trace/beauty/generated/kcmp_type_array.c" + +size_t syscall_arg__scnprintf_kcmp_idx(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long fd = arg->val; + int type = syscall_arg__val(arg, 2); + pid_t pid; + + if (type != KCMP_FILE) + return syscall_arg__scnprintf_long(bf, size, arg); + + pid = syscall_arg__val(arg, arg->idx == 3 ? 0 : 1); /* idx1 -> pid1, idx2 -> pid2 */ + return pid__scnprintf_fd(arg->trace, pid, fd, bf, size); +} + +static size_t kcmp__scnprintf_type(int type, char *bf, size_t size, bool show_prefix) +{ + static DEFINE_STRARRAY(kcmp_types, "KCMP_"); + return strarray__scnprintf(&strarray__kcmp_types, bf, size, "%d", show_prefix, type); +} + +size_t syscall_arg__scnprintf_kcmp_type(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long type = arg->val; + + if (type != KCMP_FILE) + arg->mask |= (1 << 3) | (1 << 4); /* Ignore idx1 and idx2 */ + + return kcmp__scnprintf_type(type, bf, size, arg->show_string_prefix); +} diff --git a/tools/perf/trace/beauty/kcmp_type.sh b/tools/perf/trace/beauty/kcmp_type.sh new file mode 100755 index 0000000000..5df9dcbd67 --- /dev/null +++ b/tools/perf/trace/beauty/kcmp_type.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ + +printf "static const char *kcmp_types[] = {\n" +regex='^[[:space:]]+(KCMP_(\w+)),' +grep -E $regex ${header_dir}/kcmp.h | grep -v KCMP_TYPES, | \ + sed -r "s/$regex/\1 \2/g" | \ + xargs printf "\t[%s]\t= \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/kvm_ioctl.sh b/tools/perf/trace/beauty/kvm_ioctl.sh new file mode 100755 index 0000000000..bd0efd45fa --- /dev/null +++ b/tools/perf/trace/beauty/kvm_ioctl.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ + +printf "static const char *kvm_ioctl_cmds[] = {\n" +regex='^#[[:space:]]*define[[:space:]]+KVM_(\w+)[[:space:]]+_IO[RW]*\([[:space:]]*KVMIO[[:space:]]*,[[:space:]]*(0x[[:xdigit:]]+).*' +grep -E $regex ${header_dir}/kvm.h | \ + sed -r "s/$regex/\2 \1/g" | \ + grep -E -v " ((ARM|PPC|S390)_|[GS]ET_(DEBUGREGS|PIT2|XSAVE|TSC_KHZ)|CREATE_SPAPR_TCE_64)" | \ + sort | xargs printf "\t[%s] = \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/madvise_behavior.sh b/tools/perf/trace/beauty/madvise_behavior.sh new file mode 100755 index 0000000000..c659c33bfc --- /dev/null +++ b/tools/perf/trace/beauty/madvise_behavior.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/asm-generic/ + +printf "static const char *madvise_advices[] = {\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MADV_([[:alnum:]_]+)[[:space:]]+([[:digit:]]+)[[:space:]]*.*' +grep -E $regex ${header_dir}/mman-common.h | \ + sed -r "s/$regex/\2 \1/g" | \ + sort -n | xargs printf "\t[%s] = \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/mmap.c b/tools/perf/trace/beauty/mmap.c new file mode 100644 index 0000000000..3c5e97b93d --- /dev/null +++ b/tools/perf/trace/beauty/mmap.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: LGPL-2.1 +#include <linux/log2.h> + +#include "trace/beauty/generated/mmap_prot_array.c" +static DEFINE_STRARRAY(mmap_prot, "PROT_"); + +static size_t mmap__scnprintf_prot(unsigned long prot, char *bf, size_t size, bool show_prefix) +{ + return strarray__scnprintf_flags(&strarray__mmap_prot, bf, size, show_prefix, prot); +} + +static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long prot = arg->val; + + if (prot == 0) + return scnprintf(bf, size, "%sNONE", arg->show_string_prefix ? strarray__mmap_prot.prefix : ""); + + return mmap__scnprintf_prot(prot, bf, size, arg->show_string_prefix); +} + +#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot + +#include "trace/beauty/generated/mmap_flags_array.c" +static DEFINE_STRARRAY(mmap_flags, "MAP_"); + +static size_t mmap__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix) +{ + return strarray__scnprintf_flags(&strarray__mmap_flags, bf, size, show_prefix, flags); +} + +static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, + struct syscall_arg *arg) +{ + unsigned long flags = arg->val; + + if (flags & MAP_ANONYMOUS) + arg->mask |= (1 << 4) | (1 << 5); /* Mask 4th ('fd') and 5th ('offset') args, ignored */ + + return mmap__scnprintf_flags(flags, bf, size, arg->show_string_prefix); +} + +#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags + +#include "trace/beauty/generated/mremap_flags_array.c" +static DEFINE_STRARRAY(mremap_flags, "MREMAP_"); + +static size_t mremap__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix) +{ + return strarray__scnprintf_flags(&strarray__mremap_flags, bf, size, show_prefix, flags); +} + +static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long flags = arg->val; + + if (!(flags & MREMAP_FIXED)) + arg->mask |= (1 << 5); /* Mask 5th ('new_address') args, ignored */ + + return mremap__scnprintf_flags(flags, bf, size, arg->show_string_prefix); +} + +#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags + +static size_t madvise__scnprintf_behavior(int behavior, char *bf, size_t size) +{ +#include "trace/beauty/generated/madvise_behavior_array.c" + static DEFINE_STRARRAY(madvise_advices, "MADV_"); + + if (behavior < strarray__madvise_advices.nr_entries && strarray__madvise_advices.entries[behavior] != NULL) + return scnprintf(bf, size, "MADV_%s", strarray__madvise_advices.entries[behavior]); + + return scnprintf(bf, size, "%#", behavior); +} + +static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, + struct syscall_arg *arg) +{ + return madvise__scnprintf_behavior(arg->val, bf, size); +} + +#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior diff --git a/tools/perf/trace/beauty/mmap_flags.sh b/tools/perf/trace/beauty/mmap_flags.sh new file mode 100755 index 0000000000..6ecdb3c5a9 --- /dev/null +++ b/tools/perf/trace/beauty/mmap_flags.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +if [ $# -ne 3 ] ; then + [ $# -eq 1 ] && hostarch=$1 || hostarch=`uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/` + linux_header_dir=tools/include/uapi/linux + header_dir=tools/include/uapi/asm-generic + arch_header_dir=tools/arch/${hostarch}/include/uapi/asm +else + linux_header_dir=$1 + header_dir=$2 + arch_header_dir=$3 +fi + +linux_mman=${linux_header_dir}/mman.h +arch_mman=${arch_header_dir}/mman.h + +# those in grep -E -vw are flags, we want just the bits + +printf "static const char *mmap_flags[] = {\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MAP_([[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*' +test -f ${arch_mman} && \ +grep -E -q $regex ${arch_mman} && \ +(grep -E $regex ${arch_mman} | \ + sed -r "s/$regex/\2 \1 \1 \1 \2/g" | \ + xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n#ifndef MAP_%s\n#define MAP_%s %s\n#endif\n") +grep -E -q $regex ${linux_mman} && \ +(grep -E $regex ${linux_mman} | \ + grep -E -vw 'MAP_(UNINITIALIZED|TYPE|SHARED_VALIDATE)' | \ + sed -r "s/$regex/\2 \1 \1 \1 \2/g" | \ + xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n#ifndef MAP_%s\n#define MAP_%s %s\n#endif\n") +( ! test -f ${arch_mman} || \ +grep -E -q '#[[:space:]]*include[[:space:]]+.*uapi/asm-generic/mman.*' ${arch_mman}) && +(grep -E $regex ${header_dir}/mman-common.h | \ + grep -E -vw 'MAP_(UNINITIALIZED|TYPE|SHARED_VALIDATE)' | \ + sed -r "s/$regex/\2 \1 \1 \1 \2/g" | \ + xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n#ifndef MAP_%s\n#define MAP_%s %s\n#endif\n") +( ! test -f ${arch_mman} || \ +grep -E -q '#[[:space:]]*include[[:space:]]+.*uapi/asm-generic/mman.h>.*' ${arch_mman}) && +(grep -E $regex ${header_dir}/mman.h | \ + sed -r "s/$regex/\2 \1 \1 \1 \2/g" | \ + xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n#ifndef MAP_%s\n#define MAP_%s %s\n#endif\n") +printf "};\n" diff --git a/tools/perf/trace/beauty/mmap_prot.sh b/tools/perf/trace/beauty/mmap_prot.sh new file mode 100755 index 0000000000..4436fcd6e8 --- /dev/null +++ b/tools/perf/trace/beauty/mmap_prot.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +if [ $# -ne 2 ] ; then + [ $# -eq 1 ] && hostarch=$1 || hostarch=`uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/` + asm_header_dir=tools/include/uapi/asm-generic + arch_header_dir=tools/arch/${hostarch}/include/uapi/asm +else + asm_header_dir=$1 + arch_header_dir=$2 +fi + +common_mman=${asm_header_dir}/mman-common.h +arch_mman=${arch_header_dir}/mman.h + +prefix="PROT" + +printf "static const char *mmap_prot[] = {\n" +regex=`printf '^[[:space:]]*#[[:space:]]*define[[:space:]]+%s_([[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*' ${prefix}` +( ! test -f ${arch_mman} \ +|| grep -E -q '#[[:space:]]*include[[:space:]]+.*uapi/asm-generic/mman.*' ${arch_mman}) && +(grep -E $regex ${common_mman} | \ + grep -E -vw PROT_NONE | \ + sed -r "s/$regex/\2 \1 \1 \1 \2/g" | \ + xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n#ifndef ${prefix}_%s\n#define ${prefix}_%s %s\n#endif\n") +test -f ${arch_mman} && grep -E -q $regex ${arch_mman} && +(grep -E $regex ${arch_mman} | \ + grep -E -vw PROT_NONE | \ + sed -r "s/$regex/\2 \1 \1 \1 \2/g" | \ + xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n#ifndef ${prefix}_%s\n#define ${prefix}_%s %s\n#endif\n") +printf "};\n" diff --git a/tools/perf/trace/beauty/mode_t.c b/tools/perf/trace/beauty/mode_t.c new file mode 100644 index 0000000000..29a8fadfb7 --- /dev/null +++ b/tools/perf/trace/beauty/mode_t.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: LGPL-2.1 +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +/* From include/linux/stat.h */ +#ifndef S_IRWXUGO +#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO) +#endif +#ifndef S_IALLUGO +#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO) +#endif +#ifndef S_IRUGO +#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) +#endif +#ifndef S_IWUGO +#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH) +#endif +#ifndef S_IXUGO +#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH) +#endif + +static size_t syscall_arg__scnprintf_mode_t(char *bf, size_t size, struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + const char *prefix = "S_"; + int printed = 0, mode = arg->val; + +#define P_MODE(n) \ + if ((mode & S_##n) == S_##n) { \ + printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ + mode &= ~S_##n; \ + } + + P_MODE(IALLUGO); + P_MODE(IRWXUGO); + P_MODE(IRUGO); + P_MODE(IWUGO); + P_MODE(IXUGO); + P_MODE(IFMT); + P_MODE(IFSOCK); + P_MODE(IFLNK); + P_MODE(IFREG); + P_MODE(IFBLK); + P_MODE(IFDIR); + P_MODE(IFCHR); + P_MODE(IFIFO); + P_MODE(ISUID); + P_MODE(ISGID); + P_MODE(ISVTX); + P_MODE(IRWXU); + P_MODE(IRUSR); + P_MODE(IWUSR); + P_MODE(IXUSR); + P_MODE(IRWXG); + P_MODE(IRGRP); + P_MODE(IWGRP); + P_MODE(IXGRP); + P_MODE(IRWXO); + P_MODE(IROTH); + P_MODE(IWOTH); + P_MODE(IXOTH); +#undef P_MODE + + if (mode) + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", mode); + + return printed; +} + +#define SCA_MODE_T syscall_arg__scnprintf_mode_t diff --git a/tools/perf/trace/beauty/mount_flags.c b/tools/perf/trace/beauty/mount_flags.c new file mode 100644 index 0000000000..10fb14cfaf --- /dev/null +++ b/tools/perf/trace/beauty/mount_flags.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/mount_flags.c + * + * Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" +#include <linux/compiler.h> +#include <linux/kernel.h> +#include <linux/log2.h> +#include <sys/mount.h> + +static size_t mount__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix) +{ +#include "trace/beauty/generated/mount_flags_array.c" + static DEFINE_STRARRAY(mount_flags, "MS_"); + + return strarray__scnprintf_flags(&strarray__mount_flags, bf, size, show_prefix, flags); +} + +unsigned long syscall_arg__mask_val_mount_flags(struct syscall_arg *arg __maybe_unused, unsigned long flags) +{ + // do_mount in fs/namespace.c: + /* + * Pre-0.97 versions of mount() didn't have a flags word. When the + * flags word was introduced its top half was required to have the + * magic value 0xC0ED, and this remained so until 2.4.0-test9. + * Therefore, if this magic number is present, it carries no + * information and must be discarded. + */ + if ((flags & MS_MGC_MSK) == MS_MGC_VAL) + flags &= ~MS_MGC_MSK; + + return flags; +} + +size_t syscall_arg__scnprintf_mount_flags(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long flags = arg->val; + + return mount__scnprintf_flags(flags, bf, size, arg->show_string_prefix); +} diff --git a/tools/perf/trace/beauty/mount_flags.sh b/tools/perf/trace/beauty/mount_flags.sh new file mode 100755 index 0000000000..730099a9a6 --- /dev/null +++ b/tools/perf/trace/beauty/mount_flags.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ + +printf "static const char *mount_flags[] = {\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MS_([[:alnum:]_]+)[[:space:]]+([[:digit:]]+)[[:space:]]*.*' +grep -E $regex ${header_dir}/mount.h | grep -E -v '(MSK|VERBOSE|MGC_VAL)\>' | \ + sed -r "s/$regex/\2 \2 \1/g" | sort -n | \ + xargs printf "\t[%s ? (ilog2(%s) + 1) : 0] = \"%s\",\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MS_([[:alnum:]_]+)[[:space:]]+\(1<<([[:digit:]]+)\)[[:space:]]*.*' +grep -E $regex ${header_dir}/mount.h | \ + sed -r "s/$regex/\2 \1/g" | \ + xargs printf "\t[%s + 1] = \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/move_mount.c b/tools/perf/trace/beauty/move_mount.c new file mode 100644 index 0000000000..78ed803954 --- /dev/null +++ b/tools/perf/trace/beauty/move_mount.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/move_mount.c + * + * Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" +#include <linux/log2.h> + +static size_t move_mount__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix) +{ +#include "trace/beauty/generated/move_mount_flags_array.c" + static DEFINE_STRARRAY(move_mount_flags, "MOVE_MOUNT_"); + + return strarray__scnprintf_flags(&strarray__move_mount_flags, bf, size, show_prefix, flags); +} + +size_t syscall_arg__scnprintf_move_mount_flags(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long flags = arg->val; + + return move_mount__scnprintf_flags(flags, bf, size, arg->show_string_prefix); +} diff --git a/tools/perf/trace/beauty/move_mount_flags.sh b/tools/perf/trace/beauty/move_mount_flags.sh new file mode 100755 index 0000000000..ce5e632d14 --- /dev/null +++ b/tools/perf/trace/beauty/move_mount_flags.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +if [ $# -ne 1 ] ; then + linux_header_dir=tools/include/uapi/linux +else + linux_header_dir=$1 +fi + +linux_mount=${linux_header_dir}/mount.h + +printf "static const char *move_mount_flags[] = {\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MOVE_MOUNT_([^_]+[[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*.*' +grep -E $regex ${linux_mount} | \ + sed -r "s/$regex/\2 \1/g" | \ + xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/mremap_flags.sh b/tools/perf/trace/beauty/mremap_flags.sh new file mode 100755 index 0000000000..4d01835018 --- /dev/null +++ b/tools/perf/trace/beauty/mremap_flags.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +if [ $# -ne 1 ] ; then + linux_header_dir=tools/include/uapi/linux +else + linux_header_dir=$1 +fi + +linux_mman=${linux_header_dir}/mman.h + +printf "static const char *mremap_flags[] = {\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MREMAP_([[:alnum:]_]+)[[:space:]]+((0x)?[[:xdigit:]]+)[[:space:]]*.*' +grep -E -q $regex ${linux_mman} && \ +(grep -E $regex ${linux_mman} | \ + sed -r "s/$regex/\2 \1 \1 \1 \2/g" | \ + xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n#ifndef MREMAP_%s\n#define MREMAP_%s %s\n#endif\n") +printf "};\n" diff --git a/tools/perf/trace/beauty/msg_flags.c b/tools/perf/trace/beauty/msg_flags.c new file mode 100644 index 0000000000..ed3ff969b5 --- /dev/null +++ b/tools/perf/trace/beauty/msg_flags.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: LGPL-2.1 +#include <sys/types.h> +#include <sys/socket.h> + +#ifndef MSG_PROBE +#define MSG_PROBE 0x10 +#endif +#ifndef MSG_WAITFORONE +#define MSG_WAITFORONE 0x10000 +#endif +#ifndef MSG_BATCH +#define MSG_BATCH 0x40000 +#endif +#ifndef MSG_ZEROCOPY +#define MSG_ZEROCOPY 0x4000000 +#endif +#ifndef MSG_SPLICE_PAGES +#define MSG_SPLICE_PAGES 0x8000000 +#endif +#ifndef MSG_FASTOPEN +#define MSG_FASTOPEN 0x20000000 +#endif +#ifndef MSG_CMSG_CLOEXEC +# define MSG_CMSG_CLOEXEC 0x40000000 +#endif + +static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size, + struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + const char *prefix = "MSG_"; + int printed = 0, flags = arg->val; + + if (flags == 0) + return scnprintf(bf, size, "NONE"); +#define P_MSG_FLAG(n) \ + if (flags & MSG_##n) { \ + printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ + flags &= ~MSG_##n; \ + } + + P_MSG_FLAG(OOB); + P_MSG_FLAG(PEEK); + P_MSG_FLAG(DONTROUTE); + P_MSG_FLAG(CTRUNC); + P_MSG_FLAG(PROBE); + P_MSG_FLAG(TRUNC); + P_MSG_FLAG(DONTWAIT); + P_MSG_FLAG(EOR); + P_MSG_FLAG(WAITALL); + P_MSG_FLAG(FIN); + P_MSG_FLAG(SYN); + P_MSG_FLAG(CONFIRM); + P_MSG_FLAG(RST); + P_MSG_FLAG(ERRQUEUE); + P_MSG_FLAG(NOSIGNAL); + P_MSG_FLAG(MORE); + P_MSG_FLAG(WAITFORONE); + P_MSG_FLAG(BATCH); + P_MSG_FLAG(ZEROCOPY); + P_MSG_FLAG(SPLICE_PAGES); + P_MSG_FLAG(FASTOPEN); + P_MSG_FLAG(CMSG_CLOEXEC); +#undef P_MSG_FLAG + + if (flags) + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); + + return printed; +} + +#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags diff --git a/tools/perf/trace/beauty/open_flags.c b/tools/perf/trace/beauty/open_flags.c new file mode 100644 index 0000000000..78f6566ef1 --- /dev/null +++ b/tools/perf/trace/beauty/open_flags.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: LGPL-2.1 +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#ifndef O_DIRECT +#define O_DIRECT 00040000 +#endif + +#ifndef O_DIRECTORY +#define O_DIRECTORY 00200000 +#endif + +#ifndef O_NOATIME +#define O_NOATIME 01000000 +#endif + +#ifndef O_TMPFILE +#define O_TMPFILE 020000000 +#endif + +#undef O_LARGEFILE +#define O_LARGEFILE 00100000 + +size_t open__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix) +{ + const char *prefix = "O_"; + int printed = 0; + + if ((flags & O_ACCMODE) == O_RDONLY) + printed = scnprintf(bf, size, "%s%s", show_prefix ? prefix : "", "RDONLY"); + if (flags == 0) + return printed; +#define P_FLAG(n) \ + if (flags & O_##n) { \ + printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ + flags &= ~O_##n; \ + } + + P_FLAG(RDWR); + P_FLAG(APPEND); + P_FLAG(ASYNC); + P_FLAG(CLOEXEC); + P_FLAG(CREAT); + P_FLAG(DIRECT); + P_FLAG(DIRECTORY); + P_FLAG(EXCL); + P_FLAG(LARGEFILE); + P_FLAG(NOFOLLOW); + P_FLAG(TMPFILE); + P_FLAG(NOATIME); + P_FLAG(NOCTTY); +#ifdef O_NONBLOCK + P_FLAG(NONBLOCK); +#elif O_NDELAY + P_FLAG(NDELAY); +#endif +#ifdef O_PATH + P_FLAG(PATH); +#endif +#ifdef O_DSYNC + if ((flags & O_SYNC) == O_SYNC) + printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", "SYNC"); + else { + P_FLAG(DSYNC); + } +#else + P_FLAG(SYNC); +#endif + P_FLAG(TRUNC); + P_FLAG(WRONLY); +#undef P_FLAG + + if (flags) + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); + + return printed; +} + +size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, struct syscall_arg *arg) +{ + int flags = arg->val; + + if (!(flags & O_CREAT)) + arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */ + + return open__scnprintf_flags(flags, bf, size, arg->show_string_prefix); +} diff --git a/tools/perf/trace/beauty/perf_event_open.c b/tools/perf/trace/beauty/perf_event_open.c new file mode 100644 index 0000000000..01ee15fe9d --- /dev/null +++ b/tools/perf/trace/beauty/perf_event_open.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: LGPL-2.1 +#ifndef PERF_FLAG_FD_NO_GROUP +# define PERF_FLAG_FD_NO_GROUP (1UL << 0) +#endif + +#ifndef PERF_FLAG_FD_OUTPUT +# define PERF_FLAG_FD_OUTPUT (1UL << 1) +#endif + +#ifndef PERF_FLAG_PID_CGROUP +# define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */ +#endif + +#ifndef PERF_FLAG_FD_CLOEXEC +# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */ +#endif + +static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size, + struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + const char *prefix = "PERF_"; + int printed = 0, flags = arg->val; + + if (flags == 0) + return 0; + +#define P_FLAG(n) \ + if (flags & PERF_FLAG_##n) { \ + printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ + flags &= ~PERF_FLAG_##n; \ + } + + P_FLAG(FD_NO_GROUP); + P_FLAG(FD_OUTPUT); + P_FLAG(PID_CGROUP); + P_FLAG(FD_CLOEXEC); +#undef P_FLAG + + if (flags) + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); + + return printed; +} + +#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags + +struct attr_fprintf_args { + size_t size, printed; + char *bf; + bool first; +}; + +static int attr__fprintf(FILE *fp __maybe_unused, const char *name, const char *val, void *priv) +{ + struct attr_fprintf_args *args = priv; + size_t printed = scnprintf(args->bf + args->printed , args->size - args->printed, "%s%s: %s", args->first ? "" : ", ", name, val); + + args->first = false; + args->printed += printed; + return printed; +} + +static size_t perf_event_attr___scnprintf(struct perf_event_attr *attr, char *bf, size_t size, bool show_zeros __maybe_unused) +{ + struct attr_fprintf_args args = { + .printed = scnprintf(bf, size, "{ "), + .size = size, + .first = true, + .bf = bf, + }; + + perf_event_attr__fprintf(stdout, attr, attr__fprintf, &args); + return args.printed + scnprintf(bf + args.printed, size - args.printed, " }"); +} + +static size_t syscall_arg__scnprintf_augmented_perf_event_attr(struct syscall_arg *arg, char *bf, size_t size) +{ + return perf_event_attr___scnprintf((void *)arg->augmented.args, bf, size, arg->trace->show_zeros); +} + +static size_t syscall_arg__scnprintf_perf_event_attr(char *bf, size_t size, struct syscall_arg *arg) +{ + if (arg->augmented.args) + return syscall_arg__scnprintf_augmented_perf_event_attr(arg, bf, size); + + return scnprintf(bf, size, "%#lx", arg->val); +} + +#define SCA_PERF_ATTR syscall_arg__scnprintf_perf_event_attr diff --git a/tools/perf/trace/beauty/perf_ioctl.sh b/tools/perf/trace/beauty/perf_ioctl.sh new file mode 100755 index 0000000000..06c2774f32 --- /dev/null +++ b/tools/perf/trace/beauty/perf_ioctl.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ + +printf "static const char *perf_ioctl_cmds[] = {\n" +regex='^#[[:space:]]*define[[:space:]]+PERF_EVENT_IOC_(\w+)[[:space:]]+_IO[RW]*[[:space:]]*\([[:space:]]*.\$.[[:space:]]*,[[:space:]]*([[:digit:]]+).*' +grep -E $regex ${header_dir}/perf_event.h | \ + sed -r "s/$regex/\2 \1/g" | \ + sort | xargs printf "\t[%s] = \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/pid.c b/tools/perf/trace/beauty/pid.c new file mode 100644 index 0000000000..8f9c9950f8 --- /dev/null +++ b/tools/perf/trace/beauty/pid.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: LGPL-2.1 + +size_t syscall_arg__scnprintf_pid(char *bf, size_t size, struct syscall_arg *arg) +{ + int pid = arg->val; + struct trace *trace = arg->trace; + size_t printed = scnprintf(bf, size, "%d", pid); + struct thread *thread = machine__findnew_thread(trace->host, pid, pid); + + if (thread != NULL) { + if (!thread__comm_set(thread)) + thread__set_comm_from_proc(thread); + + if (thread__comm_set(thread)) + printed += scnprintf(bf + printed, size - printed, + " (%s)", thread__comm_str(thread)); + thread__put(thread); + } + + return printed; +} diff --git a/tools/perf/trace/beauty/pkey_alloc.c b/tools/perf/trace/beauty/pkey_alloc.c new file mode 100644 index 0000000000..f9596ed02c --- /dev/null +++ b/tools/perf/trace/beauty/pkey_alloc.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/pkey_alloc.c + * + * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" +#include <linux/kernel.h> +#include <linux/log2.h> + +size_t strarray__scnprintf_flags(struct strarray *sa, char *bf, size_t size, bool show_prefix, unsigned long flags) +{ + int i, printed = 0; + + if (flags == 0) { + const char *s = sa->entries[0]; + if (s) + return scnprintf(bf, size, "%s%s", show_prefix ? sa->prefix : "", s); + return scnprintf(bf, size, "%d", 0); + } + + for (i = 1; i < sa->nr_entries; ++i) { + unsigned long bit = 1UL << (i - 1); + + if (!(flags & bit)) + continue; + + if (printed != 0) + printed += scnprintf(bf + printed, size - printed, "|"); + + if (sa->entries[i] != NULL) + printed += scnprintf(bf + printed, size - printed, "%s%s", show_prefix ? sa->prefix : "", sa->entries[i]); + else + printed += scnprintf(bf + printed, size - printed, "0x%#", bit); + } + + return printed; +} + +static size_t pkey_alloc__scnprintf_access_rights(int access_rights, char *bf, size_t size, bool show_prefix) +{ +#include "trace/beauty/generated/pkey_alloc_access_rights_array.c" + static DEFINE_STRARRAY(pkey_alloc_access_rights, "PKEY_"); + + return strarray__scnprintf_flags(&strarray__pkey_alloc_access_rights, bf, size, show_prefix, access_rights); +} + +size_t syscall_arg__scnprintf_pkey_alloc_access_rights(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long cmd = arg->val; + + return pkey_alloc__scnprintf_access_rights(cmd, bf, size, arg->show_string_prefix); +} diff --git a/tools/perf/trace/beauty/pkey_alloc_access_rights.sh b/tools/perf/trace/beauty/pkey_alloc_access_rights.sh new file mode 100755 index 0000000000..74da888bcd --- /dev/null +++ b/tools/perf/trace/beauty/pkey_alloc_access_rights.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/asm-generic/ + +printf "static const char *pkey_alloc_access_rights[] = {\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+PKEY_([[:alnum:]_]+)[[:space:]]+(0x[[:xdigit:]]+)[[:space:]]*' +grep -E $regex ${header_dir}/mman-common.h | \ + sed -r "s/$regex/\2 \2 \1/g" | \ + sort | xargs printf "\t[%s ? (ilog2(%s) + 1) : 0] = \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/prctl.c b/tools/perf/trace/beauty/prctl.c new file mode 100644 index 0000000000..6fe5ad5f5d --- /dev/null +++ b/tools/perf/trace/beauty/prctl.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/prctl.c + * + * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" +#include <linux/kernel.h> +#include <uapi/linux/prctl.h> + +#include "trace/beauty/generated/prctl_option_array.c" + +DEFINE_STRARRAY(prctl_options, "PR_"); + +static size_t prctl__scnprintf_option(int option, char *bf, size_t size, bool show_prefix) +{ + return strarray__scnprintf(&strarray__prctl_options, bf, size, "%d", show_prefix, option); +} + +static size_t prctl__scnprintf_set_mm(int option, char *bf, size_t size, bool show_prefix) +{ + static DEFINE_STRARRAY(prctl_set_mm_options, "PR_SET_MM_"); + return strarray__scnprintf(&strarray__prctl_set_mm_options, bf, size, "%d", show_prefix, option); +} + +size_t syscall_arg__scnprintf_prctl_arg2(char *bf, size_t size, struct syscall_arg *arg) +{ + int option = syscall_arg__val(arg, 0); + + if (option == PR_SET_MM) + return prctl__scnprintf_set_mm(arg->val, bf, size, arg->show_string_prefix); + /* + * We still don't grab the contents of pointers on entry or exit, + * so just print them as hex numbers + */ + if (option == PR_SET_NAME) + return syscall_arg__scnprintf_hex(bf, size, arg); + + return syscall_arg__scnprintf_long(bf, size, arg); +} + +size_t syscall_arg__scnprintf_prctl_arg3(char *bf, size_t size, struct syscall_arg *arg) +{ + int option = syscall_arg__val(arg, 0); + + if (option == PR_SET_MM) + return syscall_arg__scnprintf_hex(bf, size, arg); + + return syscall_arg__scnprintf_long(bf, size, arg); +} + +size_t syscall_arg__scnprintf_prctl_option(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long option = arg->val; + enum { + SPO_ARG2 = (1 << 1), + SPO_ARG3 = (1 << 2), + SPO_ARG4 = (1 << 3), + SPO_ARG5 = (1 << 4), + SPO_ARG6 = (1 << 5), + }; + const u8 all_but2 = SPO_ARG3 | SPO_ARG4 | SPO_ARG5 | SPO_ARG6; + const u8 all = SPO_ARG2 | all_but2; + const u8 masks[] = { + [PR_GET_DUMPABLE] = all, + [PR_SET_DUMPABLE] = all_but2, + [PR_SET_NAME] = all_but2, + [PR_GET_CHILD_SUBREAPER] = all_but2, + [PR_SET_CHILD_SUBREAPER] = all_but2, + [PR_GET_SECUREBITS] = all, + [PR_SET_SECUREBITS] = all_but2, + [PR_SET_MM] = SPO_ARG4 | SPO_ARG5 | SPO_ARG6, + [PR_GET_PDEATHSIG] = all, + [PR_SET_PDEATHSIG] = all_but2, + }; + + if (option < ARRAY_SIZE(masks)) + arg->mask |= masks[option]; + + return prctl__scnprintf_option(option, bf, size, arg->show_string_prefix); +} diff --git a/tools/perf/trace/beauty/prctl_option.sh b/tools/perf/trace/beauty/prctl_option.sh new file mode 100755 index 0000000000..8059342ca4 --- /dev/null +++ b/tools/perf/trace/beauty/prctl_option.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ + +printf "static const char *prctl_options[] = {\n" +regex='^#define[[:space:]]{1}PR_(\w+)[[:space:]]*([[:xdigit:]]+)([[:space:]]*\/.*)?$' +grep -E $regex ${header_dir}/prctl.h | grep -v PR_SET_PTRACER | \ + sed -r "s/$regex/\2 \1/g" | \ + sort -n | xargs printf "\t[%s] = \"%s\",\n" +printf "};\n" + +printf "static const char *prctl_set_mm_options[] = {\n" +regex='^#[[:space:]]+define[[:space:]]+PR_SET_MM_(\w+)[[:space:]]*([[:digit:]]+).*' +grep -E $regex ${header_dir}/prctl.h | \ + sed -r "s/$regex/\2 \1/g" | \ + sort -n | xargs printf "\t[%s] = \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/rename_flags.sh b/tools/perf/trace/beauty/rename_flags.sh new file mode 100755 index 0000000000..94bf7f45d2 --- /dev/null +++ b/tools/perf/trace/beauty/rename_flags.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> +# SPDX-License-Identifier: LGPL-2.1 + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ + +fs_header=${header_dir}/fs.h + +printf "static const char *rename_flags[] = {\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+RENAME_([[:alnum:]_]+)[[:space:]]+\(1[[:space:]]*<<[[:space:]]*([[:xdigit:]]+)[[:space:]]*\)[[:space:]]*.*' +grep -E -q $regex ${fs_header} && \ +(grep -E $regex ${fs_header} | \ + sed -r "s/$regex/\2 \1/g" | \ + xargs printf "\t[%d + 1] = \"%s\",\n") +printf "};\n" diff --git a/tools/perf/trace/beauty/renameat.c b/tools/perf/trace/beauty/renameat.c new file mode 100644 index 0000000000..852d2e2718 --- /dev/null +++ b/tools/perf/trace/beauty/renameat.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: LGPL-2.1 +// Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + +#include "trace/beauty/beauty.h" + +static size_t renameat2__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix) +{ +#include "trace/beauty/generated/rename_flags_array.c" + static DEFINE_STRARRAY(rename_flags, "RENAME_"); + + return strarray__scnprintf_flags(&strarray__rename_flags, bf, size, show_prefix, flags); +} + +size_t syscall_arg__scnprintf_renameat2_flags(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long flags = arg->val; + return renameat2__scnprintf_flags(flags, bf, size, arg->show_string_prefix); +} diff --git a/tools/perf/trace/beauty/sched_policy.c b/tools/perf/trace/beauty/sched_policy.c new file mode 100644 index 0000000000..68aa59eeed --- /dev/null +++ b/tools/perf/trace/beauty/sched_policy.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: LGPL-2.1 +#include <sched.h> + +/* + * Not defined anywhere else, probably, just to make sure we + * catch future flags + */ +#define SCHED_POLICY_MASK 0xff + +#ifndef SCHED_DEADLINE +#define SCHED_DEADLINE 6 +#endif +#ifndef SCHED_RESET_ON_FORK +#define SCHED_RESET_ON_FORK 0x40000000 +#endif + +static size_t syscall_arg__scnprintf_sched_policy(char *bf, size_t size, + struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + const char *prefix = "SCHED_"; + const char *policies[] = { + "NORMAL", "FIFO", "RR", "BATCH", "ISO", "IDLE", "DEADLINE", + }; + size_t printed; + int policy = arg->val, + flags = policy & ~SCHED_POLICY_MASK; + + policy &= SCHED_POLICY_MASK; + if (policy <= SCHED_DEADLINE) + printed = scnprintf(bf, size, "%s%s", show_prefix ? prefix : "", policies[policy]); + else + printed = scnprintf(bf, size, "%#x", policy); + +#define P_POLICY_FLAG(n) \ + if (flags & SCHED_##n) { \ + printed += scnprintf(bf + printed, size - printed, "|%s%s", show_prefix ? prefix : "", #n); \ + flags &= ~SCHED_##n; \ + } + + P_POLICY_FLAG(RESET_ON_FORK); +#undef P_POLICY_FLAG + + if (flags) + printed += scnprintf(bf + printed, size - printed, "|%#x", flags); + + return printed; +} + +#define SCA_SCHED_POLICY syscall_arg__scnprintf_sched_policy diff --git a/tools/perf/trace/beauty/seccomp.c b/tools/perf/trace/beauty/seccomp.c new file mode 100644 index 0000000000..637722e279 --- /dev/null +++ b/tools/perf/trace/beauty/seccomp.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: LGPL-2.1 +#ifndef SECCOMP_SET_MODE_STRICT +#define SECCOMP_SET_MODE_STRICT 0 +#endif +#ifndef SECCOMP_SET_MODE_FILTER +#define SECCOMP_SET_MODE_FILTER 1 +#endif + +static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + const char *prefix = "SECCOMP_SET_MODE_"; + int op = arg->val; + size_t printed = 0; + + switch (op) { +#define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, "%s%s", show_prefix ? prefix : "", #n); break + P_SECCOMP_SET_MODE_OP(STRICT); + P_SECCOMP_SET_MODE_OP(FILTER); +#undef P_SECCOMP_SET_MODE_OP + default: printed = scnprintf(bf, size, "%#x", op); break; + } + + return printed; +} + +#define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op + +#ifndef SECCOMP_FILTER_FLAG_TSYNC +#define SECCOMP_FILTER_FLAG_TSYNC 1 +#endif + +static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size, + struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + const char *prefix = "SECCOMP_FILTER_FLAG_"; + int printed = 0, flags = arg->val; + +#define P_FLAG(n) \ + if (flags & SECCOMP_FILTER_FLAG_##n) { \ + printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ + flags &= ~SECCOMP_FILTER_FLAG_##n; \ + } + + P_FLAG(TSYNC); +#undef P_FLAG + + if (flags) + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); + + return printed; +} + +#define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags diff --git a/tools/perf/trace/beauty/signum.c b/tools/perf/trace/beauty/signum.c new file mode 100644 index 0000000000..21220c5650 --- /dev/null +++ b/tools/perf/trace/beauty/signum.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: LGPL-2.1 +#include <signal.h> + +static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + const char *prefix = "SIG"; + int sig = arg->val; + + switch (sig) { +#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, "%s%s", show_prefix ? prefix : "", #n) + P_SIGNUM(HUP); + P_SIGNUM(INT); + P_SIGNUM(QUIT); + P_SIGNUM(ILL); + P_SIGNUM(TRAP); + P_SIGNUM(ABRT); + P_SIGNUM(BUS); + P_SIGNUM(FPE); + P_SIGNUM(KILL); + P_SIGNUM(USR1); + P_SIGNUM(SEGV); + P_SIGNUM(USR2); + P_SIGNUM(PIPE); + P_SIGNUM(ALRM); + P_SIGNUM(TERM); + P_SIGNUM(CHLD); + P_SIGNUM(CONT); + P_SIGNUM(STOP); + P_SIGNUM(TSTP); + P_SIGNUM(TTIN); + P_SIGNUM(TTOU); + P_SIGNUM(URG); + P_SIGNUM(XCPU); + P_SIGNUM(XFSZ); + P_SIGNUM(VTALRM); + P_SIGNUM(PROF); + P_SIGNUM(WINCH); + P_SIGNUM(IO); + P_SIGNUM(PWR); + P_SIGNUM(SYS); +#ifdef SIGEMT + P_SIGNUM(EMT); +#endif +#ifdef SIGSTKFLT + P_SIGNUM(STKFLT); +#endif +#ifdef SIGSWI + P_SIGNUM(SWI); +#endif + default: break; + } + + return scnprintf(bf, size, "%#x", sig); +} + +#define SCA_SIGNUM syscall_arg__scnprintf_signum diff --git a/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh b/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh new file mode 100755 index 0000000000..e0803b9575 --- /dev/null +++ b/tools/perf/trace/beauty/sndrv_ctl_ioctl.sh @@ -0,0 +1,9 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/ + +printf "static const char *sndrv_ctl_ioctl_cmds[] = {\n" +grep "^#define[\t ]\+SNDRV_CTL_IOCTL_" $header_dir/asound.h | \ + sed -r 's/^#define +SNDRV_CTL_IOCTL_([A-Z0-9_]+)[\t ]+_IO[RW]*\( *.U., *(0x[[:xdigit:]]+),?.*/\t[\2] = \"\1\",/g' +printf "};\n" diff --git a/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh b/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh new file mode 100755 index 0000000000..7a464a7bf9 --- /dev/null +++ b/tools/perf/trace/beauty/sndrv_pcm_ioctl.sh @@ -0,0 +1,9 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/sound/ + +printf "static const char *sndrv_pcm_ioctl_cmds[] = {\n" +grep "^#define[\t ]\+SNDRV_PCM_IOCTL_" $header_dir/asound.h | \ + sed -r 's/^#define +SNDRV_PCM_IOCTL_([A-Z0-9_]+)[\t ]+_IO[RW]*\( *.A., *(0x[[:xdigit:]]+),?.*/\t[\2] = \"\1\",/g' +printf "};\n" diff --git a/tools/perf/trace/beauty/sockaddr.c b/tools/perf/trace/beauty/sockaddr.c new file mode 100644 index 0000000000..2e0e867c0c --- /dev/null +++ b/tools/perf/trace/beauty/sockaddr.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: LGPL-2.1 +// Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + +#include "trace/beauty/beauty.h" +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/un.h> +#include <arpa/inet.h> + +#include "trace/beauty/generated/sockaddr.c" +DEFINE_STRARRAY(socket_families, "PF_"); + +static size_t af_inet__scnprintf(struct sockaddr *sa, char *bf, size_t size) +{ + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + char tmp[16]; + return scnprintf(bf, size, ", port: %d, addr: %s", ntohs(sin->sin_port), + inet_ntop(sin->sin_family, &sin->sin_addr, tmp, sizeof(tmp))); +} + +static size_t af_inet6__scnprintf(struct sockaddr *sa, char *bf, size_t size) +{ + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + u32 flowinfo = ntohl(sin6->sin6_flowinfo); + char tmp[512]; + size_t printed = scnprintf(bf, size, ", port: %d, addr: %s", ntohs(sin6->sin6_port), + inet_ntop(sin6->sin6_family, &sin6->sin6_addr, tmp, sizeof(tmp))); + if (flowinfo != 0) + printed += scnprintf(bf + printed, size - printed, ", flowinfo: %lu", flowinfo); + if (sin6->sin6_scope_id != 0) + printed += scnprintf(bf + printed, size - printed, ", scope_id: %lu", sin6->sin6_scope_id); + + return printed; +} + +static size_t af_local__scnprintf(struct sockaddr *sa, char *bf, size_t size) +{ + struct sockaddr_un *sun = (struct sockaddr_un *)sa; + return scnprintf(bf, size, ", path: %s", sun->sun_path); +} + +static size_t (*af_scnprintfs[])(struct sockaddr *sa, char *bf, size_t size) = { + [AF_LOCAL] = af_local__scnprintf, + [AF_INET] = af_inet__scnprintf, + [AF_INET6] = af_inet6__scnprintf, +}; + +static size_t syscall_arg__scnprintf_augmented_sockaddr(struct syscall_arg *arg, char *bf, size_t size) +{ + struct sockaddr *sa = (struct sockaddr *)arg->augmented.args; + char family[32]; + size_t printed; + + strarray__scnprintf(&strarray__socket_families, family, sizeof(family), "%d", arg->show_string_prefix, sa->sa_family); + printed = scnprintf(bf, size, "{ .family: %s", family); + + if (sa->sa_family < ARRAY_SIZE(af_scnprintfs) && af_scnprintfs[sa->sa_family]) + printed += af_scnprintfs[sa->sa_family](sa, bf + printed, size - printed); + + return printed + scnprintf(bf + printed, size - printed, " }"); +} + +size_t syscall_arg__scnprintf_sockaddr(char *bf, size_t size, struct syscall_arg *arg) +{ + if (arg->augmented.args) + return syscall_arg__scnprintf_augmented_sockaddr(arg, bf, size); + + return scnprintf(bf, size, "%#lx", arg->val); +} diff --git a/tools/perf/trace/beauty/sockaddr.sh b/tools/perf/trace/beauty/sockaddr.sh new file mode 100755 index 0000000000..a59827ea14 --- /dev/null +++ b/tools/perf/trace/beauty/sockaddr.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +# This one uses a copy from the kernel sources headers that is in a +# place used just for these tools/perf/beauty/ usage, we shouldn't not +# put it in tools/include/linux otherwise they would be used in the +# normal compiler building process and would drag needless stuff from the +# kernel. + +# When what these scripts need is already in tools/include/ then use it, +# otherwise grab and check the copy from the kernel sources just for these +# string table building scripts. + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/perf/trace/beauty/include/linux/ + +printf "static const char *socket_families[] = {\n" +# #define AF_LOCAL 1 /* POSIX name for AF_UNIX */ +regex='^#define[[:space:]]+AF_(\w+)[[:space:]]+([[:digit:]]+).*' + +grep -E $regex ${header_dir}/socket.h | \ + sed -r "s/$regex/\2 \1/g" | \ + xargs printf "\t[%s] = \"%s\",\n" | \ + grep -E -v "\"(UNIX|MAX)\"" +printf "};\n" diff --git a/tools/perf/trace/beauty/socket.c b/tools/perf/trace/beauty/socket.c new file mode 100644 index 0000000000..b0870c7b48 --- /dev/null +++ b/tools/perf/trace/beauty/socket.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/socket.c + * + * Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" +#include <sys/types.h> +#include <sys/socket.h> + +#include "trace/beauty/generated/socket.c" + +static size_t socket__scnprintf_ipproto(int protocol, char *bf, size_t size, bool show_prefix) +{ + static DEFINE_STRARRAY(socket_ipproto, "IPPROTO_"); + + return strarray__scnprintf(&strarray__socket_ipproto, bf, size, "%d", show_prefix, protocol); +} + +size_t syscall_arg__scnprintf_socket_protocol(char *bf, size_t size, struct syscall_arg *arg) +{ + int domain = syscall_arg__val(arg, 0); + + if (domain == AF_INET || domain == AF_INET6) + return socket__scnprintf_ipproto(arg->val, bf, size, arg->show_string_prefix); + + return syscall_arg__scnprintf_int(bf, size, arg); +} + +static size_t socket__scnprintf_level(int level, char *bf, size_t size, bool show_prefix) +{ +#if defined(__alpha__) || defined(__hppa__) || defined(__mips__) || defined(__sparc__) + const int sol_socket = 0xffff; +#else + const int sol_socket = 1; +#endif + if (level == sol_socket) + return scnprintf(bf, size, "%sSOCKET", show_prefix ? "SOL_" : ""); + + return strarray__scnprintf(&strarray__socket_level, bf, size, "%d", show_prefix, level); +} + +size_t syscall_arg__scnprintf_socket_level(char *bf, size_t size, struct syscall_arg *arg) +{ + return socket__scnprintf_level(arg->val, bf, size, arg->show_string_prefix); +} diff --git a/tools/perf/trace/beauty/socket.sh b/tools/perf/trace/beauty/socket.sh new file mode 100755 index 0000000000..8bc7ba6220 --- /dev/null +++ b/tools/perf/trace/beauty/socket.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +if [ $# -gt 0 ] ; then + uapi_header_dir=$1 + beauty_header_dir=$2 +else + uapi_header_dir=tools/include/uapi/linux/ + beauty_header_dir=tools/perf/trace/beauty/include/linux/ +fi + +printf "static const char *socket_ipproto[] = {\n" +ipproto_regex='^[[:space:]]+IPPROTO_(\w+)[[:space:]]+=[[:space:]]+([[:digit:]]+),.*' + +grep -E $ipproto_regex ${uapi_header_dir}/in.h | \ + sed -r "s/$ipproto_regex/\2 \1/g" | \ + sort -n | xargs printf "\t[%s] = \"%s\",\n" +printf "};\n\n" + +printf "static const char *socket_level[] = {\n" +socket_level_regex='^#define[[:space:]]+SOL_(\w+)[[:space:]]+([[:digit:]]+)([[:space:]]+\/.*)?' + +grep -E $socket_level_regex ${beauty_header_dir}/socket.h | \ + sed -r "s/$socket_level_regex/\2 \1/g" | \ + sort -n | xargs printf "\t[%s] = \"%s\",\n" +printf "};\n\n" + +printf 'DEFINE_STRARRAY(socket_level, "SOL_");\n' diff --git a/tools/perf/trace/beauty/socket_type.c b/tools/perf/trace/beauty/socket_type.c new file mode 100644 index 0000000000..bed8d5761c --- /dev/null +++ b/tools/perf/trace/beauty/socket_type.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: LGPL-2.1 +#include <sys/types.h> +#include <sys/socket.h> + +#ifndef SOCK_DCCP +# define SOCK_DCCP 6 +#endif + +#ifndef SOCK_CLOEXEC +# define SOCK_CLOEXEC 02000000 +#endif + +#ifndef SOCK_NONBLOCK +# define SOCK_NONBLOCK 00004000 +#endif + +#ifndef SOCK_TYPE_MASK +#define SOCK_TYPE_MASK 0xf +#endif + +static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size, struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + const char *prefix = "SOCK_"; + size_t printed; + int type = arg->val, + flags = type & ~SOCK_TYPE_MASK; + + type &= SOCK_TYPE_MASK; + /* + * Can't use a strarray, MIPS may override for ABI reasons. + */ + switch (type) { +#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, "%s%s", show_prefix ? prefix : "", #n); break; + P_SK_TYPE(STREAM); + P_SK_TYPE(DGRAM); + P_SK_TYPE(RAW); + P_SK_TYPE(RDM); + P_SK_TYPE(SEQPACKET); + P_SK_TYPE(DCCP); + P_SK_TYPE(PACKET); +#undef P_SK_TYPE + default: + printed = scnprintf(bf, size, "%#x", type); + } + +#define P_SK_FLAG(n) \ + if (flags & SOCK_##n) { \ + printed += scnprintf(bf + printed, size - printed, "|%s", #n); \ + flags &= ~SOCK_##n; \ + } + + P_SK_FLAG(CLOEXEC); + P_SK_FLAG(NONBLOCK); +#undef P_SK_FLAG + + if (flags) + printed += scnprintf(bf + printed, size - printed, "|%#x", flags); + + return printed; +} + +#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type diff --git a/tools/perf/trace/beauty/statx.c b/tools/perf/trace/beauty/statx.c new file mode 100644 index 0000000000..5f5320f7c6 --- /dev/null +++ b/tools/perf/trace/beauty/statx.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/statx.c + * + * Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" +#include <linux/kernel.h> +#include <sys/types.h> +#include <uapi/linux/fcntl.h> +#include <uapi/linux/stat.h> + +size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + const char *prefix = "AT_"; + int printed = 0, flags = arg->val; + + if (flags == 0) + return scnprintf(bf, size, "%s%s", show_prefix ? "AT_STATX_" : "", "SYNC_AS_STAT"); +#define P_FLAG(n) \ + if (flags & AT_##n) { \ + printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ + flags &= ~AT_##n; \ + } + + P_FLAG(SYMLINK_NOFOLLOW); + P_FLAG(REMOVEDIR); + P_FLAG(SYMLINK_FOLLOW); + P_FLAG(NO_AUTOMOUNT); + P_FLAG(EMPTY_PATH); + P_FLAG(STATX_FORCE_SYNC); + P_FLAG(STATX_DONT_SYNC); + +#undef P_FLAG + + if (flags) + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); + + return printed; +} + +size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + const char *prefix = "STATX_"; + int printed = 0, flags = arg->val; + +#define P_FLAG(n) \ + if (flags & STATX_##n) { \ + printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ + flags &= ~STATX_##n; \ + } + + P_FLAG(TYPE); + P_FLAG(MODE); + P_FLAG(NLINK); + P_FLAG(UID); + P_FLAG(GID); + P_FLAG(ATIME); + P_FLAG(MTIME); + P_FLAG(CTIME); + P_FLAG(INO); + P_FLAG(SIZE); + P_FLAG(BLOCKS); + P_FLAG(BTIME); + P_FLAG(MNT_ID); + P_FLAG(DIOALIGN); + +#undef P_FLAG + + if (flags) + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); + + return printed; +} diff --git a/tools/perf/trace/beauty/sync_file_range.c b/tools/perf/trace/beauty/sync_file_range.c new file mode 100644 index 0000000000..1c425f0404 --- /dev/null +++ b/tools/perf/trace/beauty/sync_file_range.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/sync_file_range.c + * + * Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" +#include <linux/log2.h> +#include <uapi/linux/fs.h> + +static size_t sync_file_range__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix) +{ +#include "trace/beauty/generated/sync_file_range_arrays.c" + static DEFINE_STRARRAY(sync_file_range_flags, "SYNC_FILE_RANGE_"); + size_t printed = 0; + + if ((flags & SYNC_FILE_RANGE_WRITE_AND_WAIT) == SYNC_FILE_RANGE_WRITE_AND_WAIT) { + printed += scnprintf(bf + printed, size - printed, "%s%s", show_prefix ? "SYNC_FILE_RANGE_" : "", "WRITE_AND_WAIT"); + flags &= ~SYNC_FILE_RANGE_WRITE_AND_WAIT; + } + + return printed + strarray__scnprintf_flags(&strarray__sync_file_range_flags, bf + printed, size - printed, show_prefix, flags); +} + +size_t syscall_arg__scnprintf_sync_file_range_flags(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long flags = arg->val; + + return sync_file_range__scnprintf_flags(flags, bf, size, arg->show_string_prefix); +} diff --git a/tools/perf/trace/beauty/sync_file_range.sh b/tools/perf/trace/beauty/sync_file_range.sh new file mode 100755 index 0000000000..90bf633be8 --- /dev/null +++ b/tools/perf/trace/beauty/sync_file_range.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +if [ $# -ne 1 ] ; then + linux_header_dir=tools/include/uapi/linux +else + linux_header_dir=$1 +fi + +linux_fs=${linux_header_dir}/fs.h + +printf "static const char *sync_file_range_flags[] = {\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+SYNC_FILE_RANGE_([[:alnum:]_]+)[[:space:]]+([[:xdigit:]]+)[[:space:]]*.*' +grep -E $regex ${linux_fs} | \ + sed -r "s/$regex/\2 \1/g" | \ + xargs printf "\t[ilog2(%s) + 1] = \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/timespec.c b/tools/perf/trace/beauty/timespec.c new file mode 100644 index 0000000000..e1a61f092a --- /dev/null +++ b/tools/perf/trace/beauty/timespec.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: LGPL-2.1 +// Copyright (C) 2022, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + +#include "trace/beauty/beauty.h" +#include <inttypes.h> +#include <time.h> + +static size_t syscall_arg__scnprintf_augmented_timespec(struct syscall_arg *arg, char *bf, size_t size) +{ + struct timespec *ts = (struct timespec *)arg->augmented.args; + + return scnprintf(bf, size, "{ .tv_sec: %" PRIu64 ", .tv_nsec: %" PRIu64 " }", ts->tv_sec, ts->tv_nsec); +} + +size_t syscall_arg__scnprintf_timespec(char *bf, size_t size, struct syscall_arg *arg) +{ + if (arg->augmented.args) + return syscall_arg__scnprintf_augmented_timespec(arg, bf, size); + + return scnprintf(bf, size, "%#lx", arg->val); +} diff --git a/tools/perf/trace/beauty/tracepoints/Build b/tools/perf/trace/beauty/tracepoints/Build new file mode 100644 index 0000000000..e35087fdd1 --- /dev/null +++ b/tools/perf/trace/beauty/tracepoints/Build @@ -0,0 +1,2 @@ +perf-y += x86_irq_vectors.o +perf-y += x86_msr.o diff --git a/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.c b/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.c new file mode 100644 index 0000000000..8eb9bc8534 --- /dev/null +++ b/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/x86_irq_vectors.c + * + * Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" + +#include "trace/beauty/generated/x86_arch_irq_vectors_array.c" + +static DEFINE_STRARRAY(x86_irq_vectors, "_VECTOR"); + +static size_t x86_irq_vectors__scnprintf(unsigned long vector, char *bf, size_t size, bool show_prefix) +{ + return strarray__scnprintf_suffix(&strarray__x86_irq_vectors, bf, size, "%#x", show_prefix, vector); +} + +size_t syscall_arg__scnprintf_x86_irq_vectors(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long vector = arg->val; + + return x86_irq_vectors__scnprintf(vector, bf, size, arg->show_string_prefix); +} + +bool syscall_arg__strtoul_x86_irq_vectors(char *bf, size_t size, struct syscall_arg *arg __maybe_unused, u64 *ret) +{ + return strarray__strtoul(&strarray__x86_irq_vectors, bf, size, ret); +} diff --git a/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh b/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh new file mode 100755 index 0000000000..87dc68c7de --- /dev/null +++ b/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh @@ -0,0 +1,27 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 +# (C) 2019, Arnaldo Carvalho de Melo <acme@redhat.com> + +if [ $# -ne 1 ] ; then + arch_x86_header_dir=tools/arch/x86/include/asm/ +else + arch_x86_header_dir=$1 +fi + +x86_irq_vectors=${arch_x86_header_dir}/irq_vectors.h + +# FIRST_EXTERNAL_VECTOR is not that useful, find what is its number +# and then replace whatever is using it and that is useful, which at +# the time of writing of this script was: 0x20. + +first_external_regex='^#define[[:space:]]+FIRST_EXTERNAL_VECTOR[[:space:]]+(0x[[:xdigit:]]+)$' +first_external_vector=$(grep -E ${first_external_regex} ${x86_irq_vectors} | sed -r "s/${first_external_regex}/\1/g") + +printf "static const char *x86_irq_vectors[] = {\n" +regex='^#define[[:space:]]+([[:alnum:]_]+)_VECTOR[[:space:]]+(0x[[:xdigit:]]+)$' +sed -r "s/FIRST_EXTERNAL_VECTOR/${first_external_vector}/g" ${x86_irq_vectors} | \ +grep -E ${regex} | \ + sed -r "s/${regex}/\2 \1/g" | sort -n | \ + xargs printf "\t[%s] = \"%s\",\n" +printf "};\n\n" + diff --git a/tools/perf/trace/beauty/tracepoints/x86_msr.c b/tools/perf/trace/beauty/tracepoints/x86_msr.c new file mode 100644 index 0000000000..6b8f129579 --- /dev/null +++ b/tools/perf/trace/beauty/tracepoints/x86_msr.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * trace/beauty/x86_msr.c + * + * Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + */ + +#include "trace/beauty/beauty.h" + +#include "trace/beauty/generated/x86_arch_MSRs_array.c" + +static DEFINE_STRARRAY(x86_MSRs, "MSR_"); +static DEFINE_STRARRAY_OFFSET(x86_64_specific_MSRs, "MSR_", x86_64_specific_MSRs_offset); +static DEFINE_STRARRAY_OFFSET(x86_AMD_V_KVM_MSRs, "MSR_", x86_AMD_V_KVM_MSRs_offset); + +static struct strarray *x86_MSRs_tables[] = { + &strarray__x86_MSRs, + &strarray__x86_64_specific_MSRs, + &strarray__x86_AMD_V_KVM_MSRs, +}; + +static DEFINE_STRARRAYS(x86_MSRs_tables); + +static size_t x86_MSR__scnprintf(unsigned long msr, char *bf, size_t size, bool show_prefix) +{ + return strarrays__scnprintf(&strarrays__x86_MSRs_tables, bf, size, "%#x", show_prefix, msr); +} + +size_t syscall_arg__scnprintf_x86_MSR(char *bf, size_t size, struct syscall_arg *arg) +{ + unsigned long flags = arg->val; + + return x86_MSR__scnprintf(flags, bf, size, arg->show_string_prefix); +} + +bool syscall_arg__strtoul_x86_MSR(char *bf, size_t size, struct syscall_arg *arg __maybe_unused, u64 *ret) +{ + return strarrays__strtoul(&strarrays__x86_MSRs_tables, bf, size, ret); +} diff --git a/tools/perf/trace/beauty/tracepoints/x86_msr.sh b/tools/perf/trace/beauty/tracepoints/x86_msr.sh new file mode 100755 index 0000000000..fa3c4418e8 --- /dev/null +++ b/tools/perf/trace/beauty/tracepoints/x86_msr.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +if [ $# -ne 1 ] ; then + arch_x86_header_dir=tools/arch/x86/include/asm/ +else + arch_x86_header_dir=$1 +fi + +x86_msr_index=${arch_x86_header_dir}/msr-index.h + +# Support all later, with some hash table, for now chop off +# Just the ones starting with 0x00000 so as to have a simple +# array. + +printf "static const char * const x86_MSRs[] = {\n" +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MSR_([[:alnum:]][[:alnum:]_]+)[[:space:]]+(0x00000[[:xdigit:]]+)[[:space:]]*.*' +grep -E $regex ${x86_msr_index} | grep -E -v 'MSR_(ATOM|P[46]|IA32_(TSC_DEADLINE|UCODE_REV)|IDT_FCR4)' | \ + sed -r "s/$regex/\2 \1/g" | sort -n | \ + xargs printf "\t[%s] = \"%s\",\n" +printf "};\n\n" + +# Remove MSR_K6_WHCR, clashes with MSR_LSTAR +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MSR_([[:alnum:]][[:alnum:]_]+)[[:space:]]+(0xc0000[[:xdigit:]]+)[[:space:]]*.*' +printf "#define x86_64_specific_MSRs_offset " +grep -E $regex ${x86_msr_index} | sed -r "s/$regex/\2/g" | sort -n | head -1 +printf "static const char * const x86_64_specific_MSRs[] = {\n" +grep -E $regex ${x86_msr_index} | \ + sed -r "s/$regex/\2 \1/g" | grep -E -vw 'K6_WHCR' | sort -n | \ + xargs printf "\t[%s - x86_64_specific_MSRs_offset] = \"%s\",\n" +printf "};\n\n" + +regex='^[[:space:]]*#[[:space:]]*define[[:space:]]+MSR_([[:alnum:]][[:alnum:]_]+)[[:space:]]+(0xc0010[[:xdigit:]]+)[[:space:]]*.*' +printf "#define x86_AMD_V_KVM_MSRs_offset " +grep -E $regex ${x86_msr_index} | sed -r "s/$regex/\2/g" | sort -n | head -1 +printf "static const char * const x86_AMD_V_KVM_MSRs[] = {\n" +grep -E $regex ${x86_msr_index} | \ + sed -r "s/$regex/\2 \1/g" | sort -n | \ + xargs printf "\t[%s - x86_AMD_V_KVM_MSRs_offset] = \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/usbdevfs_ioctl.sh b/tools/perf/trace/beauty/usbdevfs_ioctl.sh new file mode 100755 index 0000000000..b39cfb3720 --- /dev/null +++ b/tools/perf/trace/beauty/usbdevfs_ioctl.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ + +# also as: +# #define USBDEVFS_CONNINFO_EX(len) _IOC(_IOC_READ, 'U', 32, len) + +printf "static const char *usbdevfs_ioctl_cmds[] = {\n" +regex="^#[[:space:]]*define[[:space:]]+USBDEVFS_(\w+)(\(\w+\))?[[:space:]]+_IO[CWR]{0,2}\([[:space:]]*(_IOC_\w+,[[:space:]]*)?'U'[[:space:]]*,[[:space:]]*([[:digit:]]+).*" +grep -E "$regex" ${header_dir}/usbdevice_fs.h | grep -E -v 'USBDEVFS_\w+32[[:space:]]' | \ + sed -r "s/$regex/\4 \1/g" | \ + sort | xargs printf "\t[%s] = \"%s\",\n" +printf "};\n\n" +printf "#if 0\n" +printf "static const char *usbdevfs_ioctl_32_cmds[] = {\n" +regex="^#[[:space:]]*define[[:space:]]+USBDEVFS_(\w+)[[:space:]]+_IO[WR]{0,2}\([[:space:]]*'U'[[:space:]]*,[[:space:]]*([[:digit:]]+).*" +grep -E $regex ${header_dir}/usbdevice_fs.h | grep -E 'USBDEVFS_\w+32[[:space:]]' | \ + sed -r "s/$regex/\2 \1/g" | \ + sort | xargs printf "\t[%s] = \"%s\",\n" +printf "};\n" +printf "#endif\n" diff --git a/tools/perf/trace/beauty/vhost_virtio_ioctl.sh b/tools/perf/trace/beauty/vhost_virtio_ioctl.sh new file mode 100755 index 0000000000..2dd0a3b1f5 --- /dev/null +++ b/tools/perf/trace/beauty/vhost_virtio_ioctl.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1 + +[ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/ + +printf "static const char *vhost_virtio_ioctl_cmds[] = {\n" +regex='^#[[:space:]]*define[[:space:]]+VHOST_(\w+)[[:space:]]+_IOW?\([[:space:]]*VHOST_VIRTIO[[:space:]]*,[[:space:]]*(0x[[:xdigit:]]+).*' +grep -E $regex ${header_dir}/vhost.h | \ + sed -r "s/$regex/\2 \1/g" | \ + sort | xargs printf "\t[%s] = \"%s\",\n" +printf "};\n" + +printf "static const char *vhost_virtio_ioctl_read_cmds[] = {\n" +regex='^#[[:space:]]*define[[:space:]]+VHOST_(\w+)[[:space:]]+_IOW?R\([[:space:]]*VHOST_VIRTIO[[:space:]]*,[[:space:]]*(0x[[:xdigit:]]+).*' +grep -E $regex ${header_dir}/vhost.h | \ + sed -r "s/$regex/\2 \1/g" | \ + sort | xargs printf "\t[%s] = \"%s\",\n" +printf "};\n" diff --git a/tools/perf/trace/beauty/waitid_options.c b/tools/perf/trace/beauty/waitid_options.c new file mode 100644 index 0000000000..d4d10b33ba --- /dev/null +++ b/tools/perf/trace/beauty/waitid_options.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: LGPL-2.1 +#include <sys/types.h> +#include <sys/wait.h> + +static size_t syscall_arg__scnprintf_waitid_options(char *bf, size_t size, + struct syscall_arg *arg) +{ + bool show_prefix = arg->show_string_prefix; + const char *prefix = "W"; + int printed = 0, options = arg->val; + +#define P_OPTION(n) \ + if (options & W##n) { \ + printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \ + options &= ~W##n; \ + } + + P_OPTION(NOHANG); + P_OPTION(UNTRACED); + P_OPTION(CONTINUED); +#undef P_OPTION + + if (options) + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", options); + + return printed; +} + +#define SCA_WAITID_OPTIONS syscall_arg__scnprintf_waitid_options diff --git a/tools/perf/trace/beauty/x86_arch_prctl.sh b/tools/perf/trace/beauty/x86_arch_prctl.sh new file mode 100755 index 0000000000..b1596df251 --- /dev/null +++ b/tools/perf/trace/beauty/x86_arch_prctl.sh @@ -0,0 +1,27 @@ +#!/bin/sh +# Copyright (C) 2018, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> +# SPDX-License-Identifier: LGPL-2.1 + +[ $# -eq 1 ] && x86_header_dir=$1 || x86_header_dir=tools/arch/x86/include/uapi/asm/ + +prctl_arch_header=${x86_header_dir}/prctl.h + +print_range () { + idx=$1 + prefix=$2 + first_entry=$3 + + printf "#define x86_arch_prctl_codes_%d_offset %s\n" $idx $first_entry + printf "static const char *x86_arch_prctl_codes_%d[] = {\n" $idx + regex=`printf '^[[:space:]]*#[[:space:]]*define[[:space:]]+ARCH_([[:alnum:]_]+)[[:space:]]+(%s[[:xdigit:]]+).*' ${prefix}` + fmt="\t[%#x - ${first_entry}]= \"%s\",\n" + grep -E -q $regex ${prctl_arch_header} && \ + (grep -E $regex ${prctl_arch_header} | \ + sed -r "s/$regex/\2 \1/g" | \ + xargs printf "$fmt") + printf "};\n\n" +} + +print_range 1 0x1 0x1001 +print_range 2 0x2 0x2001 +print_range 3 0x4 0x4001 diff --git a/tools/perf/trace/strace/groups/file b/tools/perf/trace/strace/groups/file new file mode 100644 index 0000000000..722e25d200 --- /dev/null +++ b/tools/perf/trace/strace/groups/file @@ -0,0 +1,20 @@ +access +chmod +creat +execve +faccessat +getcwd +lstat +mkdir +open +openat +quotactl +read +readlink +rename +rmdir +stat +statfs +symlink +unlink +write diff --git a/tools/perf/trace/strace/groups/string b/tools/perf/trace/strace/groups/string new file mode 100644 index 0000000000..c87129a3e3 --- /dev/null +++ b/tools/perf/trace/strace/groups/string @@ -0,0 +1,65 @@ +access +acct +add_key +chdir +chmod +chown +chroot +creat +delete_module +execve +execveat +faccessat +fchmodat +fchownat +fgetxattr +finit_module +fremovexattr +fsetxattr +futimesat +getxattr +inotify_add_watch +lchown +lgetxattr +link +linkat +listxattr +llistxattr +lremovexattr +lsetxattr +lstat +memfd_create +mkdir +mkdirat +mknod +mknodat +mq_open +mq_timedsend +mq_unlink +name_to_handle_at +newfstatat +open +openat +pivot_root +pwrite64 +quotactl +readlink +readlinkat +removexattr +rename +renameat +renameat2 +request_key +rmdir +setxattr +stat +statfs +statx +swapoff +swapon +symlink +symlinkat +truncate +unlink +unlinkat +utimensat |