cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sample-parsing.c (10592B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <stdbool.h>
      3#include <inttypes.h>
      4#include <stdlib.h>
      5#include <string.h>
      6#include <linux/bitops.h>
      7#include <linux/kernel.h>
      8#include <linux/types.h>
      9
     10#include "map_symbol.h"
     11#include "branch.h"
     12#include "event.h"
     13#include "evsel.h"
     14#include "debug.h"
     15#include "util/synthetic-events.h"
     16#include "util/trace-event.h"
     17
     18#include "tests.h"
     19
     20#define COMP(m) do {					\
     21	if (s1->m != s2->m) {				\
     22		pr_debug("Samples differ at '"#m"'\n");	\
     23		return false;				\
     24	}						\
     25} while (0)
     26
     27#define MCOMP(m) do {					\
     28	if (memcmp(&s1->m, &s2->m, sizeof(s1->m))) {	\
     29		pr_debug("Samples differ at '"#m"'\n");	\
     30		return false;				\
     31	}						\
     32} while (0)
     33
     34/*
     35 * Hardcode the expected values for branch_entry flags.
     36 * These are based on the input value (213) specified
     37 * in branch_stack variable.
     38 */
     39#define BS_EXPECTED_BE	0xa000d00000000000
     40#define BS_EXPECTED_LE	0xd5000000
     41#define FLAG(s)	s->branch_stack->entries[i].flags
     42
     43static bool samples_same(const struct perf_sample *s1,
     44			 const struct perf_sample *s2,
     45			 u64 type, u64 read_format, bool needs_swap)
     46{
     47	size_t i;
     48
     49	if (type & PERF_SAMPLE_IDENTIFIER)
     50		COMP(id);
     51
     52	if (type & PERF_SAMPLE_IP)
     53		COMP(ip);
     54
     55	if (type & PERF_SAMPLE_TID) {
     56		COMP(pid);
     57		COMP(tid);
     58	}
     59
     60	if (type & PERF_SAMPLE_TIME)
     61		COMP(time);
     62
     63	if (type & PERF_SAMPLE_ADDR)
     64		COMP(addr);
     65
     66	if (type & PERF_SAMPLE_ID)
     67		COMP(id);
     68
     69	if (type & PERF_SAMPLE_STREAM_ID)
     70		COMP(stream_id);
     71
     72	if (type & PERF_SAMPLE_CPU)
     73		COMP(cpu);
     74
     75	if (type & PERF_SAMPLE_PERIOD)
     76		COMP(period);
     77
     78	if (type & PERF_SAMPLE_READ) {
     79		if (read_format & PERF_FORMAT_GROUP)
     80			COMP(read.group.nr);
     81		else
     82			COMP(read.one.value);
     83		if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
     84			COMP(read.time_enabled);
     85		if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
     86			COMP(read.time_running);
     87		/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
     88		if (read_format & PERF_FORMAT_GROUP) {
     89			for (i = 0; i < s1->read.group.nr; i++)
     90				MCOMP(read.group.values[i]);
     91		} else {
     92			COMP(read.one.id);
     93		}
     94	}
     95
     96	if (type & PERF_SAMPLE_CALLCHAIN) {
     97		COMP(callchain->nr);
     98		for (i = 0; i < s1->callchain->nr; i++)
     99			COMP(callchain->ips[i]);
    100	}
    101
    102	if (type & PERF_SAMPLE_RAW) {
    103		COMP(raw_size);
    104		if (memcmp(s1->raw_data, s2->raw_data, s1->raw_size)) {
    105			pr_debug("Samples differ at 'raw_data'\n");
    106			return false;
    107		}
    108	}
    109
    110	if (type & PERF_SAMPLE_BRANCH_STACK) {
    111		COMP(branch_stack->nr);
    112		COMP(branch_stack->hw_idx);
    113		for (i = 0; i < s1->branch_stack->nr; i++) {
    114			if (needs_swap)
    115				return ((tep_is_bigendian()) ?
    116					(FLAG(s2).value == BS_EXPECTED_BE) :
    117					(FLAG(s2).value == BS_EXPECTED_LE));
    118			else
    119				MCOMP(branch_stack->entries[i]);
    120		}
    121	}
    122
    123	if (type & PERF_SAMPLE_REGS_USER) {
    124		size_t sz = hweight_long(s1->user_regs.mask) * sizeof(u64);
    125
    126		COMP(user_regs.mask);
    127		COMP(user_regs.abi);
    128		if (s1->user_regs.abi &&
    129		    (!s1->user_regs.regs || !s2->user_regs.regs ||
    130		     memcmp(s1->user_regs.regs, s2->user_regs.regs, sz))) {
    131			pr_debug("Samples differ at 'user_regs'\n");
    132			return false;
    133		}
    134	}
    135
    136	if (type & PERF_SAMPLE_STACK_USER) {
    137		COMP(user_stack.size);
    138		if (memcmp(s1->user_stack.data, s2->user_stack.data,
    139			   s1->user_stack.size)) {
    140			pr_debug("Samples differ at 'user_stack'\n");
    141			return false;
    142		}
    143	}
    144
    145	if (type & PERF_SAMPLE_WEIGHT)
    146		COMP(weight);
    147
    148	if (type & PERF_SAMPLE_DATA_SRC)
    149		COMP(data_src);
    150
    151	if (type & PERF_SAMPLE_TRANSACTION)
    152		COMP(transaction);
    153
    154	if (type & PERF_SAMPLE_REGS_INTR) {
    155		size_t sz = hweight_long(s1->intr_regs.mask) * sizeof(u64);
    156
    157		COMP(intr_regs.mask);
    158		COMP(intr_regs.abi);
    159		if (s1->intr_regs.abi &&
    160		    (!s1->intr_regs.regs || !s2->intr_regs.regs ||
    161		     memcmp(s1->intr_regs.regs, s2->intr_regs.regs, sz))) {
    162			pr_debug("Samples differ at 'intr_regs'\n");
    163			return false;
    164		}
    165	}
    166
    167	if (type & PERF_SAMPLE_PHYS_ADDR)
    168		COMP(phys_addr);
    169
    170	if (type & PERF_SAMPLE_CGROUP)
    171		COMP(cgroup);
    172
    173	if (type & PERF_SAMPLE_DATA_PAGE_SIZE)
    174		COMP(data_page_size);
    175
    176	if (type & PERF_SAMPLE_CODE_PAGE_SIZE)
    177		COMP(code_page_size);
    178
    179	if (type & PERF_SAMPLE_AUX) {
    180		COMP(aux_sample.size);
    181		if (memcmp(s1->aux_sample.data, s2->aux_sample.data,
    182			   s1->aux_sample.size)) {
    183			pr_debug("Samples differ at 'aux_sample'\n");
    184			return false;
    185		}
    186	}
    187
    188	return true;
    189}
    190
    191static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
    192{
    193	struct evsel evsel = {
    194		.needs_swap = false,
    195		.core = {
    196			. attr = {
    197				.sample_type = sample_type,
    198				.read_format = read_format,
    199			},
    200		},
    201	};
    202	union perf_event *event;
    203	union {
    204		struct ip_callchain callchain;
    205		u64 data[64];
    206	} callchain = {
    207		/* 3 ips */
    208		.data = {3, 201, 202, 203},
    209	};
    210	union {
    211		struct branch_stack branch_stack;
    212		u64 data[64];
    213	} branch_stack = {
    214		/* 1 branch_entry */
    215		.data = {1, -1ULL, 211, 212, 213},
    216	};
    217	u64 regs[64];
    218	const u32 raw_data[] = {0x12345678, 0x0a0b0c0d, 0x11020304, 0x05060708, 0 };
    219	const u64 data[] = {0x2211443366558877ULL, 0, 0xaabbccddeeff4321ULL};
    220	const u64 aux_data[] = {0xa55a, 0, 0xeeddee, 0x0282028202820282};
    221	struct perf_sample sample = {
    222		.ip		= 101,
    223		.pid		= 102,
    224		.tid		= 103,
    225		.time		= 104,
    226		.addr		= 105,
    227		.id		= 106,
    228		.stream_id	= 107,
    229		.period		= 108,
    230		.weight		= 109,
    231		.cpu		= 110,
    232		.raw_size	= sizeof(raw_data),
    233		.data_src	= 111,
    234		.transaction	= 112,
    235		.raw_data	= (void *)raw_data,
    236		.callchain	= &callchain.callchain,
    237		.no_hw_idx      = false,
    238		.branch_stack	= &branch_stack.branch_stack,
    239		.user_regs	= {
    240			.abi	= PERF_SAMPLE_REGS_ABI_64,
    241			.mask	= sample_regs,
    242			.regs	= regs,
    243		},
    244		.user_stack	= {
    245			.size	= sizeof(data),
    246			.data	= (void *)data,
    247		},
    248		.read		= {
    249			.time_enabled = 0x030a59d664fca7deULL,
    250			.time_running = 0x011b6ae553eb98edULL,
    251		},
    252		.intr_regs	= {
    253			.abi	= PERF_SAMPLE_REGS_ABI_64,
    254			.mask	= sample_regs,
    255			.regs	= regs,
    256		},
    257		.phys_addr	= 113,
    258		.cgroup		= 114,
    259		.data_page_size = 115,
    260		.code_page_size = 116,
    261		.aux_sample	= {
    262			.size	= sizeof(aux_data),
    263			.data	= (void *)aux_data,
    264		},
    265	};
    266	struct sample_read_value values[] = {{1, 5}, {9, 3}, {2, 7}, {6, 4},};
    267	struct perf_sample sample_out, sample_out_endian;
    268	size_t i, sz, bufsz;
    269	int err, ret = -1;
    270
    271	if (sample_type & PERF_SAMPLE_REGS_USER)
    272		evsel.core.attr.sample_regs_user = sample_regs;
    273
    274	if (sample_type & PERF_SAMPLE_REGS_INTR)
    275		evsel.core.attr.sample_regs_intr = sample_regs;
    276
    277	if (sample_type & PERF_SAMPLE_BRANCH_STACK)
    278		evsel.core.attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX;
    279
    280	for (i = 0; i < sizeof(regs); i++)
    281		*(i + (u8 *)regs) = i & 0xfe;
    282
    283	if (read_format & PERF_FORMAT_GROUP) {
    284		sample.read.group.nr     = 4;
    285		sample.read.group.values = values;
    286	} else {
    287		sample.read.one.value = 0x08789faeb786aa87ULL;
    288		sample.read.one.id    = 99;
    289	}
    290
    291	sz = perf_event__sample_event_size(&sample, sample_type, read_format);
    292	bufsz = sz + 4096; /* Add a bit for overrun checking */
    293	event = malloc(bufsz);
    294	if (!event) {
    295		pr_debug("malloc failed\n");
    296		return -1;
    297	}
    298
    299	memset(event, 0xff, bufsz);
    300	event->header.type = PERF_RECORD_SAMPLE;
    301	event->header.misc = 0;
    302	event->header.size = sz;
    303
    304	err = perf_event__synthesize_sample(event, sample_type, read_format,
    305					    &sample);
    306	if (err) {
    307		pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
    308			 "perf_event__synthesize_sample", sample_type, err);
    309		goto out_free;
    310	}
    311
    312	/* The data does not contain 0xff so we use that to check the size */
    313	for (i = bufsz; i > 0; i--) {
    314		if (*(i - 1 + (u8 *)event) != 0xff)
    315			break;
    316	}
    317	if (i != sz) {
    318		pr_debug("Event size mismatch: actual %zu vs expected %zu\n",
    319			 i, sz);
    320		goto out_free;
    321	}
    322
    323	evsel.sample_size = __evsel__sample_size(sample_type);
    324
    325	err = evsel__parse_sample(&evsel, event, &sample_out);
    326	if (err) {
    327		pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
    328			 "evsel__parse_sample", sample_type, err);
    329		goto out_free;
    330	}
    331
    332	if (!samples_same(&sample, &sample_out, sample_type, read_format, evsel.needs_swap)) {
    333		pr_debug("parsing failed for sample_type %#"PRIx64"\n",
    334			 sample_type);
    335		goto out_free;
    336	}
    337
    338	if (sample_type == PERF_SAMPLE_BRANCH_STACK) {
    339		evsel.needs_swap = true;
    340		evsel.sample_size = __evsel__sample_size(sample_type);
    341		err = evsel__parse_sample(&evsel, event, &sample_out_endian);
    342		if (err) {
    343			pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
    344				 "evsel__parse_sample", sample_type, err);
    345			goto out_free;
    346		}
    347
    348		if (!samples_same(&sample, &sample_out_endian, sample_type, read_format, evsel.needs_swap)) {
    349			pr_debug("parsing failed for sample_type %#"PRIx64"\n",
    350				 sample_type);
    351			goto out_free;
    352		}
    353	}
    354
    355	ret = 0;
    356out_free:
    357	free(event);
    358	if (ret && read_format)
    359		pr_debug("read_format %#"PRIx64"\n", read_format);
    360	return ret;
    361}
    362
    363/**
    364 * test__sample_parsing - test sample parsing.
    365 *
    366 * This function implements a test that synthesizes a sample event, parses it
    367 * and then checks that the parsed sample matches the original sample.  The test
    368 * checks sample format bits separately and together.  If the test passes %0 is
    369 * returned, otherwise %-1 is returned.
    370 */
    371static int test__sample_parsing(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
    372{
    373	const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15};
    374	u64 sample_type;
    375	u64 sample_regs;
    376	size_t i;
    377	int err;
    378
    379	/*
    380	 * Fail the test if it has not been updated when new sample format bits
    381	 * were added.  Please actually update the test rather than just change
    382	 * the condition below.
    383	 */
    384	if (PERF_SAMPLE_MAX > PERF_SAMPLE_WEIGHT_STRUCT << 1) {
    385		pr_debug("sample format has changed, some new PERF_SAMPLE_ bit was introduced - test needs updating\n");
    386		return -1;
    387	}
    388
    389	/* Test each sample format bit separately */
    390	for (sample_type = 1; sample_type != PERF_SAMPLE_MAX;
    391	     sample_type <<= 1) {
    392		/* Test read_format variations */
    393		if (sample_type == PERF_SAMPLE_READ) {
    394			for (i = 0; i < ARRAY_SIZE(rf); i++) {
    395				err = do_test(sample_type, 0, rf[i]);
    396				if (err)
    397					return err;
    398			}
    399			continue;
    400		}
    401		sample_regs = 0;
    402
    403		if (sample_type == PERF_SAMPLE_REGS_USER)
    404			sample_regs = 0x3fff;
    405
    406		if (sample_type == PERF_SAMPLE_REGS_INTR)
    407			sample_regs = 0xff0fff;
    408
    409		err = do_test(sample_type, sample_regs, 0);
    410		if (err)
    411			return err;
    412	}
    413
    414	/*
    415	 * Test all sample format bits together
    416	 * Note: PERF_SAMPLE_WEIGHT and PERF_SAMPLE_WEIGHT_STRUCT cannot
    417	 *       be set simultaneously.
    418	 */
    419	sample_type = (PERF_SAMPLE_MAX - 1) & ~PERF_SAMPLE_WEIGHT;
    420	sample_regs = 0x3fff; /* shared yb intr and user regs */
    421	for (i = 0; i < ARRAY_SIZE(rf); i++) {
    422		err = do_test(sample_type, sample_regs, rf[i]);
    423		if (err)
    424			return err;
    425	}
    426
    427	return 0;
    428}
    429
    430DEFINE_SUITE("Sample parsing", sample_parsing);