From 7adb5a2f9e3ec8caeac841e8275834aac6d1e12f Mon Sep 17 00:00:00 2001 From: Eugene Syromyatnikov Date: Tue, 15 May 2018 18:45:28 +0200 Subject: [PATCH] Implement PERF_EVENT_IOC_* decoding * perf.c (fetch_perf_event_attr, print_perf_event_attr): Remove "static" qualifier. * defs.h (fetch_perf_event_attr, print_perf_event_attr): New declarations. * perf_event_struct.h (struct perf_event_query_bpf): New type definition. * perf_ioctl.c: New file. * Makefile.am (strace_SOURCES): Add it. * xlat/perf_ioctl_cmds.in: New file. * xlat/perf_ioctl_flags.in: Likewise. * ioctl.c (ioctl_decode) : Call perf_ioctl. * tests/gen_tests.in (ioctl_perf): New test. * tests/ioctl_perf.c: New file. * tests/pure_executables.list: ioctl_perf. * tests/.gitignore: Likewise. Co-Authored-by: Dmitry V. Levin --- Makefile.am | 1 + defs.h | 5 + ioctl.c | 2 + perf.c | 4 +- perf_event_struct.h | 6 + perf_ioctl.c | 153 ++++++++++++++++++++++++ tests/.gitignore | 1 + tests/gen_tests.in | 1 + tests/ioctl_perf.c | 232 ++++++++++++++++++++++++++++++++++++ tests/pure_executables.list | 1 + xlat/perf_ioctl_cmds.in | 12 ++ xlat/perf_ioctl_flags.in | 1 + 12 files changed, 417 insertions(+), 2 deletions(-) create mode 100644 perf_ioctl.c create mode 100644 tests/ioctl_perf.c create mode 100644 xlat/perf_ioctl_cmds.in create mode 100644 xlat/perf_ioctl_flags.in diff --git a/Makefile.am b/Makefile.am index 5f3eb288..76895517 100644 --- a/Makefile.am +++ b/Makefile.am @@ -235,6 +235,7 @@ strace_SOURCES = \ pathtrace.c \ perf.c \ perf_event_struct.h \ + perf_ioctl.c \ personality.c \ pkeys.c \ poll.c \ diff --git a/defs.h b/defs.h index b401cccb..f21604ee 100644 --- a/defs.h +++ b/defs.h @@ -845,6 +845,11 @@ print_struct_statfs(struct tcb *, kernel_ulong_t addr); extern void print_struct_statfs64(struct tcb *, kernel_ulong_t addr, kernel_ulong_t size); +extern int +fetch_perf_event_attr(struct tcb *const tcp, const kernel_ulong_t addr); +extern void +print_perf_event_attr(struct tcb *const tcp, const kernel_ulong_t addr); + extern void print_ifindex(unsigned int); extern void print_bpf_filter_code(const uint16_t code, bool extended); diff --git a/ioctl.c b/ioctl.c index 9d2f9d52..93fb5263 100644 --- a/ioctl.c +++ b/ioctl.c @@ -255,6 +255,8 @@ ioctl_decode(struct tcb *tcp) const kernel_ulong_t arg = tcp->u_arg[2]; switch (_IOC_TYPE(code)) { + case '$': + return perf_ioctl(tcp, code, arg); #if defined(ALPHA) || defined(POWERPC) case 'f': { int ret = file_ioctl(tcp, code, arg); diff --git a/perf.c b/perf.c index b37f54a2..e66ca4d7 100644 --- a/perf.c +++ b/perf.c @@ -60,7 +60,7 @@ free_pea_desc(void *pea_desc_ptr) free(desc); } -static int +int fetch_perf_event_attr(struct tcb *const tcp, const kernel_ulong_t addr) { struct pea_desc *desc; @@ -117,7 +117,7 @@ fetch_perf_event_attr(struct tcb *const tcp, const kernel_ulong_t addr) printxval_search(xlat, x, dflt); \ } while (0) -static void +void print_perf_event_attr(struct tcb *const tcp, const kernel_ulong_t addr) { static const char *precise_ip_desc[] = { diff --git a/perf_event_struct.h b/perf_event_struct.h index a75b88ad..57d245bf 100644 --- a/perf_event_struct.h +++ b/perf_event_struct.h @@ -71,4 +71,10 @@ struct perf_event_attr { /* End of ver 5 - 112 bytes */ }; +struct perf_event_query_bpf { + uint32_t ids_len; + uint32_t prog_cnt; + uint32_t ids[0]; +}; + #endif /* !STRACE_LINUX_PERF_EVENT_STRUCT_H */ diff --git a/perf_ioctl.c b/perf_ioctl.c new file mode 100644 index 00000000..d1b99038 --- /dev/null +++ b/perf_ioctl.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2018 The strace developers. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "defs.h" + +#include + +#include "perf_event_struct.h" + +#define XLAT_MACROS_ONLY +# include "xlat/perf_ioctl_cmds.h" +#undef XLAT_MACROS_ONLY + +#include "xlat/perf_ioctl_flags.h" + +#include MPERS_DEFS + +static int +perf_ioctl_query_bpf(struct tcb *const tcp, const kernel_ulong_t arg) +{ + uint32_t info; + + if (entering(tcp)) { + tprints(", "); + + if (umove_or_printaddr(tcp, arg, &info)) + return RVAL_IOCTL_DECODED; + + tprintf("{ids_len=%u, ", info); + + return 0; + } + + if (syserror(tcp) || + umove(tcp, arg + offsetof(struct perf_event_query_bpf, prog_cnt), + &info)) { + tprints("...}"); + + return RVAL_IOCTL_DECODED; + } + + tprintf("prog_cnt=%u, ids=", info); + + print_array(tcp, arg + offsetof(struct perf_event_query_bpf, ids), info, + &info, sizeof(info), + umoven_or_printaddr, print_uint32_array_member, NULL); + + tprints("}"); + + return RVAL_IOCTL_DECODED; +} + +static int +perf_ioctl_modify_attributes(struct tcb *const tcp, const kernel_ulong_t arg) +{ + tprints(", "); + if (!fetch_perf_event_attr(tcp, arg)) + print_perf_event_attr(tcp, arg); + + return RVAL_IOCTL_DECODED; +} + +MPERS_PRINTER_DECL(int, perf_ioctl, + struct tcb *const tcp, const unsigned int code, + const kernel_ulong_t arg) +{ + switch (code) { + case PERF_EVENT_IOC_ENABLE: + case PERF_EVENT_IOC_DISABLE: + case PERF_EVENT_IOC_RESET: + tprints(", "); + printflags(perf_ioctl_flags, arg, "PERF_IOC_FLAG_???"); + + return RVAL_IOCTL_DECODED; + + case PERF_EVENT_IOC_REFRESH: + tprintf(", %d", (int) arg); + + return RVAL_IOCTL_DECODED; + + case PERF_EVENT_IOC_PERIOD: + tprints(", "); + printnum_int64(tcp, arg, "%" PRIu64); + + return RVAL_IOCTL_DECODED; + + case PERF_EVENT_IOC_SET_OUTPUT: + case PERF_EVENT_IOC_SET_BPF: + tprintf(", "); + printfd(tcp, (int) arg); + + return RVAL_IOCTL_DECODED; + + case PERF_EVENT_IOC_PAUSE_OUTPUT: + tprintf(", %" PRI_klu, arg); + + return RVAL_IOCTL_DECODED; + + /* + * The following ioctl requests are personality-specific + * due to the pointer size. + */ + case PERF_EVENT_IOC_SET_FILTER: + tprints(", "); + printstr_ex(tcp, arg, get_pagesize(), QUOTE_0_TERMINATED); + + return RVAL_IOCTL_DECODED; + + case PERF_EVENT_IOC_ID: + if (entering(tcp)) { + tprints(", "); + + return 0; + } + + printnum_int64(tcp, arg, "%" PRIu64); + + return RVAL_IOCTL_DECODED; + + case PERF_EVENT_IOC_QUERY_BPF: + return perf_ioctl_query_bpf(tcp, arg); + + case PERF_EVENT_IOC_MODIFY_ATTRIBUTES: + return perf_ioctl_modify_attributes(tcp, arg); + + default: + return RVAL_DECODED; + } +} diff --git a/tests/.gitignore b/tests/.gitignore index 5c468112..e585112f 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -143,6 +143,7 @@ ioctl_loop-nv ioctl_loop-v ioctl_mtd ioctl_nsfs +ioctl_perf ioctl_ptp ioctl_rtc ioctl_rtc-v diff --git a/tests/gen_tests.in b/tests/gen_tests.in index 9a175221..4400c485 100644 --- a/tests/gen_tests.in +++ b/tests/gen_tests.in @@ -140,6 +140,7 @@ ioctl_loop-nv +ioctl.test -a22 -e verbose=none ioctl_loop-v +ioctl.test -v ioctl_mtd +ioctl.test ioctl_nsfs +ioctl.test -esignal=none +ioctl_perf +ioctl.test ioctl_ptp +ioctl.test ioctl_rtc +ioctl.test ioctl_rtc-v +ioctl.test -v diff --git a/tests/ioctl_perf.c b/tests/ioctl_perf.c new file mode 100644 index 00000000..c995a416 --- /dev/null +++ b/tests/ioctl_perf.c @@ -0,0 +1,232 @@ +/* + * Check decoding of PERF_EVENT_IOC_* commands of ioctl syscall. + * + * Copyright (c) 2018 The strace developers. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "tests.h" + +#ifdef HAVE_LINUX_PERF_EVENT_H + +# include +# include +# include +# include +# include + +/* + * Workaround the bug in kernel UAPI that was fixed + * in Linux commit v2.6.33-rc1~48^2~288^2~19. + */ +# ifndef u64 +# define u64 uint64_t +# endif + +# define XLAT_MACROS_ONLY +# include "xlat/perf_ioctl_cmds.h" +# undef XLAT_MACROS_ONLY + +# define STR16 "0123456789abcdef" + +int +main(void) +{ + static const kernel_ulong_t unknown_perf_cmd = + (kernel_ulong_t) 0xbadc0dedfeed24edULL; + static const kernel_ulong_t magic = + (kernel_ulong_t) 0xdeadbeefbadc0dedULL; + static const uint64_t magic64 = 0xfacefeeddeadc0deULL; + static const char str[] = STR16 STR16 STR16 STR16; + + static struct { + unsigned int cmd; + const char *str; + } flag_iocs[] = { + { ARG_STR(PERF_EVENT_IOC_ENABLE) }, + { ARG_STR(PERF_EVENT_IOC_DISABLE) }, + { ARG_STR(PERF_EVENT_IOC_RESET) }, + }; + + TAIL_ALLOC_OBJECT_CONST_PTR(uint64_t, u64_ptr); + uint64_t *const u64_efault = u64_ptr + 1; + uint32_t *const u32_arr = tail_alloc(sizeof(uint32_t) * 4); + uint32_t *const u32_efault = u32_arr + 4; + char *const str_ptr = tail_memdup(str, sizeof(str)); + char *const str_efault = str_ptr + sizeof(str); + TAIL_ALLOC_OBJECT_CONST_PTR(struct perf_event_attr, pea_ptr); + + *u64_ptr = magic64; + fill_memory_ex(pea_ptr, sizeof(*pea_ptr), 0xaa, 0x55); + + /* Unknown perf commands */ + ioctl(-1, unknown_perf_cmd, magic); + printf("ioctl(-1, _IOC(_IOC_READ|_IOC_WRITE%s, 0x24, %#x, %#x), " + "%#lx) = -1 EBADF (%m)\n", + _IOC_DIR((unsigned int) unknown_perf_cmd) & _IOC_NONE ? + "|_IOC_NONE" : "", + _IOC_NR((unsigned int) unknown_perf_cmd), + _IOC_SIZE((unsigned int) unknown_perf_cmd), + (unsigned long) magic); + + ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES + 1, magic); + printf("ioctl(-1, _IOC(_IOC_WRITE, 0x24, %#x, %#x), %#lx)" + " = -1 EBADF (%m)\n", + (unsigned int) _IOC_NR(PERF_EVENT_IOC_MODIFY_ATTRIBUTES + 1), + (unsigned int) _IOC_SIZE(PERF_EVENT_IOC_MODIFY_ATTRIBUTES + 1), + (unsigned long) magic); + + /* PERF_EVENT_IOC_{ENABLE,DISABLE,RESET} */ + for (unsigned i = 0; i < ARRAY_SIZE(flag_iocs); i++) { + ioctl(-1, flag_iocs[i].cmd, 0); + printf("ioctl(-1, %s, 0) = -1 EBADF (%m)\n", flag_iocs[i].str); + + ioctl(-1, flag_iocs[i].cmd, 1); + printf("ioctl(-1, %s, PERF_IOC_FLAG_GROUP) = -1 EBADF (%m)\n", + flag_iocs[i].str); + + ioctl(-1, flag_iocs[i].cmd, 2); + printf("ioctl(-1, %s, 0x2 /* PERF_IOC_FLAG_??? */) " + "= -1 EBADF (%m)\n", + flag_iocs[i].str); + + ioctl(-1, flag_iocs[i].cmd, magic); + printf("ioctl(-1, %s, PERF_IOC_FLAG_GROUP|%#x) " + "= -1 EBADF (%m)\n", + flag_iocs[i].str, (unsigned int) magic & ~1U); + } + + /* PERF_EVENT_IOC_REFRESH */ + ioctl(-1, PERF_EVENT_IOC_REFRESH, magic); + printf("ioctl(-1, PERF_EVENT_IOC_REFRESH, %d) = -1 EBADF (%m)\n", + (int) magic); + + /* PERF_EVENT_IOC_PERIOD */ + ioctl(-1, PERF_EVENT_IOC_PERIOD, NULL); + printf("ioctl(-1, PERF_EVENT_IOC_PERIOD, NULL) = -1 EBADF (%m)\n"); + + ioctl(-1, PERF_EVENT_IOC_PERIOD, u64_efault); + printf("ioctl(-1, PERF_EVENT_IOC_PERIOD, %p) = -1 EBADF (%m)\n", + u64_efault); + + ioctl(-1, PERF_EVENT_IOC_PERIOD, u64_ptr); + printf("ioctl(-1, PERF_EVENT_IOC_PERIOD, [%" PRIu64 "])" + " = -1 EBADF (%m)\n", + magic64); + + /* PERF_EVENT_IOC_SET_OUTPUT */ + ioctl(-1, PERF_EVENT_IOC_SET_OUTPUT, magic); + printf("ioctl(-1, PERF_EVENT_IOC_SET_OUTPUT, %d) = -1 EBADF (%m)\n", + (int) magic); + + /* PERF_EVENT_IOC_SET_FILTER */ + ioctl(-1, PERF_EVENT_IOC_SET_FILTER, NULL); + printf("ioctl(-1, PERF_EVENT_IOC_SET_FILTER, NULL) = -1 EBADF (%m)\n"); + + ioctl(-1, PERF_EVENT_IOC_SET_FILTER, str_efault); + printf("ioctl(-1, PERF_EVENT_IOC_SET_FILTER, %p) = -1 EBADF (%m)\n", + str_efault); + + ioctl(-1, PERF_EVENT_IOC_SET_FILTER, str_ptr); + printf("ioctl(-1, PERF_EVENT_IOC_SET_FILTER, \"%.32s\"...)" + " = -1 EBADF (%m)\n", + str_ptr); + + ioctl(-1, PERF_EVENT_IOC_SET_FILTER, str_ptr + 40); + printf("ioctl(-1, PERF_EVENT_IOC_SET_FILTER, \"%.32s\")" + " = -1 EBADF (%m)\n", + str_ptr + 40); + + str_ptr[sizeof(str) - 1] = '0'; + ioctl(-1, PERF_EVENT_IOC_SET_FILTER, str_ptr + 40); + printf("ioctl(-1, PERF_EVENT_IOC_SET_FILTER, %p)" + " = -1 EBADF (%m)\n", + str_ptr + 40); + + /* PERF_EVENT_IOC_ID */ + /* TODO: check return path */ + ioctl(-1, PERF_EVENT_IOC_ID, NULL); + printf("ioctl(-1, PERF_EVENT_IOC_ID, NULL) = -1 EBADF (%m)\n"); + + ioctl(-1, PERF_EVENT_IOC_ID, u64_efault); + printf("ioctl(-1, PERF_EVENT_IOC_ID, %p) = -1 EBADF (%m)\n", + u64_efault); + + ioctl(-1, PERF_EVENT_IOC_ID, u64_ptr); + printf("ioctl(-1, PERF_EVENT_IOC_ID, %p) = -1 EBADF (%m)\n", + u64_ptr); + + /* PERF_EVENT_IOC_SET_BPF */ + ioctl(-1, PERF_EVENT_IOC_SET_BPF, magic); + printf("ioctl(-1, PERF_EVENT_IOC_SET_BPF, %d) = -1 EBADF (%m)\n", + (int) magic); + + /* PERF_EVENT_IOC_PAUSE_OUTPUT */ + ioctl(-1, PERF_EVENT_IOC_PAUSE_OUTPUT, magic); + printf("ioctl(-1, PERF_EVENT_IOC_PAUSE_OUTPUT, %lu) = -1 EBADF (%m)\n", + (unsigned long) magic); + + /* PERF_EVENT_IOC_QUERY_BPF */ + /* TODO: check return path */ + ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, NULL); + printf("ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, NULL) = -1 EBADF (%m)\n"); + + ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, u32_efault); + printf("ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, %p) = -1 EBADF (%m)\n", + u32_efault); + + u32_arr[0] = 0xbadc0ded; + ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, u32_arr); + printf("ioctl(-1, PERF_EVENT_IOC_QUERY_BPF, {ids_len=3134983661, ...})" + " = -1 EBADF (%m)\n"); + + /* PERF_EVENT_IOC_MODIFY_ATTRIBUTES */ + ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, NULL); + printf("ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, NULL)" + " = -1 EBADF (%m)\n"); + + ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, pea_ptr + 1); + printf("ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, %p)" + " = -1 EBADF (%m)\n", + pea_ptr + 1); + + printf("ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES" + ", {type=%#x /* PERF_TYPE_??? */" + ", size=%#x /* PERF_ATTR_SIZE_??? */" + ", config=%#llx, ...}) = -1 EBADF (%m)\n", + (unsigned int) pea_ptr->type, + (unsigned int) pea_ptr->size, + (unsigned long long) pea_ptr->config); + ioctl(-1, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, pea_ptr); + + puts("+++ exited with 0 +++"); + return 0; +} + +#else + +SKIP_MAIN_UNDEFINED("HAVE_LINUX_PERF_EVENT_H"); + +#endif diff --git a/tests/pure_executables.list b/tests/pure_executables.list index 4553c687..80c8ae75 100755 --- a/tests/pure_executables.list +++ b/tests/pure_executables.list @@ -112,6 +112,7 @@ ioctl_kvm_run ioctl_loop ioctl_mtd ioctl_rtc +ioctl_perf ioctl_ptp ioctl_scsi ioctl_sg_io_v3 diff --git a/xlat/perf_ioctl_cmds.in b/xlat/perf_ioctl_cmds.in new file mode 100644 index 00000000..bf7ad78a --- /dev/null +++ b/xlat/perf_ioctl_cmds.in @@ -0,0 +1,12 @@ +PERF_EVENT_IOC_ENABLE _IO ('$', 0) +PERF_EVENT_IOC_DISABLE _IO ('$', 1) +PERF_EVENT_IOC_REFRESH _IO ('$', 2) +PERF_EVENT_IOC_RESET _IO ('$', 3) +PERF_EVENT_IOC_PERIOD _IOW('$', 4, uint64_t) +PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5) +PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *) +PERF_EVENT_IOC_ID _IOR('$', 7, uint64_t *) +PERF_EVENT_IOC_SET_BPF _IOW('$', 8, uint32_t) +PERF_EVENT_IOC_PAUSE_OUTPUT _IOW('$', 9, uint32_t) +PERF_EVENT_IOC_QUERY_BPF _IOWR('$', 10, struct perf_event_query_bpf *) +PERF_EVENT_IOC_MODIFY_ATTRIBUTES _IOW('$', 11, struct perf_event_attr *) diff --git a/xlat/perf_ioctl_flags.in b/xlat/perf_ioctl_flags.in new file mode 100644 index 00000000..502f69a7 --- /dev/null +++ b/xlat/perf_ioctl_flags.in @@ -0,0 +1 @@ +PERF_IOC_FLAG_GROUP (1U << 0) -- 2.50.1