1 /*
2 * Check verbose decoding of perf_event_open syscall.
3 *
4 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
5 * Copyright (c) 2016-2023 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12 #include "scno.h"
13
14 #include <inttypes.h>
15 #include <limits.h>
16 #include <stddef.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21
22 #include <linux/perf_event.h>
23
24 #include "xlat.h"
25 #include "xlat/perf_event_open_flags.h"
26 #include "xlat/perf_attr_size.h"
27
28 #if ULONG_MAX > UINT_MAX /* Poor man's "whether long is 8 bytes?" */
29 # define LONG_STR_PREFIX "ffffffff"
30 #else /* !(ULONG_MAX > UINT_MAX) */
31 # define LONG_STR_PREFIX ""
32 #endif /* ULONG_MAX > UINT_MAX */
33
34 struct s32_val_str {
35 int32_t val;
36 const char *str;
37 };
38
39 struct u32_val_str {
40 uint32_t val;
41 const char *str;
42 };
43
44 struct u64_val_str {
45 uint64_t val;
46 const char *str;
47 };
48
49 /* In order to avoid endianness-specific hackery. */
50 struct pea_flags {
51 uint64_t disabled :1,
52 inherit :1,
53 pinned :1,
54 exclusive :1,
55 exclude_user :1,
56 exclude_kernel :1,
57 exclude_hv :1,
58 exclude_idle :1,
59 mmap :1,
60 comm :1,
61 freq :1,
62 inherit_stat :1,
63 enable_on_exec :1,
64 task :1,
65 watermark :1,
66 precise_ip :2,
67 mmap_data :1,
68 sample_id_all :1,
69 exclude_host :1,
70 exclude_guest :1,
71 exclude_callchain_kernel :1,
72 exclude_callchain_user :1,
73 mmap2 :1,
74 comm_exec :1,
75 use_clockid :1,
76 context_switch :1,
77 write_backward :1,
78 namespaces :1,
79 ksymbol :1,
80 bpf_event :1,
81 aux_output :1,
82 cgroup :1,
83 text_poke :1,
84 build_id :1,
85 inherit_thread :1,
86 remove_on_exec :1,
87 sigtrap :1,
88 __reserved_1 :26;
89 };
90
91 static const char *
92 printaddr(void *ptr)
93 {
94 static char buf[sizeof("0x") + sizeof(void *) * 2];
95
96 if (ptr == NULL)
97 return "NULL";
98
99 snprintf(buf, sizeof(buf), "%#lx", (unsigned long)ptr);
100
101 return buf;
102 }
103
104 /*
105 * Checklist:
106 *
107 * type - 8 IDs
108 * config - 13 IDs (0..11 + random), depends on type
109 * sample type - bitmask, up to 20 bits
110 * read_format - 5 IDs
111 * bp_type - 6, weird semantics (invalid/unknown)
112 * branch_sample_type - bitmask, 16 bits
113 * clockid - 13 values
114 *
115 * Unions:
116 * sample_period/sample_freq
117 * wakeup_event/wakeup_watermark
118 * bp_addr/config1
119 * bp_len/config2
120 */
121
122 /*
123 * The main idea behind all those numerous ifdefs is checking against version of
124 * structure provided in kernel headers and not use one defined in strace
125 * headers (assume the case when suddenly we add flag without proper update of
126 * __reserved_1 field or something like this).
127 */
128 static void
129 print_event_attr(struct perf_event_attr *attr_ptr, size_t size,
130 const char *type, const char *config, const char *sample_type,
131 const char *read_format, const char *precise_ip_desc,
132 const char *bp_type, const char *branch_sample_type,
133 const char *clockid, uint32_t available_size)
134 {
135 /*
136 * Currently, strace supports version 5 of the structure, which is
137 * 112 bytes in size.
138 */
139 enum {
140 STRACE_PEA_ABBREV_SIZE =
141 offsetof(struct perf_event_attr, wakeup_events),
142 STRACE_PEA_SIZE = 136,
143 };
144
145 uint32_t read_size;
146 struct perf_event_attr *attr;
147 uint64_t val;
148 union {
149 struct pea_flags flags;
150 uint64_t raw;
151 } flags_data;
152 #if VERBOSE
153 uint32_t cutoff;
154 #endif
155
156 read_size =
157 #if !VERBOSE
158 STRACE_PEA_ABBREV_SIZE;
159 #else
160 size < STRACE_PEA_SIZE ?
161 (size ? size : PERF_ATTR_SIZE_VER0) : STRACE_PEA_SIZE;
162 #endif
163
164 if (read_size > available_size) {
165 printf("%s", printaddr(attr_ptr));
166 return;
167 }
168
169 /*
170 * Replicate kernel's behaviour regarding copying structure from
171 * userspace.
172 */
173 attr = calloc(1, STRACE_PEA_SIZE);
174
175 if (!attr)
176 error_msg_and_fail("calloc");
177
178
179 memcpy(attr, attr_ptr, read_size);
180
181 if (size && (size < PERF_ATTR_SIZE_VER0)) {
182 printf("%s", printaddr(attr_ptr));
183 free(attr);
184 return;
185 }
186
187 printf("{type=%s, size=", type);
188 if (size != attr->size) {
189 printxval(perf_attr_size, size, "PERF_ATTR_SIZE_???");
190 printf(" => ");
191 }
192 printxval(perf_attr_size, attr->size, "PERF_ATTR_SIZE_???");
193 printf(", config=%s, ", config);
194
195 if (!size)
196 size = PERF_ATTR_SIZE_VER0;
197
198 printf("%s=%" PRI__u64", sample_type=%s, read_format=%s",
199 attr->freq ? "sample_freq" : "sample_period",
200 attr->freq ? attr->sample_freq : attr->sample_period,
201 sample_type, read_format);
202
203 #define PRINT_FLAG(flag_) \
204 do { \
205 if (VERBOSE || attr->flag_) { \
206 val = attr->flag_; \
207 printf(", " #flag_ "=%" PRIu64, val); \
208 } \
209 } while (0)
210
211 PRINT_FLAG(disabled);
212 PRINT_FLAG(inherit);
213 PRINT_FLAG(pinned);
214 PRINT_FLAG(exclusive);
215 PRINT_FLAG(exclude_user);
216 PRINT_FLAG(exclude_kernel);
217 PRINT_FLAG(exclude_hv);
218 PRINT_FLAG(exclude_idle);
219 PRINT_FLAG(mmap);
220 PRINT_FLAG(comm);
221 PRINT_FLAG(freq);
222 PRINT_FLAG(inherit_stat);
223 PRINT_FLAG(enable_on_exec);
224 PRINT_FLAG(task);
225 PRINT_FLAG(watermark);
226
227 flags_data.raw = ((uint64_t *) attr)[5];
228
229 val = attr->precise_ip;
230 printf(", precise_ip=%" PRIu64 " /* %s */", val, precise_ip_desc);
231
232 PRINT_FLAG(mmap_data);
233 PRINT_FLAG(sample_id_all);
234 PRINT_FLAG(exclude_host);
235 PRINT_FLAG(exclude_guest);
236 PRINT_FLAG(exclude_callchain_kernel);
237 PRINT_FLAG(exclude_callchain_user);
238 PRINT_FLAG(mmap2);
239 PRINT_FLAG(comm_exec);
240 PRINT_FLAG(use_clockid);
241 PRINT_FLAG(context_switch);
242 PRINT_FLAG(write_backward);
243 PRINT_FLAG(namespaces);
244 PRINT_FLAG(ksymbol);
245 PRINT_FLAG(bpf_event);
246 PRINT_FLAG(aux_output);
247 PRINT_FLAG(cgroup);
248 PRINT_FLAG(text_poke);
249 PRINT_FLAG(build_id);
250 PRINT_FLAG(inherit_thread);
251 PRINT_FLAG(remove_on_exec);
252 PRINT_FLAG(sigtrap);
253
254 val = flags_data.flags.__reserved_1;
255 if (val)
256 printf(", __reserved_1=%#" PRIx64 " /* Bits 63..38 */", val);
257
258 #if !VERBOSE
259 printf(", ...}");
260 #else /* !VERBOSE */
261 printf(", %s=%u",
262 attr->watermark ? "wakeup_watermark" : "wakeup_events",
263 attr->watermark ? attr->wakeup_watermark : attr->wakeup_events);
264
265 if (attr->type == PERF_TYPE_BREAKPOINT)
266 printf(", bp_type=%s", bp_type);
267
268 val = attr->config1;
269 printf(", %s=%#" PRIx64,
270 attr->type == PERF_TYPE_BREAKPOINT ? "bp_addr" : "config1",
271 val);
272
273 /* End of version 0 of the structure */
274 if (size <= 64) {
275 cutoff = 64;
276 goto end;
277 }
278
279 val = attr->config2;
280 if (attr->type == PERF_TYPE_BREAKPOINT)
281 printf(", bp_len=%" PRIu64, val);
282 else
283 printf(", config2=%#" PRIx64, val);
284
285 /* End of version 1 of the structure */
286 if (size <= 72) {
287 cutoff = 72;
288 goto end;
289 }
290
291 /*
292 * Print branch sample type only in case PERF_SAMPLE_BRANCH_STACK
293 * is set in the sample_type field.
294 */
295 if (attr->sample_type & (1 << 11))
296 printf(", branch_sample_type=%s", branch_sample_type);
297
298 /* End of version 2 of the structure */
299 if (size <= 80) {
300 cutoff = 80;
301 goto end;
302 }
303
304 val = attr->sample_regs_user;
305 printf(", sample_regs_user=%#" PRIx64, val);
306
307 if (size <= 88) {
308 cutoff = 88;
309 goto end;
310 }
311
312 val = attr->sample_stack_user;
313 /*
314 * Print branch sample type only in case PERF_SAMPLE_STACK_USER
315 * is set in the sample_type field.
316 */
317 if (attr->sample_type & (1 << 13))
318 printf(", sample_stack_user=%#" PRIx32, (uint32_t) val);
319
320 if (size <= 92) {
321 cutoff = 92;
322 goto end;
323 }
324
325 if (attr->use_clockid)
326 printf(", clockid=%s", clockid);
327
328 /* End of version 3 of the structure */
329 if (size <= 96) {
330 cutoff = 96;
331 goto end;
332 }
333
334 val = attr->sample_regs_intr;
335 printf(", sample_regs_intr=%#" PRIx64, val);
336
337 /* End of version 4 of the structure */
338 if (size <= 104) {
339 cutoff = 104;
340 goto end;
341 }
342
343 val = attr->aux_watermark;
344 printf(", aux_watermark=%" PRIu32, (uint32_t) val);
345
346 if (size <= 108) {
347 cutoff = 108;
348 goto end;
349 }
350
351 val = attr->sample_max_stack;
352 printf(", sample_max_stack=%" PRIu16, (uint16_t) val);
353
354 if (size <= 110) {
355 cutoff = 110;
356 goto end;
357 }
358
359 val = ((uint16_t *) attr)[110 / sizeof(uint16_t)];
360 if (val)
361 printf(" /* bytes 110..111: %#" PRIx16 " */", (uint16_t) val);
362
363 if (size <= 112) {
364 cutoff = 112;
365 goto end;
366 }
367
368 val = attr->aux_sample_size;
369 printf(", aux_sample_size=%" PRIu32, (uint32_t) val);
370
371 if (size <= 116) {
372 cutoff = 116;
373 goto end;
374 }
375
376 val = attr->__reserved_3;
377 if (val)
378 printf(" /* bytes 116..119: %#" PRIx32 " */", (uint32_t) val);
379
380 if (size <= 120) {
381 cutoff = 120;
382 goto end;
383 }
384
385 val = attr->sig_data;
386 printf(", sig_data=%#" PRIx64, (uint64_t) val);
387
388 if (size <= 128) {
389 cutoff = 128;
390 goto end;
391 }
392
393 val = attr->config3;
394 printf(", config3=%#" PRIx64, (uint64_t) val);
395
396 cutoff = STRACE_PEA_SIZE;
397
398 end:
399 if (size > cutoff)
400 printf(", ...");
401
402 printf("}");
403 #endif /* !VERBOSE */
404
405 free(attr);
406 }
407
408 /* These require aligned access, so no byte-grain checks possible */
409 #if defined SPARC || defined SPARC64 || defined POWERPC || defined POWERPC64 || defined ARM || defined AARCH64
410 # define ATTR_REC(sz) { tail_alloc((sz + 7) & ~7), sz }
411 #else
412 # define ATTR_REC(sz) { tail_alloc(sz), sz }
413 #endif
414
415 #define BRANCH_TYPE_ALL \
416 "PERF_SAMPLE_BRANCH_USER|" \
417 "PERF_SAMPLE_BRANCH_KERNEL|" \
418 "PERF_SAMPLE_BRANCH_HV|" \
419 "PERF_SAMPLE_BRANCH_ANY|" \
420 "PERF_SAMPLE_BRANCH_ANY_CALL|" \
421 "PERF_SAMPLE_BRANCH_ANY_RETURN|" \
422 "PERF_SAMPLE_BRANCH_IND_CALL|" \
423 "PERF_SAMPLE_BRANCH_ABORT_TX|" \
424 "PERF_SAMPLE_BRANCH_IN_TX|" \
425 "PERF_SAMPLE_BRANCH_NO_TX|" \
426 "PERF_SAMPLE_BRANCH_COND|" \
427 "PERF_SAMPLE_BRANCH_CALL_STACK|" \
428 "PERF_SAMPLE_BRANCH_IND_JUMP|" \
429 "PERF_SAMPLE_BRANCH_CALL|" \
430 "PERF_SAMPLE_BRANCH_NO_FLAGS|" \
431 "PERF_SAMPLE_BRANCH_NO_CYCLES|" \
432 "PERF_SAMPLE_BRANCH_TYPE_SAVE|" \
433 "PERF_SAMPLE_BRANCH_HW_INDEX|" \
434 "PERF_SAMPLE_BRANCH_PRIV_SAVE"
435
436 int
437 main(void)
438 {
439 static const size_t attr_small_size = PERF_ATTR_SIZE_VER0 - 8;
440 static const size_t attr_v0_size = PERF_ATTR_SIZE_VER0;
441 static const size_t attr_v1_size = PERF_ATTR_SIZE_VER1;
442 static const size_t attr_v2_size = PERF_ATTR_SIZE_VER2;
443 static const size_t attr_v2_5_size = PERF_ATTR_SIZE_VER2 + 8;
444 static const size_t attr_v2_75_size = PERF_ATTR_SIZE_VER2 + 12;
445 static const size_t attr_v3_size = PERF_ATTR_SIZE_VER3;
446 static const size_t attr_v4_size = PERF_ATTR_SIZE_VER4;
447 static const size_t attr_v4_5_size = PERF_ATTR_SIZE_VER4 + 4;
448 static const size_t attr_v4_625_size = PERF_ATTR_SIZE_VER4 + 5;
449 static const size_t attr_v4_875_size = PERF_ATTR_SIZE_VER4 + 7;
450 static const size_t attr_v5_size = PERF_ATTR_SIZE_VER5;
451 static const size_t attr_v5_25_size = PERF_ATTR_SIZE_VER5 + 2;
452 static const size_t attr_v5_5_size = PERF_ATTR_SIZE_VER5 + 4;
453 static const size_t attr_v5_75_size = PERF_ATTR_SIZE_VER5 + 6;
454 static const size_t attr_v6_size = PERF_ATTR_SIZE_VER6;
455 static const size_t attr_v6_5_size = PERF_ATTR_SIZE_VER6 + 4;
456 static const size_t attr_v7_size = PERF_ATTR_SIZE_VER7;
457 static const size_t attr_big_size = PERF_ATTR_SIZE_VER7 + 32;
458
459 static const struct u64_val_str attr_types[] = {
460 { ARG_STR(PERF_TYPE_HARDWARE) },
461 { ARG_STR(PERF_TYPE_SOFTWARE) },
462 { ARG_STR(PERF_TYPE_TRACEPOINT) },
463 { ARG_STR(PERF_TYPE_HW_CACHE) },
464 { ARG_STR(PERF_TYPE_RAW) },
465 { ARG_STR(PERF_TYPE_BREAKPOINT) },
466 { ARG_STR(0x6) " /* PERF_TYPE_??? */" },
467 { ARG_STR(0xdeadc0de) " /* PERF_TYPE_??? */" },
468 };
469 static const struct u64_val_str
470 attr_configs[ARRAY_SIZE(attr_types)][3] = {
471 /* PERF_TYPE_HARDWARE */ {
472 { 9, "PERF_COUNT_HW_REF_CPU_CYCLES" },
473 { 10, "0xa /* PERF_COUNT_HW_??? */" },
474 { 0xfaceca7500000004, "0xfaceca75<<32|"
475 "PERF_COUNT_HW_BRANCH_INSTRUCTIONS" },
476 },
477 /* PERF_TYPE_SOFTWARE */ {
478 { 11, "PERF_COUNT_SW_CGROUP_SWITCHES" },
479 { 12, "0xc /* PERF_COUNT_SW_??? */" },
480 { ARG_ULL_STR(0xdec0ded1dec0ded2)
481 " /* PERF_COUNT_SW_??? */" },
482 },
483 /* PERF_TYPE_TRACEPOINT */ {
484 { ARG_STR(0) },
485 { 4207856245U, "4207856245" },
486 { ARG_ULL_STR(16051074073505095380) },
487 },
488 /* PERF_TYPE_HW_CACHE */ {
489 { 0, "PERF_COUNT_HW_CACHE_RESULT_ACCESS<<16|"
490 "PERF_COUNT_HW_CACHE_OP_READ<<8|"
491 "PERF_COUNT_HW_CACHE_L1D" },
492 { 0x01020207, "0x1<<24|"
493 "0x2 /* PERF_COUNT_HW_CACHE_RESULT_??? */<<16|"
494 "PERF_COUNT_HW_CACHE_OP_PREFETCH<<8|"
495 "0x7 /* PERF_COUNT_HW_CACHE_??? */" },
496 { 0xdeadf15700010306ULL, "0xdeadf157<<32|"
497 "PERF_COUNT_HW_CACHE_RESULT_MISS<<16|"
498 "0x3 /* PERF_COUNT_HW_CACHE_OP_??? */<<8|"
499 "PERF_COUNT_HW_CACHE_NODE" },
500 },
501 /* PERF_TYPE_RAW */ {
502 { ARG_STR(0) },
503 { ARG_STR(0xda7a1057) },
504 { ARG_ULL_STR(0xdec0ded7dec0ded8) },
505 },
506 /* PERF_TYPE_BREAKPOINT */ {
507 { ARG_STR(0) },
508 { ARG_STR(0xbadc0ded) },
509 { ARG_ULL_STR(0xdec0ded9dec0deda) },
510 },
511 /* invalid 1 */ {
512 { ARG_STR(0) },
513 { ARG_STR(0xbeeff00d) },
514 { ARG_ULL_STR(0xdec0dedbdec0dedc) },
515 },
516 /* invalid 2 */ {
517 { ARG_STR(0) },
518 { ARG_STR(0xca75dead) },
519 { ARG_ULL_STR(0xdec0dedddec0dede) },
520 },
521 };
522 static const struct u64_val_str sample_types[] = {
523 { ARG_STR(0) },
524 { 0x800, "PERF_SAMPLE_BRANCH_STACK" },
525 { ARG_ULL_STR(0xdeadc0deda000000) " /* PERF_SAMPLE_??? */" },
526 { 0xffffffffffffffffULL,
527 "PERF_SAMPLE_IP|PERF_SAMPLE_TID|PERF_SAMPLE_TIME|"
528 "PERF_SAMPLE_ADDR|PERF_SAMPLE_READ|"
529 "PERF_SAMPLE_CALLCHAIN|PERF_SAMPLE_ID|PERF_SAMPLE_CPU|"
530 "PERF_SAMPLE_PERIOD|PERF_SAMPLE_STREAM_ID|"
531 "PERF_SAMPLE_RAW|PERF_SAMPLE_BRANCH_STACK|"
532 "PERF_SAMPLE_REGS_USER|PERF_SAMPLE_STACK_USER|"
533 "PERF_SAMPLE_WEIGHT|PERF_SAMPLE_DATA_SRC|"
534 "PERF_SAMPLE_IDENTIFIER|PERF_SAMPLE_TRANSACTION|"
535 "PERF_SAMPLE_REGS_INTR|PERF_SAMPLE_PHYS_ADDR|"
536 "PERF_SAMPLE_AUX|PERF_SAMPLE_CGROUP|"
537 "PERF_SAMPLE_DATA_PAGE_SIZE|PERF_SAMPLE_CODE_PAGE_SIZE|"
538 "PERF_SAMPLE_WEIGHT_STRUCT|"
539 "0xfffffffffe000000" },
540 };
541 static const struct u64_val_str read_formats[] = {
542 { ARG_STR(0) },
543 { ARG_STR(PERF_FORMAT_TOTAL_TIME_ENABLED) },
544 { 0x1f, "PERF_FORMAT_TOTAL_TIME_ENABLED|"
545 "PERF_FORMAT_TOTAL_TIME_RUNNING|"
546 "PERF_FORMAT_ID|"
547 "PERF_FORMAT_GROUP|"
548 "PERF_FORMAT_LOST" },
549 { ARG_ULL_STR(0xdeadf157dec0dee0) " /* PERF_FORMAT_??? */" },
550 { 0xffffffffffffffffULL,
551 "PERF_FORMAT_TOTAL_TIME_ENABLED|"
552 "PERF_FORMAT_TOTAL_TIME_RUNNING|"
553 "PERF_FORMAT_ID|PERF_FORMAT_GROUP|"
554 "PERF_FORMAT_LOST|"
555 "0xffffffffffffffe0" },
556 };
557 static const char *precise_ip_descs[] = {
558 "arbitrary skid",
559 "constant skid",
560 "requested to have 0 skid",
561 "must have 0 skid",
562 };
563 static const struct u32_val_str bp_types[] = {
564 { 0, "HW_BREAKPOINT_EMPTY" },
565 { 1, "HW_BREAKPOINT_R" },
566 { 3, "HW_BREAKPOINT_RW" },
567 { 5, "0x5 /* HW_BREAKPOINT_INVALID */" },
568 { 8, "0x8 /* HW_BREAKPOINT_??? */" },
569 { ARG_STR(0xface1e55) " /* HW_BREAKPOINT_??? */" },
570 };
571 static const struct u64_val_str branch_sample_types[] = {
572 { ARG_STR(0) },
573 { 0x80, "PERF_SAMPLE_BRANCH_ABORT_TX" },
574 { 0x7ffff, BRANCH_TYPE_ALL },
575 { ARG_ULL_STR(0xdeadcaffeee80000)
576 " /* PERF_SAMPLE_BRANCH_??? */" },
577 { 0xffffffffffffffffULL,
578 BRANCH_TYPE_ALL "|0xfffffffffff80000" }
579 };
580 static const struct s32_val_str clockids[] = {
581 { 11, "CLOCK_TAI" },
582 { ARG_STR(0xc) " /* CLOCK_??? */" },
583 { ARG_STR(0xbeeffeed) " /* CLOCK_??? */" },
584 };
585
586
587 struct {
588 struct perf_event_attr *ptr;
589 size_t size;
590 } attrs[] = {
591 ATTR_REC(sizeof(struct perf_event_attr)),
592 ATTR_REC(attr_v0_size),
593 ATTR_REC(attr_v1_size),
594 ATTR_REC(attr_v2_size),
595 ATTR_REC(attr_v2_5_size),
596 ATTR_REC(attr_v2_75_size),
597 ATTR_REC(attr_v3_size),
598 ATTR_REC(attr_v4_size),
599 ATTR_REC(attr_v4_5_size),
600 ATTR_REC(attr_v4_625_size),
601 ATTR_REC(attr_v4_875_size),
602 ATTR_REC(attr_v5_size),
603 ATTR_REC(attr_v5_25_size),
604 ATTR_REC(attr_v5_5_size),
605 ATTR_REC(attr_v5_75_size),
606 ATTR_REC(attr_v6_size),
607 ATTR_REC(attr_v6_5_size),
608 ATTR_REC(attr_v7_size),
609 ATTR_REC(attr_big_size),
610 };
611
612 TAIL_ALLOC_OBJECT_CONST_PTR(struct perf_event_attr, small_attr);
613
614 struct {
615 struct perf_event_attr *attr;
616 pid_t pid;
617 int cpu;
618 int group_fd;
619 unsigned long flags;
620 const char *flags_str;
621 } args[] = {
622 { NULL, 0xfacef00d, 0xbadabba7, -1,
623 (unsigned long) 0xFFFFFFFFFFFFFFFFLLU,
624 "PERF_FLAG_FD_NO_GROUP|PERF_FLAG_FD_OUTPUT|"
625 "PERF_FLAG_PID_CGROUP|PERF_FLAG_FD_CLOEXEC|"
626 "0x" LONG_STR_PREFIX "fffffff0"
627 },
628 { small_attr + 1, 0, 0, 0,
629 0, "0" },
630 { small_attr, -1, -1, 1,
631 PERF_FLAG_FD_NO_GROUP | PERF_FLAG_FD_OUTPUT |
632 PERF_FLAG_PID_CGROUP | PERF_FLAG_FD_CLOEXEC,
633 "PERF_FLAG_FD_NO_GROUP|PERF_FLAG_FD_OUTPUT|"
634 "PERF_FLAG_PID_CGROUP|PERF_FLAG_FD_CLOEXEC" },
635 { (struct perf_event_attr *) (uintptr_t) 0xfffffacefffffeedULL,
636 -100, 100, 0xface1e55,
637 PERF_FLAG_FD_CLOEXEC, "PERF_FLAG_FD_CLOEXEC" },
638 };
639
640 int rc;
641
642 fill_memory(small_attr, sizeof(*small_attr));
643 small_attr->size = attr_small_size;
644
645 for (size_t i = 0; i < ARRAY_SIZE(args); ++i) {
646 rc = syscall(__NR_perf_event_open, args[i].attr, args[i].pid,
647 args[i].cpu, args[i].group_fd, args[i].flags);
648 printf("perf_event_open(%s, %d, %d, %d, %s) = %s\n",
649 printaddr(args[i].attr), args[i].pid, args[i].cpu,
650 args[i].group_fd, args[i].flags_str, sprintrc(rc));
651 }
652
653 for (size_t i = 0; i < ARRAY_SIZE(attrs) * ARRAY_SIZE(attr_types) *
654 ARRAY_SIZE(attr_configs[0]) + 1; ++i) {
655 struct perf_event_attr *attr = attrs[i % ARRAY_SIZE(attrs)].ptr;
656 uint32_t size = attrs[i % ARRAY_SIZE(attrs)].size;
657 unsigned char fill_start = 0x80 + i;
658 size_t type_idx = i % ARRAY_SIZE(attr_types);
659 size_t config_idx = i % ARRAY_SIZE(attr_configs[0]);
660 size_t sample_type_idx = i % ARRAY_SIZE(sample_types);
661 size_t read_format_idx = i % ARRAY_SIZE(read_formats);
662 size_t bp_type_idx = (i / ARRAY_SIZE(attr_configs[0])) %
663 ARRAY_SIZE(bp_types);
664 size_t branch_sample_type_idx = (i / ARRAY_SIZE(sample_types)) %
665 ARRAY_SIZE(branch_sample_types);
666 size_t clockid_idx = i % ARRAY_SIZE(clockids);
667 size_t args_idx = i % ARRAY_SIZE(args);
668 const char *ip_desc_str;
669
670 fill_memory_ex(attr, size, fill_start, 0xff);
671
672 attr->type = attr_types[type_idx].val;
673 attr->size = size;
674 attr->config = attr_configs[type_idx][config_idx].val;
675 attr->sample_type = sample_types[sample_type_idx].val;
676 attr->read_format = read_formats[read_format_idx].val;
677
678 if ((i % 11) == 5)
679 attr->__reserved_1 = 0;
680
681 attr->bp_type = bp_types[bp_type_idx].val;
682
683 if (size >= 80)
684 attr->branch_sample_type =
685 branch_sample_types[branch_sample_type_idx].val;
686
687 if (size >= 96)
688 attr->clockid =
689 clockids[clockid_idx].val;
690
691 ip_desc_str = precise_ip_descs[attr->precise_ip];
692
693 if (((i % 17) == 3) && (size >= 112))
694 ((uint16_t *) attr)[110 / sizeof(uint16_t)] = 0;
695
696 if (((i % 23) == 7) && (size >= 120))
697 ((uint32_t *) attr)[116 / sizeof(uint32_t)] = 0;
698
699 if (i == 0)
700 attr->size = size + 8;
701
702 if (i == 1)
703 attr->size = 0;
704
705 rc = syscall(__NR_perf_event_open, attr, args[args_idx].pid,
706 args[args_idx].cpu, args[args_idx].group_fd,
707 args[args_idx].flags);
708
709 printf("perf_event_open(");
710 print_event_attr(attr, i ? ((i == 1) ? 0 : size) : size + 8,
711 attr_types[type_idx].str,
712 attr_configs[type_idx][config_idx].str,
713 sample_types[sample_type_idx].str,
714 read_formats[read_format_idx].str,
715 ip_desc_str,
716 bp_types[bp_type_idx].str,
717 branch_sample_types[branch_sample_type_idx].str,
718 clockids[clockid_idx].str, size);
719 printf(", %d, %d, %d, %s) = %s\n", args[args_idx].pid,
720 args[args_idx].cpu, args[args_idx].group_fd,
721 args[args_idx].flags_str, sprintrc(rc));
722 }
723
724 puts("+++ exited with 0 +++");
725 return 0;
726 }