-
Notifications
You must be signed in to change notification settings - Fork 10
/
editor.go
80 lines (70 loc) · 1.91 KB
/
editor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package manager
import (
"errors"
"fmt"
"github.com/cilium/ebpf/asm"
)
// editor modifies eBPF instructions.
type editor struct {
instructions *asm.Instructions
ReferenceOffsets map[string][]int
}
// newEditor creates a new editor.
//
// The editor retains a reference to insns and modifies its
// contents.
func newEditor(insns *asm.Instructions) *editor {
refs := insns.ReferenceOffsets()
return &editor{insns, refs}
}
// RewriteConstant rewrites all loads of a symbol to a constant value.
//
// This is a way to parameterize clang-compiled eBPF byte code at load
// time.
//
// The following macro should be used to access the constant:
//
// #define LOAD_CONSTANT(param, var) asm("%0 = " param " ll" : "=r"(var))
//
// int xdp() {
// bool my_constant;
// LOAD_CONSTANT("SYMBOL_NAME", my_constant);
//
// if (my_constant) ...
//
// Caveats:
//
// - The symbol name you pick must be unique
//
// - Failing to rewrite a symbol will not result in an error,
// 0 will be loaded instead (subject to change)
//
// Use isUnreferencedSymbol if you want to rewrite potentially
// unused symbols.
func (ed *editor) RewriteConstant(symbol string, value uint64) error {
indices := ed.ReferenceOffsets[symbol]
if len(indices) == 0 {
return &unreferencedSymbolError{symbol}
}
ldDWImm := asm.LoadImmOp(asm.DWord)
for _, index := range indices {
load := &(*ed.instructions)[index]
if load.OpCode != ldDWImm {
return fmt.Errorf("symbol %v: load: found %v instead of %v", symbol, load.OpCode, ldDWImm)
}
load.Constant = int64(value)
}
return nil
}
type unreferencedSymbolError struct {
symbol string
}
func (use *unreferencedSymbolError) Error() string {
return fmt.Sprintf("unreferenced symbol %s", use.symbol)
}
// isUnreferencedSymbol returns true if err was caused by
// an unreferenced symbol.
func isUnreferencedSymbol(err error) bool {
var ue *unreferencedSymbolError
return errors.As(err, &ue)
}