1 // SPDX-License-Identifier: GPL-2.0
2 #include "block-range.h"
12 static void block_range__debug(void)
16 u64 old
= 0; /* NULL isn't executable */
18 for (rb
= rb_first(&block_ranges
.root
); rb
; rb
= rb_next(rb
)) {
19 struct block_range
*entry
= rb_entry(rb
, struct block_range
, node
);
21 assert(old
< entry
->start
);
22 assert(entry
->start
<= entry
->end
); /* single instruction block; jump to a jump */
29 struct block_range
*block_range__find(u64 addr
)
31 struct rb_node
**p
= &block_ranges
.root
.rb_node
;
32 struct rb_node
*parent
= NULL
;
33 struct block_range
*entry
;
37 entry
= rb_entry(parent
, struct block_range
, node
);
39 if (addr
< entry
->start
)
41 else if (addr
> entry
->end
)
42 p
= &parent
->rb_right
;
50 static inline void rb_link_left_of_node(struct rb_node
*left
, struct rb_node
*node
)
52 struct rb_node
**p
= &node
->rb_left
;
57 rb_link_node(left
, node
, p
);
60 static inline void rb_link_right_of_node(struct rb_node
*right
, struct rb_node
*node
)
62 struct rb_node
**p
= &node
->rb_right
;
67 rb_link_node(right
, node
, p
);
72 * @start: branch target starting this basic block
73 * @end: branch ending this basic block
75 * Create all the required block ranges to precisely span the given range.
77 struct block_range_iter
block_range__create(u64 start
, u64 end
)
79 struct rb_node
**p
= &block_ranges
.root
.rb_node
;
80 struct rb_node
*n
, *parent
= NULL
;
81 struct block_range
*next
, *entry
= NULL
;
82 struct block_range_iter iter
= { NULL
, NULL
};
86 entry
= rb_entry(parent
, struct block_range
, node
);
88 if (start
< entry
->start
)
90 else if (start
> entry
->end
)
91 p
= &parent
->rb_right
;
97 * Didn't find anything.. there's a hole at @start, however @end might
98 * be inside/behind the next range.
101 if (!entry
) /* tree empty */
105 * If the last node is before, advance one to find the next.
108 if (entry
->end
< start
) {
113 next
= rb_entry(n
, struct block_range
, node
);
115 if (next
->start
<= end
) { /* add head: [start...][n->start...] */
116 struct block_range
*head
= malloc(sizeof(struct block_range
));
120 *head
= (struct block_range
){
122 .end
= next
->start
- 1,
127 rb_link_left_of_node(&head
->node
, &next
->node
);
128 rb_insert_color(&head
->node
, &block_ranges
.root
);
129 block_range__debug();
137 * The whole [start..end] range is non-overlapping.
139 entry
= malloc(sizeof(struct block_range
));
143 *entry
= (struct block_range
){
150 rb_link_node(&entry
->node
, parent
, p
);
151 rb_insert_color(&entry
->node
, &block_ranges
.root
);
152 block_range__debug();
160 * We found a range that overlapped with ours, split if needed.
162 if (entry
->start
< start
) { /* split: [e->start...][start...] */
163 struct block_range
*head
= malloc(sizeof(struct block_range
));
167 *head
= (struct block_range
){
168 .start
= entry
->start
,
170 .is_target
= entry
->is_target
,
173 .coverage
= entry
->coverage
,
174 .entry
= entry
->entry
,
177 entry
->start
= start
;
178 entry
->is_target
= 1;
181 rb_link_left_of_node(&head
->node
, &entry
->node
);
182 rb_insert_color(&head
->node
, &block_ranges
.root
);
183 block_range__debug();
185 } else if (entry
->start
== start
)
186 entry
->is_target
= 1;
192 * At this point we've got: @iter.start = [@start...] but @end can still be
193 * inside or beyond it.
198 * If @end is inside @entry, split.
200 if (end
< entry
->end
) { /* split: [...end][...e->end] */
201 struct block_range
*tail
= malloc(sizeof(struct block_range
));
205 *tail
= (struct block_range
){
209 .is_branch
= entry
->is_branch
,
211 .coverage
= entry
->coverage
,
212 .taken
= entry
->taken
,
217 entry
->is_branch
= 1;
221 rb_link_right_of_node(&tail
->node
, &entry
->node
);
222 rb_insert_color(&tail
->node
, &block_ranges
.root
);
223 block_range__debug();
230 * If @end matches @entry, done
232 if (end
== entry
->end
) {
233 entry
->is_branch
= 1;
238 next
= block_range__next(entry
);
243 * If @end is in beyond @entry but not inside @next, add tail.
245 if (end
< next
->start
) { /* add tail: [...e->end][...end] */
246 struct block_range
*tail
;
248 tail
= malloc(sizeof(struct block_range
));
252 *tail
= (struct block_range
){
253 .start
= entry
->end
+ 1,
259 rb_link_right_of_node(&tail
->node
, &entry
->node
);
260 rb_insert_color(&tail
->node
, &block_ranges
.root
);
261 block_range__debug();
268 * If there is a hole between @entry and @next, fill it.
270 if (entry
->end
+ 1 != next
->start
) {
271 struct block_range
*hole
= malloc(sizeof(struct block_range
));
275 *hole
= (struct block_range
){
276 .start
= entry
->end
+ 1,
277 .end
= next
->start
- 1,
282 rb_link_left_of_node(&hole
->node
, &next
->node
);
283 rb_insert_color(&hole
->node
, &block_ranges
.root
);
284 block_range__debug();
291 assert(iter
.start
->start
== start
&& iter
.start
->is_target
);
292 assert(iter
.end
->end
== end
&& iter
.end
->is_branch
);
294 block_ranges
.blocks
++;
301 * Compute coverage as:
303 * br->coverage / br->sym->max_coverage
305 * This ensures each symbol has a 100% spot, to reflect that each symbol has a
306 * most covered section.
308 * Returns [0-1] for coverage and -1 if we had no data what so ever or the
309 * symbol does not exist.
311 double block_range__coverage(struct block_range
*br
)
314 struct annotated_branch
*branch
;
317 if (block_ranges
.blocks
)
327 branch
= symbol__annotation(sym
)->branch
;
331 return (double)br
->coverage
/ branch
->max_coverage
;