1 // SPDX-License-Identifier: GPL-2.0
2 #include "block-range.h"
10 static void block_range__debug(void)
13 * XXX still paranoid for now; see if we can make this depend on
18 u64 old
= 0; /* NULL isn't executable */
20 for (rb
= rb_first(&block_ranges
.root
); rb
; rb
= rb_next(rb
)) {
21 struct block_range
*entry
= rb_entry(rb
, struct block_range
, node
);
23 assert(old
< entry
->start
);
24 assert(entry
->start
<= entry
->end
); /* single instruction block; jump to a jump */
31 struct block_range
*block_range__find(u64 addr
)
33 struct rb_node
**p
= &block_ranges
.root
.rb_node
;
34 struct rb_node
*parent
= NULL
;
35 struct block_range
*entry
;
39 entry
= rb_entry(parent
, struct block_range
, node
);
41 if (addr
< entry
->start
)
43 else if (addr
> entry
->end
)
44 p
= &parent
->rb_right
;
52 static inline void rb_link_left_of_node(struct rb_node
*left
, struct rb_node
*node
)
54 struct rb_node
**p
= &node
->rb_left
;
59 rb_link_node(left
, node
, p
);
62 static inline void rb_link_right_of_node(struct rb_node
*right
, struct rb_node
*node
)
64 struct rb_node
**p
= &node
->rb_right
;
69 rb_link_node(right
, node
, p
);
74 * @start: branch target starting this basic block
75 * @end: branch ending this basic block
77 * Create all the required block ranges to precisely span the given range.
79 struct block_range_iter
block_range__create(u64 start
, u64 end
)
81 struct rb_node
**p
= &block_ranges
.root
.rb_node
;
82 struct rb_node
*n
, *parent
= NULL
;
83 struct block_range
*next
, *entry
= NULL
;
84 struct block_range_iter iter
= { NULL
, NULL
};
88 entry
= rb_entry(parent
, struct block_range
, node
);
90 if (start
< entry
->start
)
92 else if (start
> entry
->end
)
93 p
= &parent
->rb_right
;
99 * Didn't find anything.. there's a hole at @start, however @end might
100 * be inside/behind the next range.
103 if (!entry
) /* tree empty */
107 * If the last node is before, advance one to find the next.
110 if (entry
->end
< start
) {
115 next
= rb_entry(n
, struct block_range
, node
);
117 if (next
->start
<= end
) { /* add head: [start...][n->start...] */
118 struct block_range
*head
= malloc(sizeof(struct block_range
));
122 *head
= (struct block_range
){
124 .end
= next
->start
- 1,
129 rb_link_left_of_node(&head
->node
, &next
->node
);
130 rb_insert_color(&head
->node
, &block_ranges
.root
);
131 block_range__debug();
139 * The whole [start..end] range is non-overlapping.
141 entry
= malloc(sizeof(struct block_range
));
145 *entry
= (struct block_range
){
152 rb_link_node(&entry
->node
, parent
, p
);
153 rb_insert_color(&entry
->node
, &block_ranges
.root
);
154 block_range__debug();
162 * We found a range that overlapped with ours, split if needed.
164 if (entry
->start
< start
) { /* split: [e->start...][start...] */
165 struct block_range
*head
= malloc(sizeof(struct block_range
));
169 *head
= (struct block_range
){
170 .start
= entry
->start
,
172 .is_target
= entry
->is_target
,
175 .coverage
= entry
->coverage
,
176 .entry
= entry
->entry
,
179 entry
->start
= start
;
180 entry
->is_target
= 1;
183 rb_link_left_of_node(&head
->node
, &entry
->node
);
184 rb_insert_color(&head
->node
, &block_ranges
.root
);
185 block_range__debug();
187 } else if (entry
->start
== start
)
188 entry
->is_target
= 1;
194 * At this point we've got: @iter.start = [@start...] but @end can still be
195 * inside or beyond it.
200 * If @end is inside @entry, split.
202 if (end
< entry
->end
) { /* split: [...end][...e->end] */
203 struct block_range
*tail
= malloc(sizeof(struct block_range
));
207 *tail
= (struct block_range
){
211 .is_branch
= entry
->is_branch
,
213 .coverage
= entry
->coverage
,
214 .taken
= entry
->taken
,
219 entry
->is_branch
= 1;
223 rb_link_right_of_node(&tail
->node
, &entry
->node
);
224 rb_insert_color(&tail
->node
, &block_ranges
.root
);
225 block_range__debug();
232 * If @end matches @entry, done
234 if (end
== entry
->end
) {
235 entry
->is_branch
= 1;
240 next
= block_range__next(entry
);
245 * If @end is in beyond @entry but not inside @next, add tail.
247 if (end
< next
->start
) { /* add tail: [...e->end][...end] */
248 struct block_range
*tail
;
250 tail
= malloc(sizeof(struct block_range
));
254 *tail
= (struct block_range
){
255 .start
= entry
->end
+ 1,
261 rb_link_right_of_node(&tail
->node
, &entry
->node
);
262 rb_insert_color(&tail
->node
, &block_ranges
.root
);
263 block_range__debug();
270 * If there is a hole between @entry and @next, fill it.
272 if (entry
->end
+ 1 != next
->start
) {
273 struct block_range
*hole
= malloc(sizeof(struct block_range
));
277 *hole
= (struct block_range
){
278 .start
= entry
->end
+ 1,
279 .end
= next
->start
- 1,
284 rb_link_left_of_node(&hole
->node
, &next
->node
);
285 rb_insert_color(&hole
->node
, &block_ranges
.root
);
286 block_range__debug();
293 assert(iter
.start
->start
== start
&& iter
.start
->is_target
);
294 assert(iter
.end
->end
== end
&& iter
.end
->is_branch
);
296 block_ranges
.blocks
++;
303 * Compute coverage as:
305 * br->coverage / br->sym->max_coverage
307 * This ensures each symbol has a 100% spot, to reflect that each symbol has a
308 * most covered section.
310 * Returns [0-1] for coverage and -1 if we had no data what so ever or the
311 * symbol does not exist.
313 double block_range__coverage(struct block_range
*br
)
318 if (block_ranges
.blocks
)
328 return (double)br
->coverage
/ symbol__annotation(sym
)->max_coverage
;