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