(root)/
strace-6.5/
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-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  }