]> granicus.if.org Git - strace/blob - tests/perf_event_open.c
tests: extend TEST_NETLINK_OBJECT macro
[strace] / tests / perf_event_open.c
1 /*
2  * Check verbose decoding of perf_event_open syscall.
3  *
4  * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
5  * Copyright (c) 2016-2017 The strace developers.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "tests.h"
32 #include <asm/unistd.h>
33
34 #if defined(__NR_perf_event_open) && defined(HAVE_LINUX_PERF_EVENT_H)
35
36 # include <inttypes.h>
37 # include <limits.h>
38 # include <stdbool.h>
39 # include <stddef.h>
40 # include <stdio.h>
41 # include <stdlib.h>
42 # include <string.h>
43 # include <unistd.h>
44
45 # include <linux/perf_event.h>
46
47 # include "xlat.h"
48 # include "xlat/perf_event_open_flags.h"
49 # include "xlat/perf_attr_size.h"
50
51 # if ULONG_MAX > UINT_MAX /* Poor man's "whether long is 8 bytes?" */
52 #  define LONG_STR_PREFIX "ffffffff"
53 # else /* !(ULONG_MAX > UINT_MAX) */
54 #  define LONG_STR_PREFIX ""
55 # endif /* ULONG_MAX > UINT_MAX */
56
57 # ifndef PERF_TYPE_BREAKPOINT
58 #  define PERF_TYPE_BREAKPOINT 5
59 # endif
60
61 struct s32_val_str {
62         int32_t val;
63         const char *str;
64 };
65
66 struct u32_val_str {
67         uint32_t val;
68         const char *str;
69 };
70
71 struct u64_val_str {
72         uint64_t val;
73         const char *str;
74 };
75
76 /* In order to avoid endianness-specific hackery. */
77 struct pea_flags {
78         uint64_t disabled                       :1,
79                  inherit                        :1,
80                  pinned                         :1,
81                  exclusive                      :1,
82                  exclude_user                   :1,
83                  exclude_kernel                 :1,
84                  exclude_hv                     :1,
85                  exclude_idle                   :1,
86                  mmap                           :1,
87                  comm                           :1,
88                  freq                           :1,
89                  inherit_stat                   :1,
90                  enable_on_exec                 :1,
91                  task                           :1,
92                  watermark                      :1,
93                  precise_ip                     :2,
94                  mmap_data                      :1,
95                  sample_id_all                  :1,
96                  exclude_host                   :1,
97                  exclude_guest                  :1,
98                  exclude_callchain_kernel       :1,
99                  exclude_callchain_user         :1,
100                  mmap2                          :1,
101                  comm_exec                      :1,
102                  use_clockid                    :1,
103                  context_switch                 :1,
104                  write_backward                 :1,
105                  __reserved_1                   :36;
106 };
107
108 static const char *
109 printaddr(void *ptr)
110 {
111         static char buf[sizeof("0x") + sizeof(void *) * 2];
112
113         if (ptr == NULL)
114                 return "NULL";
115
116         snprintf(buf, sizeof(buf), "%#lx", (unsigned long)ptr);
117
118         return buf;
119 }
120
121 /*
122  * Checklist:
123  *
124  * type - 8 IDs
125  * config - 13 IDs (0..11 + random), depends on type
126  * sample type - bitmask, up to 20 bits
127  * read_format - 5 IDs
128  * bp_type - 6, weird semantics (invalid/unknown)
129  * branch_sample_type - bitmask, 16 bits
130  * clockid - 13 values
131  *
132  * Unions:
133  * sample_period/sample_freq
134  * wakeup_event/wakeup_watermark
135  * bp_addr/config1
136  * bp_len/config2
137  */
138
139 /*
140  * The main idea behind all those numerous ifdefs is checking against version of
141  * structure provided in kernel headers and not use one defined in strace
142  * headers (assume the case when suddenly we add flag without proper update of
143  * __reserved_1 field or something like this).
144  */
145 static void
146 print_event_attr(struct perf_event_attr *attr_ptr, size_t size,
147         const char *type, const char *config, const char *sample_type,
148         const char *read_format, const char *precise_ip_desc,
149         const char *bp_type, const char *branch_sample_type,
150         const char *clockid, uint32_t available_size)
151 {
152         /*
153          * Currently, strace supports version 5 of the structure, which is
154          * 112 bytes in size.
155          */
156         enum {
157                 STRACE_PEA_ABBREV_SIZE =
158                         offsetof(struct perf_event_attr, config) +
159                         sizeof(attr_ptr->config),
160                 STRACE_PEA_SIZE = 112,
161         };
162
163         uint32_t read_size;
164         struct perf_event_attr *attr;
165 # if VERBOSE
166         uint32_t cutoff;
167         uint64_t val;
168         uint64_t use_clockid;
169         union {
170                 struct pea_flags flags;
171                 uint64_t raw;
172         } flags_data;
173 # endif
174
175         read_size =
176 # if !VERBOSE
177                 STRACE_PEA_ABBREV_SIZE;
178 # else
179                 size < STRACE_PEA_SIZE ?
180                         (size ? size : PERF_ATTR_SIZE_VER0) : STRACE_PEA_SIZE;
181 # endif
182
183         if (read_size > available_size) {
184                 printf("%s", printaddr(attr_ptr));
185                 return;
186         }
187
188         /*
189          * Replicate kernel's behaviour regarding copying structure from
190          * userspace.
191          */
192         attr = calloc(1, STRACE_PEA_SIZE);
193
194         if (!attr)
195                 error_msg_and_fail("calloc");
196
197
198         memcpy(attr, attr_ptr, read_size);
199
200         if (size && (size < PERF_ATTR_SIZE_VER0)) {
201                 printf("%s", printaddr(attr_ptr));
202                 free(attr);
203                 return;
204         }
205
206         printf("{type=%s, size=", type);
207         if (size != attr->size) {
208                 printxval(perf_attr_size, size, "PERF_ATTR_SIZE_???");
209                 printf(" => ");
210         }
211         printxval(perf_attr_size, attr->size, "PERF_ATTR_SIZE_???");
212         printf(", config=%s, ", config);
213
214         if (!size)
215                 size = PERF_ATTR_SIZE_VER0;
216
217 # if !VERBOSE
218         printf("...}");
219 # else /* !VERBOSE */
220         printf("%s=%" PRI__u64", sample_type=%s, read_format=%s",
221                attr->freq ? "sample_freq" : "sample_period",
222                attr->freq ? attr->sample_freq : attr->sample_period,
223                sample_type, read_format);
224
225         printf(", disabled=%u"
226                ", inherit=%u"
227                ", pinned=%u"
228                ", exclusive=%u"
229                ", exclusive_user=%u"
230                ", exclude_kernel=%u"
231                ", exclude_hv=%u"
232                ", exclude_idle=%u"
233                ", mmap=%u"
234                ", comm=%u"
235                ", freq=%u"
236                ", inherit_stat=%u"
237                ", enable_on_exec=%u"
238                ", task=%u"
239                ", watermark=%u",
240                attr->disabled,
241                attr->inherit,
242                attr->pinned,
243                attr->exclusive,
244                attr->exclude_user,
245                attr->exclude_kernel,
246                attr->exclude_hv,
247                attr->exclude_idle,
248                attr->mmap,
249                attr->comm,
250                attr->freq,
251                attr->inherit_stat,
252                attr->enable_on_exec,
253                attr->task,
254                attr->watermark);
255
256         flags_data.raw = ((uint64_t *) attr)[5];
257
258         val =
259 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_PRECISE_IP
260                 attr->precise_ip;
261 # else
262                 flags_data.flags.precise_ip;
263 # endif
264         printf(", precise_ip=%" PRIu64 " /* %s */", val, precise_ip_desc);
265
266         val =
267 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_MMAP_DATA
268                 attr->mmap_data;
269 # else
270                 flags_data.flags.mmap_data;
271 # endif
272         printf(", mmap_data=%" PRIu64, val);
273
274         val =
275 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_SAMPLE_ID_ALL
276                 attr->sample_id_all;
277 # else
278                 flags_data.flags.sample_id_all;
279 # endif
280         printf(", sample_id_all=%" PRIu64, val);
281
282         val =
283 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_EXCLUDE_HOST
284                 attr->exclude_host;
285 # else
286                 flags_data.flags.exclude_host;
287 # endif
288         printf(", exclude_host=%" PRIu64, val);
289
290         val =
291 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_EXCLUDE_GUEST
292                 attr->exclude_guest;
293 # else
294                 flags_data.flags.exclude_guest;
295 # endif
296         printf(", exclude_guest=%" PRIu64, val);
297
298         val =
299 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_EXCLUDE_CALLCHAIN_KERNEL
300                 attr->exclude_callchain_kernel;
301 # else
302                 flags_data.flags.exclude_callchain_kernel;
303 # endif
304         printf(", exclude_callchain_kernel=%" PRIu64, val);
305
306         val =
307 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_EXCLUDE_CALLCHAIN_USER
308                 attr->exclude_callchain_user;
309 # else
310                 flags_data.flags.exclude_callchain_user;
311 # endif
312         printf(", exclude_callchain_user=%" PRIu64, val);
313
314         val =
315 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_MMAP2
316                 attr->mmap2;
317 # else
318                 flags_data.flags.mmap2;
319 # endif
320         printf(", mmap2=%" PRIu64, val);
321
322         val =
323 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_COMM_EXEC
324                 attr->comm_exec;
325 # else
326                 flags_data.flags.comm_exec;
327 # endif
328         printf(", comm_exec=%" PRIu64, val);
329
330         use_clockid = val =
331 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_USE_CLOCKID
332                 attr->use_clockid;
333 # else
334                 flags_data.flags.use_clockid;
335 # endif
336         printf(", use_clockid=%" PRIu64, val);
337
338         val =
339 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_CONTEXT_SWITCH
340                 attr->context_switch;
341 # else
342                 flags_data.flags.context_switch;
343 # endif
344         printf(", context_switch=%" PRIu64, val);
345
346         val =
347 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_WRITE_BACKWARD
348                 attr->write_backward;
349 # else
350                 flags_data.flags.write_backward;
351 # endif
352         printf(", write_backward=%" PRIu64, val);
353
354         val = flags_data.flags.__reserved_1;
355         if (val)
356                 printf(", __reserved_1=%#" PRIx64 " /* Bits 63..28 */", val);
357
358         printf(", %s=%u",
359                 attr->watermark ? "wakeup_watermark" : "wakeup_events",
360                 attr->watermark ? attr->wakeup_watermark : attr->wakeup_events);
361
362         if (attr->type == PERF_TYPE_BREAKPOINT)
363                 printf(", bp_type=%s", bp_type);
364
365         val =
366 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_CONFIG1
367                 attr->config1;
368 # else
369                 ((uint64_t *) attr)[56 / sizeof(uint64_t)];
370 # endif
371         printf(", %s=%#" PRIx64,
372                attr->type == PERF_TYPE_BREAKPOINT ? "bp_addr" : "config1",
373                val);
374
375         /* End of version 0 of the structure */
376         if (size <= 64) {
377                 cutoff = 64;
378                 goto end;
379         }
380
381         val =
382 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_CONFIG2
383                 attr->config2;
384 # else
385                 ((uint64_t *) attr)[64 / sizeof(uint64_t)];
386 # endif
387         if (attr->type == PERF_TYPE_BREAKPOINT)
388                 printf(", bp_len=%" PRIu64, val);
389         else
390                 printf(", config2=%#" PRIx64, val);
391
392         /* End of version 1 of the structure */
393         if (size <= 72) {
394                 cutoff = 72;
395                 goto end;
396         }
397
398         /*
399          * Print branch sample type only in case  PERF_SAMPLE_BRANCH_STACK
400          * is set in the sample_type field.
401          */
402         if (attr->sample_type & (1 << 11))
403                 printf(", branch_sample_type=%s", branch_sample_type);
404
405         /* End of version 2 of the structure */
406         if (size <= 80) {
407                 cutoff = 80;
408                 goto end;
409         }
410
411         val =
412 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_SAMPLE_REGS_USER
413                 attr->sample_regs_user;
414 # else
415                 ((uint64_t *) attr)[80 / sizeof(uint64_t)];
416 # endif
417         printf(", sample_regs_user=%#" PRIx64, val);
418
419         if (size <= 88) {
420                 cutoff = 88;
421                 goto end;
422         }
423
424         val =
425 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_SAMPLE_STACK_USER
426                 attr->sample_stack_user;
427 # else
428                 ((uint32_t *) attr)[88 / sizeof(uint32_t)];
429 # endif
430         /*
431          * Print branch sample type only in case PERF_SAMPLE_STACK_USER
432          * is set in the sample_type field.
433          */
434         if (attr->sample_type & (1 << 13))
435                 printf(", sample_stack_user=%#" PRIx32, (uint32_t) val);
436
437         if (size <= 92) {
438                 cutoff = 92;
439                 goto end;
440         }
441
442         if (use_clockid)
443                 printf(", clockid=%s", clockid);
444
445         /* End of version 3 of the structure */
446         if (size <= 96) {
447                 cutoff = 96;
448                 goto end;
449         }
450
451         val =
452 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_SAMPLE_REGS_INTR
453                 attr->sample_regs_intr;
454 # else
455                 ((uint64_t *) attr)[96 / sizeof(uint64_t)];
456 # endif
457         printf(", sample_regs_intr=%#" PRIx64, val);
458
459         /* End of version 4 of the structure */
460         if (size <= 104) {
461                 cutoff = 104;
462                 goto end;
463         }
464
465         val =
466 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_AUX_WATERMARK
467                 attr->aux_watermark;
468 # else
469                 ((uint32_t *) attr)[104 / sizeof(uint32_t)];
470 # endif
471         printf(", aux_watermark=%" PRIu32, (uint32_t) val);
472
473         if (size <= 108) {
474                 cutoff = 108;
475                 goto end;
476         }
477
478         val =
479 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_SAMPLE_MAX_STACK
480                 attr->sample_max_stack;
481 # else
482                 ((uint16_t *) attr)[108 / sizeof(uint16_t)];
483 # endif
484         printf(", sample_max_stack=%" PRIu16, (uint16_t) val);
485
486         if (size <= 110) {
487                 cutoff = 110;
488                 goto end;
489         }
490
491         cutoff = STRACE_PEA_SIZE;
492
493 end:
494         if (size > cutoff)
495                 printf(", ...");
496
497         printf("}");
498 # endif /* !VERBOSE */
499
500         free(attr);
501 }
502
503 /* These require aligned access, so no byte-grain checks possible */
504 # if defined SPARC || defined SPARC64 || defined POWERPC || defined POWERPC64
505 #  define ATTR_REC(sz) { tail_alloc((sz + 7) & ~7), sz }
506 # else
507 #  define ATTR_REC(sz) { tail_alloc(sz), sz }
508 # endif
509
510 # define BRANCH_TYPE_ALL \
511         "PERF_SAMPLE_BRANCH_USER|" \
512         "PERF_SAMPLE_BRANCH_KERNEL|" \
513         "PERF_SAMPLE_BRANCH_HV|" \
514         "PERF_SAMPLE_BRANCH_ANY|" \
515         "PERF_SAMPLE_BRANCH_ANY_CALL|" \
516         "PERF_SAMPLE_BRANCH_ANY_RETURN|" \
517         "PERF_SAMPLE_BRANCH_IND_CALL|" \
518         "PERF_SAMPLE_BRANCH_ABORT_TX|" \
519         "PERF_SAMPLE_BRANCH_IN_TX|" \
520         "PERF_SAMPLE_BRANCH_NO_TX|" \
521         "PERF_SAMPLE_BRANCH_COND|" \
522         "PERF_SAMPLE_BRANCH_CALL_STACK|" \
523         "PERF_SAMPLE_BRANCH_IND_JUMP|" \
524         "PERF_SAMPLE_BRANCH_CALL|" \
525         "PERF_SAMPLE_BRANCH_NO_FLAGS|" \
526         "PERF_SAMPLE_BRANCH_NO_CYCLES"
527
528 int
529 main(void)
530 {
531         static const size_t attr_small_size = PERF_ATTR_SIZE_VER0 - 8;
532         static const size_t attr_v0_size = PERF_ATTR_SIZE_VER0;
533         static const size_t attr_v1_size = PERF_ATTR_SIZE_VER1;
534         static const size_t attr_v2_size = PERF_ATTR_SIZE_VER2;
535         static const size_t attr_v2_5_size = PERF_ATTR_SIZE_VER2 + 8;
536         static const size_t attr_v2_75_size = PERF_ATTR_SIZE_VER2 + 12;
537         static const size_t attr_v3_size = PERF_ATTR_SIZE_VER3;
538         static const size_t attr_v4_size = PERF_ATTR_SIZE_VER4;
539         static const size_t attr_v4_5_size = PERF_ATTR_SIZE_VER4 + 4;
540         static const size_t attr_v4_625_size = PERF_ATTR_SIZE_VER4 + 5;
541         static const size_t attr_v4_875_size = PERF_ATTR_SIZE_VER4 + 7;
542         static const size_t attr_v5_size = PERF_ATTR_SIZE_VER5;
543         static const size_t attr_big_size = PERF_ATTR_SIZE_VER5 + 32;
544
545         static const struct u64_val_str attr_types[] = {
546                 { ARG_STR(PERF_TYPE_HARDWARE) },
547                 { ARG_STR(PERF_TYPE_SOFTWARE) },
548                 { ARG_STR(PERF_TYPE_TRACEPOINT) },
549                 { ARG_STR(PERF_TYPE_HW_CACHE) },
550                 { ARG_STR(PERF_TYPE_RAW) },
551                 { ARG_STR(PERF_TYPE_BREAKPOINT) },
552                 { ARG_STR(0x6) " /* PERF_TYPE_??? */" },
553                 { ARG_STR(0xdeadc0de) " /* PERF_TYPE_??? */" },
554         };
555         static const struct u64_val_str
556             attr_configs[ARRAY_SIZE(attr_types)][3] = {
557                 /* PERF_TYPE_HARDWARE */ {
558                         { 9, "PERF_COUNT_HW_REF_CPU_CYCLES" },
559                         { 10, "0xa /* PERF_COUNT_HW_??? */" },
560                         { ARG_ULL_STR(0xfaceca75deadb0d4)
561                                 " /* PERF_COUNT_HW_??? */" },
562                 },
563                 /* PERF_TYPE_SOFTWARE */ {
564                         { 10, "PERF_COUNT_SW_BPF_OUTPUT" },
565                         { 11, "0xb /* PERF_COUNT_SW_??? */" },
566                         { ARG_ULL_STR(0xdec0ded1dec0ded2)
567                                 " /* PERF_COUNT_SW_??? */" },
568                 },
569                 /* PERF_TYPE_TRACEPOINT */ {
570                         { ARG_STR(0) },
571                         { 4207856245U, "4207856245" },
572                         { ARG_ULL_STR(16051074073505095380) },
573                 },
574                 /* PERF_TYPE_HW_CACHE */ {
575                         { 0, "PERF_COUNT_HW_CACHE_L1D|"
576                                 "PERF_COUNT_HW_CACHE_OP_READ<<8|"
577                                 "PERF_COUNT_HW_CACHE_RESULT_ACCESS<<16" },
578                         { 0x020207, "0x7 /* PERF_COUNT_HW_CACHE_??? */|"
579                                 "PERF_COUNT_HW_CACHE_OP_PREFETCH<<8|"
580                                 "0x2 /* PERF_COUNT_HW_CACHE_RESULT_??? */<<16" },
581                         { 0xdeadf157ed010306ULL, "PERF_COUNT_HW_CACHE_NODE|"
582                                 "0x3 /* PERF_COUNT_HW_CACHE_OP_??? */<<8|"
583                                 "PERF_COUNT_HW_CACHE_RESULT_MISS<<16|"
584                                 "0xdeadf157ed<<24 "
585                                 "/* PERF_COUNT_HW_CACHE_??? */" },
586                 },
587                 /* PERF_TYPE_RAW */ {
588                         { ARG_STR(0) },
589                         { ARG_STR(0xda7a1057) },
590                         { ARG_ULL_STR(0xdec0ded7dec0ded8) },
591                 },
592                 /* PERF_TYPE_BREAKPOINT */ {
593                         { ARG_STR(0) },
594                         { ARG_STR(0xbadc0ded) },
595                         { ARG_ULL_STR(0xdec0ded9dec0deda) },
596                 },
597                 /* invalid 1 */ {
598                         { ARG_STR(0) },
599                         { ARG_STR(0xbeeff00d) },
600                         { ARG_ULL_STR(0xdec0dedbdec0dedc) },
601                 },
602                 /* invalid 2 */ {
603                         { ARG_STR(0) },
604                         { ARG_STR(0xca75dead) },
605                         { ARG_ULL_STR(0xdec0dedddec0dede) },
606                 },
607         };
608         static const struct u64_val_str sample_types[] = {
609                 { ARG_STR(0) },
610                 { 0x800, "PERF_SAMPLE_BRANCH_STACK" },
611                 { ARG_ULL_STR(0xdeadc0deda780000) " /* PERF_SAMPLE_??? */" },
612                 { 0xffffffffffffffffULL,
613                         "PERF_SAMPLE_IP|PERF_SAMPLE_TID|PERF_SAMPLE_TIME|"
614                         "PERF_SAMPLE_ADDR|PERF_SAMPLE_READ|"
615                         "PERF_SAMPLE_CALLCHAIN|PERF_SAMPLE_ID|PERF_SAMPLE_CPU|"
616                         "PERF_SAMPLE_PERIOD|PERF_SAMPLE_STREAM_ID|"
617                         "PERF_SAMPLE_RAW|PERF_SAMPLE_BRANCH_STACK|"
618                         "PERF_SAMPLE_REGS_USER|PERF_SAMPLE_STACK_USER|"
619                         "PERF_SAMPLE_WEIGHT|PERF_SAMPLE_DATA_SRC|"
620                         "PERF_SAMPLE_IDENTIFIER|PERF_SAMPLE_TRANSACTION|"
621                         "PERF_SAMPLE_REGS_INTR|0xfffffffffff80000" },
622         };
623         static const struct u64_val_str read_formats[] = {
624                 { ARG_STR(0) },
625                 { ARG_STR(PERF_FORMAT_TOTAL_TIME_ENABLED) },
626                 { 0xf, "PERF_FORMAT_TOTAL_TIME_ENABLED|"
627                         "PERF_FORMAT_TOTAL_TIME_RUNNING|"
628                         "PERF_FORMAT_ID|PERF_FORMAT_GROUP" },
629                 { ARG_ULL_STR(0xdeadf157dec0ded0) " /* PERF_FORMAT_??? */" },
630                 { 0xffffffffffffffffULL,
631                         "PERF_FORMAT_TOTAL_TIME_ENABLED|"
632                         "PERF_FORMAT_TOTAL_TIME_RUNNING|"
633                         "PERF_FORMAT_ID|PERF_FORMAT_GROUP|"
634                         "0xfffffffffffffff0" },
635         };
636         static const char *precise_ip_descs[] = {
637                 "arbitrary skid",
638                 "constant skid",
639                 "requested to have 0 skid",
640                 "must have 0 skid",
641         };
642         static const struct u32_val_str bp_types[] = {
643                 { 0, "HW_BREAKPOINT_EMPTY" },
644                 { 1, "HW_BREAKPOINT_R" },
645                 { 3, "HW_BREAKPOINT_RW" },
646                 { 5, "0x5 /* HW_BREAKPOINT_INVALID */" },
647                 { 8, "0x8 /* HW_BREAKPOINT_??? */" },
648                 { ARG_STR(0xface1e55) " /* HW_BREAKPOINT_??? */" },
649         };
650         static const struct u64_val_str branch_sample_types[] = {
651                 { ARG_STR(0) },
652                 { 0x80, "PERF_SAMPLE_BRANCH_ABORT_TX" },
653                 { 0xffff, BRANCH_TYPE_ALL },
654                 { ARG_ULL_STR(0xdeadcaffeeed0000)
655                         " /* PERF_SAMPLE_BRANCH_??? */" },
656                 { 0xffffffffffffffffULL,
657                         BRANCH_TYPE_ALL "|0xffffffffffff0000" }
658         };
659         static const struct s32_val_str clockids[] = {
660                 { 11, "CLOCK_TAI" },
661                 { ARG_STR(0xc) " /* CLOCK_??? */" },
662                 { ARG_STR(0xbeeffeed) " /* CLOCK_??? */" },
663         };
664
665
666         struct {
667                 struct perf_event_attr *ptr;
668                 size_t size;
669         } attrs[] = {
670                 ATTR_REC(sizeof(struct perf_event_attr)),
671                 ATTR_REC(attr_v0_size),
672                 ATTR_REC(attr_v1_size),
673                 ATTR_REC(attr_v2_size),
674                 ATTR_REC(attr_v2_5_size),
675                 ATTR_REC(attr_v2_75_size),
676                 ATTR_REC(attr_v3_size),
677                 ATTR_REC(attr_v4_size),
678                 ATTR_REC(attr_v4_5_size),
679                 ATTR_REC(attr_v4_625_size),
680                 ATTR_REC(attr_v4_875_size),
681                 ATTR_REC(attr_v5_size),
682                 ATTR_REC(attr_big_size),
683         };
684
685         TAIL_ALLOC_OBJECT_CONST_PTR(struct perf_event_attr, small_attr);
686
687         struct {
688                 struct perf_event_attr *attr;
689                 pid_t pid;
690                 int cpu;
691                 int group_fd;
692                 unsigned long flags;
693                 const char *flags_str;
694         } args[] = {
695                 { NULL,           0xfacef00d, 0xbadabba7, -1,
696                         (unsigned long) 0xFFFFFFFFFFFFFFFFLLU,
697                         "PERF_FLAG_FD_NO_GROUP|PERF_FLAG_FD_OUTPUT|"
698                         "PERF_FLAG_PID_CGROUP|PERF_FLAG_FD_CLOEXEC|"
699                         "0x" LONG_STR_PREFIX "fffffff0"
700                         },
701                 { small_attr + 1, 0,          0,          0,
702                         0, "0" },
703                 { small_attr,     -1,         -1,         1,
704                         PERF_FLAG_FD_NO_GROUP | PERF_FLAG_FD_OUTPUT |
705                         PERF_FLAG_PID_CGROUP | PERF_FLAG_FD_CLOEXEC,
706                         "PERF_FLAG_FD_NO_GROUP|PERF_FLAG_FD_OUTPUT|"
707                         "PERF_FLAG_PID_CGROUP|PERF_FLAG_FD_CLOEXEC" },
708                 { (struct perf_event_attr *) (uintptr_t) 0xfffffacefffffeedULL,
709                                   -100,       100,        0xface1e55,
710                         PERF_FLAG_FD_CLOEXEC, "PERF_FLAG_FD_CLOEXEC" },
711         };
712
713         size_t i;
714         int rc;
715
716         fill_memory(small_attr, sizeof(*small_attr));
717         small_attr->size = attr_small_size;
718
719         for (i = 0; i < ARRAY_SIZE(args); i++) {
720                 rc = syscall(__NR_perf_event_open, args[i].attr, args[i].pid,
721                              args[i].cpu, args[i].group_fd, args[i].flags);
722                 printf("perf_event_open(%s, %d, %d, %d, %s) = %s\n",
723                        printaddr(args[i].attr), args[i].pid, args[i].cpu,
724                        args[i].group_fd, args[i].flags_str, sprintrc(rc));
725         }
726
727         for (i = 0; i < ARRAY_SIZE(attrs) * ARRAY_SIZE(attr_types) *
728             ARRAY_SIZE(attr_configs[0]) + 1; i++) {
729                 struct perf_event_attr *attr = attrs[i % ARRAY_SIZE(attrs)].ptr;
730                 uint32_t size = attrs[i % ARRAY_SIZE(attrs)].size;
731                 unsigned char fill_start = 0x80 + i;
732                 size_t type_idx = i % ARRAY_SIZE(attr_types);
733                 size_t config_idx = i % ARRAY_SIZE(attr_configs[0]);
734                 size_t sample_type_idx = i % ARRAY_SIZE(sample_types);
735                 size_t read_format_idx = i % ARRAY_SIZE(read_formats);
736                 size_t bp_type_idx = (i / ARRAY_SIZE(attr_configs[0])) %
737                         ARRAY_SIZE(bp_types);
738                 size_t branch_sample_type_idx = (i / ARRAY_SIZE(sample_types)) %
739                         ARRAY_SIZE(branch_sample_types);
740                 size_t clockid_idx = i % ARRAY_SIZE(clockids);
741                 size_t args_idx = i % ARRAY_SIZE(args);
742                 const char *ip_desc_str;
743
744                 fill_memory_ex(attr, size, fill_start, 0xff);
745
746                 attr->type = attr_types[type_idx].val;
747                 attr->size = size;
748                 attr->config = attr_configs[type_idx][config_idx].val;
749                 attr->sample_type = sample_types[sample_type_idx].val;
750                 attr->read_format = read_formats[read_format_idx].val;
751
752                 if ((i % 11) == 5)
753                         attr->__reserved_1 = 0;
754
755 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_BP_TYPE
756                 attr->bp_type =
757 # else
758                 ((uint32_t *) attr)[52 / sizeof(uint32_t)] =
759 # endif
760                         bp_types[bp_type_idx].val;
761
762                 if (size >= 80)
763 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_BRANCH_SAMPLE_TYPE
764                         attr->branch_sample_type =
765 # else
766                         ((uint64_t *) attr)[72 / sizeof(uint64_t)] =
767 # endif
768                                 branch_sample_types[branch_sample_type_idx].val;
769
770                 if (size >= 96)
771 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_CLOCKID
772                         attr->clockid =
773 # else
774                         ((uint32_t *) attr)[92 / sizeof(uint32_t)] =
775 # endif
776                                 clockids[clockid_idx].val;
777
778 # ifdef HAVE_STRUCT_PERF_EVENT_ATTR_PRECISE_IP
779                 ip_desc_str = precise_ip_descs[attr->precise_ip];
780 # else
781                 union {
782                         struct pea_flags flags;
783                         uint64_t raw;
784                 } flags_data = { .raw = ((uint64_t *) attr)[5] };
785
786                 ip_desc_str = precise_ip_descs[flags_data.flags.precise_ip];
787 # endif
788
789                 if (i == 0)
790                         attr->size = size + 8;
791
792                 if (i == 1)
793                         attr->size = 0;
794
795                 rc = syscall(__NR_perf_event_open, attr, args[args_idx].pid,
796                              args[args_idx].cpu, args[args_idx].group_fd,
797                              args[args_idx].flags);
798
799                 printf("perf_event_open(");
800                 print_event_attr(attr, i ? ((i == 1) ? 0 : size) : size + 8,
801                                  attr_types[type_idx].str,
802                                  attr_configs[type_idx][config_idx].str,
803                                  sample_types[sample_type_idx].str,
804                                  read_formats[read_format_idx].str,
805                                  ip_desc_str,
806                                  bp_types[bp_type_idx].str,
807                                  branch_sample_types[branch_sample_type_idx].str,
808                                  clockids[clockid_idx].str, size);
809                 printf(", %d, %d, %d, %s) = %s\n", args[args_idx].pid,
810                        args[args_idx].cpu, args[args_idx].group_fd,
811                        args[args_idx].flags_str, sprintrc(rc));
812         }
813
814         puts("+++ exited with 0 +++");
815         return 0;
816 }
817
818 #else
819
820 SKIP_MAIN_UNDEFINED("__NR_perf_event_open && HAVE_LINUX_PERF_EVENT_H");
821
822 #endif