58 lines
1.7 KiB
Go
58 lines
1.7 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|||
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
||
|
|
|
||
|
|
package verify
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"sort"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Block describes one basic block within a function: a maximal sequence of
|
||
|
|
// instructions with a single entry point (a label or the function start) and
|
||
|
|
// a single exit (a jump, conditional jump or RET).
|
||
|
|
type Block struct {
|
||
|
|
Offset int // byte offset within the function
|
||
|
|
Label string // label name ("" for the entry block)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Blocks identifies the basic blocks of a function from its local labels.
|
||
|
|
// Each label is a potential jump target and therefore a block boundary; the
|
||
|
|
// function entry (offset 0) is always a block. The blocks are returned in
|
||
|
|
// ascending offset order.
|
||
|
|
func (k *Kernel) Blocks(name string) ([]Block, error) {
|
||
|
|
idx, ok := k.funcs[name]
|
||
|
|
if !ok {
|
||
|
|
return nil, fmt.Errorf("verify: function %q not found", name)
|
||
|
|
}
|
||
|
|
fl := k.img.Funcs[idx]
|
||
|
|
|
||
|
|
blocks := []Block{{Offset: 0, Label: "(entry)"}}
|
||
|
|
// Build a reverse map: offset → label name.
|
||
|
|
offToLabel := make(map[int]string, len(fl.Labels))
|
||
|
|
for label, off := range fl.Labels {
|
||
|
|
if off > 0 && off < fl.Size {
|
||
|
|
offToLabel[off] = label
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Collect and sort offsets.
|
||
|
|
offsets := make([]int, 0, len(offToLabel))
|
||
|
|
for off := range offToLabel {
|
||
|
|
offsets = append(offsets, off)
|
||
|
|
}
|
||
|
|
sort.Ints(offsets)
|
||
|
|
for _, off := range offsets {
|
||
|
|
blocks = append(blocks, Block{Offset: off, Label: offToLabel[off]})
|
||
|
|
}
|
||
|
|
return blocks, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// BlockCount returns the number of identified basic blocks for the function.
|
||
|
|
func (k *Kernel) BlockCount(name string) (int, error) {
|
||
|
|
blocks, err := k.Blocks(name)
|
||
|
|
if err != nil {
|
||
|
|
return 0, err
|
||
|
|
}
|
||
|
|
return len(blocks), nil
|
||
|
|
}
|