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

block-range.c (7024B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include "block-range.h"
      3#include "annotate.h"
      4#include <assert.h>
      5#include <stdlib.h>
      6
      7struct {
      8	struct rb_root root;
      9	u64 blocks;
     10} block_ranges;
     11
     12static void block_range__debug(void)
     13{
     14	/*
     15	 * XXX still paranoid for now; see if we can make this depend on
     16	 * DEBUG=1 builds.
     17	 */
     18#if 1
     19	struct rb_node *rb;
     20	u64 old = 0; /* NULL isn't executable */
     21
     22	for (rb = rb_first(&block_ranges.root); rb; rb = rb_next(rb)) {
     23		struct block_range *entry = rb_entry(rb, struct block_range, node);
     24
     25		assert(old < entry->start);
     26		assert(entry->start <= entry->end); /* single instruction block; jump to a jump */
     27
     28		old = entry->end;
     29	}
     30#endif
     31}
     32
     33struct block_range *block_range__find(u64 addr)
     34{
     35	struct rb_node **p = &block_ranges.root.rb_node;
     36	struct rb_node *parent = NULL;
     37	struct block_range *entry;
     38
     39	while (*p != NULL) {
     40		parent = *p;
     41		entry = rb_entry(parent, struct block_range, node);
     42
     43		if (addr < entry->start)
     44			p = &parent->rb_left;
     45		else if (addr > entry->end)
     46			p = &parent->rb_right;
     47		else
     48			return entry;
     49	}
     50
     51	return NULL;
     52}
     53
     54static inline void rb_link_left_of_node(struct rb_node *left, struct rb_node *node)
     55{
     56	struct rb_node **p = &node->rb_left;
     57	while (*p) {
     58		node = *p;
     59		p = &node->rb_right;
     60	}
     61	rb_link_node(left, node, p);
     62}
     63
     64static inline void rb_link_right_of_node(struct rb_node *right, struct rb_node *node)
     65{
     66	struct rb_node **p = &node->rb_right;
     67	while (*p) {
     68		node = *p;
     69		p = &node->rb_left;
     70	}
     71	rb_link_node(right, node, p);
     72}
     73
     74/**
     75 * block_range__create
     76 * @start: branch target starting this basic block
     77 * @end:   branch ending this basic block
     78 *
     79 * Create all the required block ranges to precisely span the given range.
     80 */
     81struct block_range_iter block_range__create(u64 start, u64 end)
     82{
     83	struct rb_node **p = &block_ranges.root.rb_node;
     84	struct rb_node *n, *parent = NULL;
     85	struct block_range *next, *entry = NULL;
     86	struct block_range_iter iter = { NULL, NULL };
     87
     88	while (*p != NULL) {
     89		parent = *p;
     90		entry = rb_entry(parent, struct block_range, node);
     91
     92		if (start < entry->start)
     93			p = &parent->rb_left;
     94		else if (start > entry->end)
     95			p = &parent->rb_right;
     96		else
     97			break;
     98	}
     99
    100	/*
    101	 * Didn't find anything.. there's a hole at @start, however @end might
    102	 * be inside/behind the next range.
    103	 */
    104	if (!*p) {
    105		if (!entry) /* tree empty */
    106			goto do_whole;
    107
    108		/*
    109		 * If the last node is before, advance one to find the next.
    110		 */
    111		n = parent;
    112		if (entry->end < start) {
    113			n = rb_next(n);
    114			if (!n)
    115				goto do_whole;
    116		}
    117		next = rb_entry(n, struct block_range, node);
    118
    119		if (next->start <= end) { /* add head: [start...][n->start...] */
    120			struct block_range *head = malloc(sizeof(struct block_range));
    121			if (!head)
    122				return iter;
    123
    124			*head = (struct block_range){
    125				.start		= start,
    126				.end		= next->start - 1,
    127				.is_target	= 1,
    128				.is_branch	= 0,
    129			};
    130
    131			rb_link_left_of_node(&head->node, &next->node);
    132			rb_insert_color(&head->node, &block_ranges.root);
    133			block_range__debug();
    134
    135			iter.start = head;
    136			goto do_tail;
    137		}
    138
    139do_whole:
    140		/*
    141		 * The whole [start..end] range is non-overlapping.
    142		 */
    143		entry = malloc(sizeof(struct block_range));
    144		if (!entry)
    145			return iter;
    146
    147		*entry = (struct block_range){
    148			.start		= start,
    149			.end		= end,
    150			.is_target	= 1,
    151			.is_branch	= 1,
    152		};
    153
    154		rb_link_node(&entry->node, parent, p);
    155		rb_insert_color(&entry->node, &block_ranges.root);
    156		block_range__debug();
    157
    158		iter.start = entry;
    159		iter.end   = entry;
    160		goto done;
    161	}
    162
    163	/*
    164	 * We found a range that overlapped with ours, split if needed.
    165	 */
    166	if (entry->start < start) { /* split: [e->start...][start...] */
    167		struct block_range *head = malloc(sizeof(struct block_range));
    168		if (!head)
    169			return iter;
    170
    171		*head = (struct block_range){
    172			.start		= entry->start,
    173			.end		= start - 1,
    174			.is_target	= entry->is_target,
    175			.is_branch	= 0,
    176
    177			.coverage	= entry->coverage,
    178			.entry		= entry->entry,
    179		};
    180
    181		entry->start		= start;
    182		entry->is_target	= 1;
    183		entry->entry		= 0;
    184
    185		rb_link_left_of_node(&head->node, &entry->node);
    186		rb_insert_color(&head->node, &block_ranges.root);
    187		block_range__debug();
    188
    189	} else if (entry->start == start)
    190		entry->is_target = 1;
    191
    192	iter.start = entry;
    193
    194do_tail:
    195	/*
    196	 * At this point we've got: @iter.start = [@start...] but @end can still be
    197	 * inside or beyond it.
    198	 */
    199	entry = iter.start;
    200	for (;;) {
    201		/*
    202		 * If @end is inside @entry, split.
    203		 */
    204		if (end < entry->end) { /* split: [...end][...e->end] */
    205			struct block_range *tail = malloc(sizeof(struct block_range));
    206			if (!tail)
    207				return iter;
    208
    209			*tail = (struct block_range){
    210				.start		= end + 1,
    211				.end		= entry->end,
    212				.is_target	= 0,
    213				.is_branch	= entry->is_branch,
    214
    215				.coverage	= entry->coverage,
    216				.taken		= entry->taken,
    217				.pred		= entry->pred,
    218			};
    219
    220			entry->end		= end;
    221			entry->is_branch	= 1;
    222			entry->taken		= 0;
    223			entry->pred		= 0;
    224
    225			rb_link_right_of_node(&tail->node, &entry->node);
    226			rb_insert_color(&tail->node, &block_ranges.root);
    227			block_range__debug();
    228
    229			iter.end = entry;
    230			goto done;
    231		}
    232
    233		/*
    234		 * If @end matches @entry, done
    235		 */
    236		if (end == entry->end) {
    237			entry->is_branch = 1;
    238			iter.end = entry;
    239			goto done;
    240		}
    241
    242		next = block_range__next(entry);
    243		if (!next)
    244			goto add_tail;
    245
    246		/*
    247		 * If @end is in beyond @entry but not inside @next, add tail.
    248		 */
    249		if (end < next->start) { /* add tail: [...e->end][...end] */
    250			struct block_range *tail;
    251add_tail:
    252			tail = malloc(sizeof(struct block_range));
    253			if (!tail)
    254				return iter;
    255
    256			*tail = (struct block_range){
    257				.start		= entry->end + 1,
    258				.end		= end,
    259				.is_target	= 0,
    260				.is_branch	= 1,
    261			};
    262
    263			rb_link_right_of_node(&tail->node, &entry->node);
    264			rb_insert_color(&tail->node, &block_ranges.root);
    265			block_range__debug();
    266
    267			iter.end = tail;
    268			goto done;
    269		}
    270
    271		/*
    272		 * If there is a hole between @entry and @next, fill it.
    273		 */
    274		if (entry->end + 1 != next->start) {
    275			struct block_range *hole = malloc(sizeof(struct block_range));
    276			if (!hole)
    277				return iter;
    278
    279			*hole = (struct block_range){
    280				.start		= entry->end + 1,
    281				.end		= next->start - 1,
    282				.is_target	= 0,
    283				.is_branch	= 0,
    284			};
    285
    286			rb_link_left_of_node(&hole->node, &next->node);
    287			rb_insert_color(&hole->node, &block_ranges.root);
    288			block_range__debug();
    289		}
    290
    291		entry = next;
    292	}
    293
    294done:
    295	assert(iter.start->start == start && iter.start->is_target);
    296	assert(iter.end->end == end && iter.end->is_branch);
    297
    298	block_ranges.blocks++;
    299
    300	return iter;
    301}
    302
    303
    304/*
    305 * Compute coverage as:
    306 *
    307 *    br->coverage / br->sym->max_coverage
    308 *
    309 * This ensures each symbol has a 100% spot, to reflect that each symbol has a
    310 * most covered section.
    311 *
    312 * Returns [0-1] for coverage and -1 if we had no data what so ever or the
    313 * symbol does not exist.
    314 */
    315double block_range__coverage(struct block_range *br)
    316{
    317	struct symbol *sym;
    318
    319	if (!br) {
    320		if (block_ranges.blocks)
    321			return 0;
    322
    323		return -1;
    324	}
    325
    326	sym = br->sym;
    327	if (!sym)
    328		return -1;
    329
    330	return (double)br->coverage / symbol__annotation(sym)->max_coverage;
    331}