| // SPDX-License-Identifier: GPL-2.0 | 
 | #include "block-range.h" | 
 | #include "annotate.h" | 
 |  | 
 | struct { | 
 | 	struct rb_root root; | 
 | 	u64 blocks; | 
 | } block_ranges; | 
 |  | 
 | static void block_range__debug(void) | 
 | { | 
 | 	/* | 
 | 	 * XXX still paranoid for now; see if we can make this depend on | 
 | 	 * DEBUG=1 builds. | 
 | 	 */ | 
 | #if 1 | 
 | 	struct rb_node *rb; | 
 | 	u64 old = 0; /* NULL isn't executable */ | 
 |  | 
 | 	for (rb = rb_first(&block_ranges.root); rb; rb = rb_next(rb)) { | 
 | 		struct block_range *entry = rb_entry(rb, struct block_range, node); | 
 |  | 
 | 		assert(old < entry->start); | 
 | 		assert(entry->start <= entry->end); /* single instruction block; jump to a jump */ | 
 |  | 
 | 		old = entry->end; | 
 | 	} | 
 | #endif | 
 | } | 
 |  | 
 | struct block_range *block_range__find(u64 addr) | 
 | { | 
 | 	struct rb_node **p = &block_ranges.root.rb_node; | 
 | 	struct rb_node *parent = NULL; | 
 | 	struct block_range *entry; | 
 |  | 
 | 	while (*p != NULL) { | 
 | 		parent = *p; | 
 | 		entry = rb_entry(parent, struct block_range, node); | 
 |  | 
 | 		if (addr < entry->start) | 
 | 			p = &parent->rb_left; | 
 | 		else if (addr > entry->end) | 
 | 			p = &parent->rb_right; | 
 | 		else | 
 | 			return entry; | 
 | 	} | 
 |  | 
 | 	return NULL; | 
 | } | 
 |  | 
 | static inline void rb_link_left_of_node(struct rb_node *left, struct rb_node *node) | 
 | { | 
 | 	struct rb_node **p = &node->rb_left; | 
 | 	while (*p) { | 
 | 		node = *p; | 
 | 		p = &node->rb_right; | 
 | 	} | 
 | 	rb_link_node(left, node, p); | 
 | } | 
 |  | 
 | static inline void rb_link_right_of_node(struct rb_node *right, struct rb_node *node) | 
 | { | 
 | 	struct rb_node **p = &node->rb_right; | 
 | 	while (*p) { | 
 | 		node = *p; | 
 | 		p = &node->rb_left; | 
 | 	} | 
 | 	rb_link_node(right, node, p); | 
 | } | 
 |  | 
 | /** | 
 |  * block_range__create | 
 |  * @start: branch target starting this basic block | 
 |  * @end:   branch ending this basic block | 
 |  * | 
 |  * Create all the required block ranges to precisely span the given range. | 
 |  */ | 
 | struct block_range_iter block_range__create(u64 start, u64 end) | 
 | { | 
 | 	struct rb_node **p = &block_ranges.root.rb_node; | 
 | 	struct rb_node *n, *parent = NULL; | 
 | 	struct block_range *next, *entry = NULL; | 
 | 	struct block_range_iter iter = { NULL, NULL }; | 
 |  | 
 | 	while (*p != NULL) { | 
 | 		parent = *p; | 
 | 		entry = rb_entry(parent, struct block_range, node); | 
 |  | 
 | 		if (start < entry->start) | 
 | 			p = &parent->rb_left; | 
 | 		else if (start > entry->end) | 
 | 			p = &parent->rb_right; | 
 | 		else | 
 | 			break; | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * Didn't find anything.. there's a hole at @start, however @end might | 
 | 	 * be inside/behind the next range. | 
 | 	 */ | 
 | 	if (!*p) { | 
 | 		if (!entry) /* tree empty */ | 
 | 			goto do_whole; | 
 |  | 
 | 		/* | 
 | 		 * If the last node is before, advance one to find the next. | 
 | 		 */ | 
 | 		n = parent; | 
 | 		if (entry->end < start) { | 
 | 			n = rb_next(n); | 
 | 			if (!n) | 
 | 				goto do_whole; | 
 | 		} | 
 | 		next = rb_entry(n, struct block_range, node); | 
 |  | 
 | 		if (next->start <= end) { /* add head: [start...][n->start...] */ | 
 | 			struct block_range *head = malloc(sizeof(struct block_range)); | 
 | 			if (!head) | 
 | 				return iter; | 
 |  | 
 | 			*head = (struct block_range){ | 
 | 				.start		= start, | 
 | 				.end		= next->start - 1, | 
 | 				.is_target	= 1, | 
 | 				.is_branch	= 0, | 
 | 			}; | 
 |  | 
 | 			rb_link_left_of_node(&head->node, &next->node); | 
 | 			rb_insert_color(&head->node, &block_ranges.root); | 
 | 			block_range__debug(); | 
 |  | 
 | 			iter.start = head; | 
 | 			goto do_tail; | 
 | 		} | 
 |  | 
 | do_whole: | 
 | 		/* | 
 | 		 * The whole [start..end] range is non-overlapping. | 
 | 		 */ | 
 | 		entry = malloc(sizeof(struct block_range)); | 
 | 		if (!entry) | 
 | 			return iter; | 
 |  | 
 | 		*entry = (struct block_range){ | 
 | 			.start		= start, | 
 | 			.end		= end, | 
 | 			.is_target	= 1, | 
 | 			.is_branch	= 1, | 
 | 		}; | 
 |  | 
 | 		rb_link_node(&entry->node, parent, p); | 
 | 		rb_insert_color(&entry->node, &block_ranges.root); | 
 | 		block_range__debug(); | 
 |  | 
 | 		iter.start = entry; | 
 | 		iter.end   = entry; | 
 | 		goto done; | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * We found a range that overlapped with ours, split if needed. | 
 | 	 */ | 
 | 	if (entry->start < start) { /* split: [e->start...][start...] */ | 
 | 		struct block_range *head = malloc(sizeof(struct block_range)); | 
 | 		if (!head) | 
 | 			return iter; | 
 |  | 
 | 		*head = (struct block_range){ | 
 | 			.start		= entry->start, | 
 | 			.end		= start - 1, | 
 | 			.is_target	= entry->is_target, | 
 | 			.is_branch	= 0, | 
 |  | 
 | 			.coverage	= entry->coverage, | 
 | 			.entry		= entry->entry, | 
 | 		}; | 
 |  | 
 | 		entry->start		= start; | 
 | 		entry->is_target	= 1; | 
 | 		entry->entry		= 0; | 
 |  | 
 | 		rb_link_left_of_node(&head->node, &entry->node); | 
 | 		rb_insert_color(&head->node, &block_ranges.root); | 
 | 		block_range__debug(); | 
 |  | 
 | 	} else if (entry->start == start) | 
 | 		entry->is_target = 1; | 
 |  | 
 | 	iter.start = entry; | 
 |  | 
 | do_tail: | 
 | 	/* | 
 | 	 * At this point we've got: @iter.start = [@start...] but @end can still be | 
 | 	 * inside or beyond it. | 
 | 	 */ | 
 | 	entry = iter.start; | 
 | 	for (;;) { | 
 | 		/* | 
 | 		 * If @end is inside @entry, split. | 
 | 		 */ | 
 | 		if (end < entry->end) { /* split: [...end][...e->end] */ | 
 | 			struct block_range *tail = malloc(sizeof(struct block_range)); | 
 | 			if (!tail) | 
 | 				return iter; | 
 |  | 
 | 			*tail = (struct block_range){ | 
 | 				.start		= end + 1, | 
 | 				.end		= entry->end, | 
 | 				.is_target	= 0, | 
 | 				.is_branch	= entry->is_branch, | 
 |  | 
 | 				.coverage	= entry->coverage, | 
 | 				.taken		= entry->taken, | 
 | 				.pred		= entry->pred, | 
 | 			}; | 
 |  | 
 | 			entry->end		= end; | 
 | 			entry->is_branch	= 1; | 
 | 			entry->taken		= 0; | 
 | 			entry->pred		= 0; | 
 |  | 
 | 			rb_link_right_of_node(&tail->node, &entry->node); | 
 | 			rb_insert_color(&tail->node, &block_ranges.root); | 
 | 			block_range__debug(); | 
 |  | 
 | 			iter.end = entry; | 
 | 			goto done; | 
 | 		} | 
 |  | 
 | 		/* | 
 | 		 * If @end matches @entry, done | 
 | 		 */ | 
 | 		if (end == entry->end) { | 
 | 			entry->is_branch = 1; | 
 | 			iter.end = entry; | 
 | 			goto done; | 
 | 		} | 
 |  | 
 | 		next = block_range__next(entry); | 
 | 		if (!next) | 
 | 			goto add_tail; | 
 |  | 
 | 		/* | 
 | 		 * If @end is in beyond @entry but not inside @next, add tail. | 
 | 		 */ | 
 | 		if (end < next->start) { /* add tail: [...e->end][...end] */ | 
 | 			struct block_range *tail; | 
 | add_tail: | 
 | 			tail = malloc(sizeof(struct block_range)); | 
 | 			if (!tail) | 
 | 				return iter; | 
 |  | 
 | 			*tail = (struct block_range){ | 
 | 				.start		= entry->end + 1, | 
 | 				.end		= end, | 
 | 				.is_target	= 0, | 
 | 				.is_branch	= 1, | 
 | 			}; | 
 |  | 
 | 			rb_link_right_of_node(&tail->node, &entry->node); | 
 | 			rb_insert_color(&tail->node, &block_ranges.root); | 
 | 			block_range__debug(); | 
 |  | 
 | 			iter.end = tail; | 
 | 			goto done; | 
 | 		} | 
 |  | 
 | 		/* | 
 | 		 * If there is a hole between @entry and @next, fill it. | 
 | 		 */ | 
 | 		if (entry->end + 1 != next->start) { | 
 | 			struct block_range *hole = malloc(sizeof(struct block_range)); | 
 | 			if (!hole) | 
 | 				return iter; | 
 |  | 
 | 			*hole = (struct block_range){ | 
 | 				.start		= entry->end + 1, | 
 | 				.end		= next->start - 1, | 
 | 				.is_target	= 0, | 
 | 				.is_branch	= 0, | 
 | 			}; | 
 |  | 
 | 			rb_link_left_of_node(&hole->node, &next->node); | 
 | 			rb_insert_color(&hole->node, &block_ranges.root); | 
 | 			block_range__debug(); | 
 | 		} | 
 |  | 
 | 		entry = next; | 
 | 	} | 
 |  | 
 | done: | 
 | 	assert(iter.start->start == start && iter.start->is_target); | 
 | 	assert(iter.end->end == end && iter.end->is_branch); | 
 |  | 
 | 	block_ranges.blocks++; | 
 |  | 
 | 	return iter; | 
 | } | 
 |  | 
 |  | 
 | /* | 
 |  * Compute coverage as: | 
 |  * | 
 |  *    br->coverage / br->sym->max_coverage | 
 |  * | 
 |  * This ensures each symbol has a 100% spot, to reflect that each symbol has a | 
 |  * most covered section. | 
 |  * | 
 |  * Returns [0-1] for coverage and -1 if we had no data what so ever or the | 
 |  * symbol does not exist. | 
 |  */ | 
 | double block_range__coverage(struct block_range *br) | 
 | { | 
 | 	struct symbol *sym; | 
 |  | 
 | 	if (!br) { | 
 | 		if (block_ranges.blocks) | 
 | 			return 0; | 
 |  | 
 | 		return -1; | 
 | 	} | 
 |  | 
 | 	sym = br->sym; | 
 | 	if (!sym) | 
 | 		return -1; | 
 |  | 
 | 	return (double)br->coverage / symbol__annotation(sym)->max_coverage; | 
 | } |