1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
270fbe057SPeter Zijlstra #include "block-range.h"
370fbe057SPeter Zijlstra #include "annotate.h"
4e7a795d3SArnaldo Carvalho de Melo #include <assert.h>
5e7a795d3SArnaldo Carvalho de Melo #include <stdlib.h>
670fbe057SPeter Zijlstra
770fbe057SPeter Zijlstra struct {
870fbe057SPeter Zijlstra struct rb_root root;
970fbe057SPeter Zijlstra u64 blocks;
1070fbe057SPeter Zijlstra } block_ranges;
1170fbe057SPeter Zijlstra
block_range__debug(void)1270fbe057SPeter Zijlstra static void block_range__debug(void)
1370fbe057SPeter Zijlstra {
14*984a785fSIan Rogers #ifndef NDEBUG
1570fbe057SPeter Zijlstra struct rb_node *rb;
1670fbe057SPeter Zijlstra u64 old = 0; /* NULL isn't executable */
1770fbe057SPeter Zijlstra
1870fbe057SPeter Zijlstra for (rb = rb_first(&block_ranges.root); rb; rb = rb_next(rb)) {
1970fbe057SPeter Zijlstra struct block_range *entry = rb_entry(rb, struct block_range, node);
2070fbe057SPeter Zijlstra
2170fbe057SPeter Zijlstra assert(old < entry->start);
2270fbe057SPeter Zijlstra assert(entry->start <= entry->end); /* single instruction block; jump to a jump */
2370fbe057SPeter Zijlstra
2470fbe057SPeter Zijlstra old = entry->end;
2570fbe057SPeter Zijlstra }
2670fbe057SPeter Zijlstra #endif
2770fbe057SPeter Zijlstra }
2870fbe057SPeter Zijlstra
block_range__find(u64 addr)2970fbe057SPeter Zijlstra struct block_range *block_range__find(u64 addr)
3070fbe057SPeter Zijlstra {
3170fbe057SPeter Zijlstra struct rb_node **p = &block_ranges.root.rb_node;
3270fbe057SPeter Zijlstra struct rb_node *parent = NULL;
3370fbe057SPeter Zijlstra struct block_range *entry;
3470fbe057SPeter Zijlstra
3570fbe057SPeter Zijlstra while (*p != NULL) {
3670fbe057SPeter Zijlstra parent = *p;
3770fbe057SPeter Zijlstra entry = rb_entry(parent, struct block_range, node);
3870fbe057SPeter Zijlstra
3970fbe057SPeter Zijlstra if (addr < entry->start)
4070fbe057SPeter Zijlstra p = &parent->rb_left;
4170fbe057SPeter Zijlstra else if (addr > entry->end)
4270fbe057SPeter Zijlstra p = &parent->rb_right;
4370fbe057SPeter Zijlstra else
4470fbe057SPeter Zijlstra return entry;
4570fbe057SPeter Zijlstra }
4670fbe057SPeter Zijlstra
4770fbe057SPeter Zijlstra return NULL;
4870fbe057SPeter Zijlstra }
4970fbe057SPeter Zijlstra
rb_link_left_of_node(struct rb_node * left,struct rb_node * node)5070fbe057SPeter Zijlstra static inline void rb_link_left_of_node(struct rb_node *left, struct rb_node *node)
5170fbe057SPeter Zijlstra {
5270fbe057SPeter Zijlstra struct rb_node **p = &node->rb_left;
5370fbe057SPeter Zijlstra while (*p) {
5470fbe057SPeter Zijlstra node = *p;
5570fbe057SPeter Zijlstra p = &node->rb_right;
5670fbe057SPeter Zijlstra }
5770fbe057SPeter Zijlstra rb_link_node(left, node, p);
5870fbe057SPeter Zijlstra }
5970fbe057SPeter Zijlstra
rb_link_right_of_node(struct rb_node * right,struct rb_node * node)6070fbe057SPeter Zijlstra static inline void rb_link_right_of_node(struct rb_node *right, struct rb_node *node)
6170fbe057SPeter Zijlstra {
6270fbe057SPeter Zijlstra struct rb_node **p = &node->rb_right;
6370fbe057SPeter Zijlstra while (*p) {
6470fbe057SPeter Zijlstra node = *p;
6570fbe057SPeter Zijlstra p = &node->rb_left;
6670fbe057SPeter Zijlstra }
6770fbe057SPeter Zijlstra rb_link_node(right, node, p);
6870fbe057SPeter Zijlstra }
6970fbe057SPeter Zijlstra
7070fbe057SPeter Zijlstra /**
7170fbe057SPeter Zijlstra * block_range__create
7270fbe057SPeter Zijlstra * @start: branch target starting this basic block
7370fbe057SPeter Zijlstra * @end: branch ending this basic block
7470fbe057SPeter Zijlstra *
7570fbe057SPeter Zijlstra * Create all the required block ranges to precisely span the given range.
7670fbe057SPeter Zijlstra */
block_range__create(u64 start,u64 end)7770fbe057SPeter Zijlstra struct block_range_iter block_range__create(u64 start, u64 end)
7870fbe057SPeter Zijlstra {
7970fbe057SPeter Zijlstra struct rb_node **p = &block_ranges.root.rb_node;
8070fbe057SPeter Zijlstra struct rb_node *n, *parent = NULL;
8170fbe057SPeter Zijlstra struct block_range *next, *entry = NULL;
8270fbe057SPeter Zijlstra struct block_range_iter iter = { NULL, NULL };
8370fbe057SPeter Zijlstra
8470fbe057SPeter Zijlstra while (*p != NULL) {
8570fbe057SPeter Zijlstra parent = *p;
8670fbe057SPeter Zijlstra entry = rb_entry(parent, struct block_range, node);
8770fbe057SPeter Zijlstra
8870fbe057SPeter Zijlstra if (start < entry->start)
8970fbe057SPeter Zijlstra p = &parent->rb_left;
9070fbe057SPeter Zijlstra else if (start > entry->end)
9170fbe057SPeter Zijlstra p = &parent->rb_right;
9270fbe057SPeter Zijlstra else
9370fbe057SPeter Zijlstra break;
9470fbe057SPeter Zijlstra }
9570fbe057SPeter Zijlstra
9670fbe057SPeter Zijlstra /*
9770fbe057SPeter Zijlstra * Didn't find anything.. there's a hole at @start, however @end might
9870fbe057SPeter Zijlstra * be inside/behind the next range.
9970fbe057SPeter Zijlstra */
10070fbe057SPeter Zijlstra if (!*p) {
10170fbe057SPeter Zijlstra if (!entry) /* tree empty */
10270fbe057SPeter Zijlstra goto do_whole;
10370fbe057SPeter Zijlstra
10470fbe057SPeter Zijlstra /*
10570fbe057SPeter Zijlstra * If the last node is before, advance one to find the next.
10670fbe057SPeter Zijlstra */
10770fbe057SPeter Zijlstra n = parent;
10870fbe057SPeter Zijlstra if (entry->end < start) {
10970fbe057SPeter Zijlstra n = rb_next(n);
11070fbe057SPeter Zijlstra if (!n)
11170fbe057SPeter Zijlstra goto do_whole;
11270fbe057SPeter Zijlstra }
11370fbe057SPeter Zijlstra next = rb_entry(n, struct block_range, node);
11470fbe057SPeter Zijlstra
11570fbe057SPeter Zijlstra if (next->start <= end) { /* add head: [start...][n->start...] */
11670fbe057SPeter Zijlstra struct block_range *head = malloc(sizeof(struct block_range));
11770fbe057SPeter Zijlstra if (!head)
11870fbe057SPeter Zijlstra return iter;
11970fbe057SPeter Zijlstra
12070fbe057SPeter Zijlstra *head = (struct block_range){
12170fbe057SPeter Zijlstra .start = start,
12270fbe057SPeter Zijlstra .end = next->start - 1,
12370fbe057SPeter Zijlstra .is_target = 1,
12470fbe057SPeter Zijlstra .is_branch = 0,
12570fbe057SPeter Zijlstra };
12670fbe057SPeter Zijlstra
12770fbe057SPeter Zijlstra rb_link_left_of_node(&head->node, &next->node);
12870fbe057SPeter Zijlstra rb_insert_color(&head->node, &block_ranges.root);
12970fbe057SPeter Zijlstra block_range__debug();
13070fbe057SPeter Zijlstra
13170fbe057SPeter Zijlstra iter.start = head;
13270fbe057SPeter Zijlstra goto do_tail;
13370fbe057SPeter Zijlstra }
13470fbe057SPeter Zijlstra
13570fbe057SPeter Zijlstra do_whole:
13670fbe057SPeter Zijlstra /*
13770fbe057SPeter Zijlstra * The whole [start..end] range is non-overlapping.
13870fbe057SPeter Zijlstra */
13970fbe057SPeter Zijlstra entry = malloc(sizeof(struct block_range));
14070fbe057SPeter Zijlstra if (!entry)
14170fbe057SPeter Zijlstra return iter;
14270fbe057SPeter Zijlstra
14370fbe057SPeter Zijlstra *entry = (struct block_range){
14470fbe057SPeter Zijlstra .start = start,
14570fbe057SPeter Zijlstra .end = end,
14670fbe057SPeter Zijlstra .is_target = 1,
14770fbe057SPeter Zijlstra .is_branch = 1,
14870fbe057SPeter Zijlstra };
14970fbe057SPeter Zijlstra
15070fbe057SPeter Zijlstra rb_link_node(&entry->node, parent, p);
15170fbe057SPeter Zijlstra rb_insert_color(&entry->node, &block_ranges.root);
15270fbe057SPeter Zijlstra block_range__debug();
15370fbe057SPeter Zijlstra
15470fbe057SPeter Zijlstra iter.start = entry;
15570fbe057SPeter Zijlstra iter.end = entry;
15670fbe057SPeter Zijlstra goto done;
15770fbe057SPeter Zijlstra }
15870fbe057SPeter Zijlstra
15970fbe057SPeter Zijlstra /*
16070fbe057SPeter Zijlstra * We found a range that overlapped with ours, split if needed.
16170fbe057SPeter Zijlstra */
16270fbe057SPeter Zijlstra if (entry->start < start) { /* split: [e->start...][start...] */
16370fbe057SPeter Zijlstra struct block_range *head = malloc(sizeof(struct block_range));
16470fbe057SPeter Zijlstra if (!head)
16570fbe057SPeter Zijlstra return iter;
16670fbe057SPeter Zijlstra
16770fbe057SPeter Zijlstra *head = (struct block_range){
16870fbe057SPeter Zijlstra .start = entry->start,
16970fbe057SPeter Zijlstra .end = start - 1,
17070fbe057SPeter Zijlstra .is_target = entry->is_target,
17170fbe057SPeter Zijlstra .is_branch = 0,
17270fbe057SPeter Zijlstra
17370fbe057SPeter Zijlstra .coverage = entry->coverage,
17470fbe057SPeter Zijlstra .entry = entry->entry,
17570fbe057SPeter Zijlstra };
17670fbe057SPeter Zijlstra
17770fbe057SPeter Zijlstra entry->start = start;
17870fbe057SPeter Zijlstra entry->is_target = 1;
17970fbe057SPeter Zijlstra entry->entry = 0;
18070fbe057SPeter Zijlstra
18170fbe057SPeter Zijlstra rb_link_left_of_node(&head->node, &entry->node);
18270fbe057SPeter Zijlstra rb_insert_color(&head->node, &block_ranges.root);
18370fbe057SPeter Zijlstra block_range__debug();
18470fbe057SPeter Zijlstra
18570fbe057SPeter Zijlstra } else if (entry->start == start)
18670fbe057SPeter Zijlstra entry->is_target = 1;
18770fbe057SPeter Zijlstra
18870fbe057SPeter Zijlstra iter.start = entry;
18970fbe057SPeter Zijlstra
19070fbe057SPeter Zijlstra do_tail:
19170fbe057SPeter Zijlstra /*
19270fbe057SPeter Zijlstra * At this point we've got: @iter.start = [@start...] but @end can still be
19370fbe057SPeter Zijlstra * inside or beyond it.
19470fbe057SPeter Zijlstra */
19570fbe057SPeter Zijlstra entry = iter.start;
19670fbe057SPeter Zijlstra for (;;) {
19770fbe057SPeter Zijlstra /*
19870fbe057SPeter Zijlstra * If @end is inside @entry, split.
19970fbe057SPeter Zijlstra */
20070fbe057SPeter Zijlstra if (end < entry->end) { /* split: [...end][...e->end] */
20170fbe057SPeter Zijlstra struct block_range *tail = malloc(sizeof(struct block_range));
20270fbe057SPeter Zijlstra if (!tail)
20370fbe057SPeter Zijlstra return iter;
20470fbe057SPeter Zijlstra
20570fbe057SPeter Zijlstra *tail = (struct block_range){
20670fbe057SPeter Zijlstra .start = end + 1,
20770fbe057SPeter Zijlstra .end = entry->end,
20870fbe057SPeter Zijlstra .is_target = 0,
20970fbe057SPeter Zijlstra .is_branch = entry->is_branch,
21070fbe057SPeter Zijlstra
21170fbe057SPeter Zijlstra .coverage = entry->coverage,
21270fbe057SPeter Zijlstra .taken = entry->taken,
21370fbe057SPeter Zijlstra .pred = entry->pred,
21470fbe057SPeter Zijlstra };
21570fbe057SPeter Zijlstra
21670fbe057SPeter Zijlstra entry->end = end;
21770fbe057SPeter Zijlstra entry->is_branch = 1;
21870fbe057SPeter Zijlstra entry->taken = 0;
21970fbe057SPeter Zijlstra entry->pred = 0;
22070fbe057SPeter Zijlstra
22170fbe057SPeter Zijlstra rb_link_right_of_node(&tail->node, &entry->node);
22270fbe057SPeter Zijlstra rb_insert_color(&tail->node, &block_ranges.root);
22370fbe057SPeter Zijlstra block_range__debug();
22470fbe057SPeter Zijlstra
22570fbe057SPeter Zijlstra iter.end = entry;
22670fbe057SPeter Zijlstra goto done;
22770fbe057SPeter Zijlstra }
22870fbe057SPeter Zijlstra
22970fbe057SPeter Zijlstra /*
23070fbe057SPeter Zijlstra * If @end matches @entry, done
23170fbe057SPeter Zijlstra */
23270fbe057SPeter Zijlstra if (end == entry->end) {
23370fbe057SPeter Zijlstra entry->is_branch = 1;
23470fbe057SPeter Zijlstra iter.end = entry;
23570fbe057SPeter Zijlstra goto done;
23670fbe057SPeter Zijlstra }
23770fbe057SPeter Zijlstra
23870fbe057SPeter Zijlstra next = block_range__next(entry);
23970fbe057SPeter Zijlstra if (!next)
24070fbe057SPeter Zijlstra goto add_tail;
24170fbe057SPeter Zijlstra
24270fbe057SPeter Zijlstra /*
24370fbe057SPeter Zijlstra * If @end is in beyond @entry but not inside @next, add tail.
24470fbe057SPeter Zijlstra */
24570fbe057SPeter Zijlstra if (end < next->start) { /* add tail: [...e->end][...end] */
24670fbe057SPeter Zijlstra struct block_range *tail;
24770fbe057SPeter Zijlstra add_tail:
24870fbe057SPeter Zijlstra tail = malloc(sizeof(struct block_range));
24970fbe057SPeter Zijlstra if (!tail)
25070fbe057SPeter Zijlstra return iter;
25170fbe057SPeter Zijlstra
25270fbe057SPeter Zijlstra *tail = (struct block_range){
25370fbe057SPeter Zijlstra .start = entry->end + 1,
25470fbe057SPeter Zijlstra .end = end,
25570fbe057SPeter Zijlstra .is_target = 0,
25670fbe057SPeter Zijlstra .is_branch = 1,
25770fbe057SPeter Zijlstra };
25870fbe057SPeter Zijlstra
25970fbe057SPeter Zijlstra rb_link_right_of_node(&tail->node, &entry->node);
26070fbe057SPeter Zijlstra rb_insert_color(&tail->node, &block_ranges.root);
26170fbe057SPeter Zijlstra block_range__debug();
26270fbe057SPeter Zijlstra
26370fbe057SPeter Zijlstra iter.end = tail;
26470fbe057SPeter Zijlstra goto done;
26570fbe057SPeter Zijlstra }
26670fbe057SPeter Zijlstra
26770fbe057SPeter Zijlstra /*
26870fbe057SPeter Zijlstra * If there is a hole between @entry and @next, fill it.
26970fbe057SPeter Zijlstra */
27070fbe057SPeter Zijlstra if (entry->end + 1 != next->start) {
27170fbe057SPeter Zijlstra struct block_range *hole = malloc(sizeof(struct block_range));
27270fbe057SPeter Zijlstra if (!hole)
27370fbe057SPeter Zijlstra return iter;
27470fbe057SPeter Zijlstra
27570fbe057SPeter Zijlstra *hole = (struct block_range){
27670fbe057SPeter Zijlstra .start = entry->end + 1,
27770fbe057SPeter Zijlstra .end = next->start - 1,
27870fbe057SPeter Zijlstra .is_target = 0,
27970fbe057SPeter Zijlstra .is_branch = 0,
28070fbe057SPeter Zijlstra };
28170fbe057SPeter Zijlstra
28270fbe057SPeter Zijlstra rb_link_left_of_node(&hole->node, &next->node);
28370fbe057SPeter Zijlstra rb_insert_color(&hole->node, &block_ranges.root);
28470fbe057SPeter Zijlstra block_range__debug();
28570fbe057SPeter Zijlstra }
28670fbe057SPeter Zijlstra
28770fbe057SPeter Zijlstra entry = next;
28870fbe057SPeter Zijlstra }
28970fbe057SPeter Zijlstra
29070fbe057SPeter Zijlstra done:
29170fbe057SPeter Zijlstra assert(iter.start->start == start && iter.start->is_target);
29270fbe057SPeter Zijlstra assert(iter.end->end == end && iter.end->is_branch);
29370fbe057SPeter Zijlstra
29470fbe057SPeter Zijlstra block_ranges.blocks++;
29570fbe057SPeter Zijlstra
29670fbe057SPeter Zijlstra return iter;
29770fbe057SPeter Zijlstra }
29870fbe057SPeter Zijlstra
29970fbe057SPeter Zijlstra
30070fbe057SPeter Zijlstra /*
30170fbe057SPeter Zijlstra * Compute coverage as:
30270fbe057SPeter Zijlstra *
30370fbe057SPeter Zijlstra * br->coverage / br->sym->max_coverage
30470fbe057SPeter Zijlstra *
30570fbe057SPeter Zijlstra * This ensures each symbol has a 100% spot, to reflect that each symbol has a
30670fbe057SPeter Zijlstra * most covered section.
30770fbe057SPeter Zijlstra *
30870fbe057SPeter Zijlstra * Returns [0-1] for coverage and -1 if we had no data what so ever or the
30970fbe057SPeter Zijlstra * symbol does not exist.
31070fbe057SPeter Zijlstra */
block_range__coverage(struct block_range * br)31170fbe057SPeter Zijlstra double block_range__coverage(struct block_range *br)
31270fbe057SPeter Zijlstra {
31370fbe057SPeter Zijlstra struct symbol *sym;
31470fbe057SPeter Zijlstra
31570fbe057SPeter Zijlstra if (!br) {
31670fbe057SPeter Zijlstra if (block_ranges.blocks)
31770fbe057SPeter Zijlstra return 0;
31870fbe057SPeter Zijlstra
31970fbe057SPeter Zijlstra return -1;
32070fbe057SPeter Zijlstra }
32170fbe057SPeter Zijlstra
32270fbe057SPeter Zijlstra sym = br->sym;
32370fbe057SPeter Zijlstra if (!sym)
32470fbe057SPeter Zijlstra return -1;
32570fbe057SPeter Zijlstra
32670fbe057SPeter Zijlstra return (double)br->coverage / symbol__annotation(sym)->max_coverage;
32770fbe057SPeter Zijlstra }
328