Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags   |
// SPDX-License-Identifier: GPL-2.0
#include "block-range.h"
#include "annotate.h"
#include <assert.h>
#include <stdlib.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;
}