-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathksym.go
138 lines (125 loc) · 2.99 KB
/
ksym.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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package main
import (
"bufio"
"errors"
"log"
"os"
"slices"
"sort"
"strconv"
"strings"
)
type Symbol struct {
Type string
Name string
Addr uint64
AvailableFilter bool
}
const (
kallsymsPath = "/proc/kallsyms"
availableFilterFunctionsPath = "/sys/kernel/debug/tracing/available_filter_functions"
)
var (
kallsyms []*Symbol
kallsymsByName map[string]*Symbol = make(map[string]*Symbol)
kallsymsByAddr map[uint64]*Symbol = make(map[uint64]*Symbol)
availableFilterFuncs map[string]struct{} = make(map[string]struct{})
)
func init() {
readKallsyms()
readAvailableFilterFunctions()
for _, sym := range kallsyms {
if _, ok := availableFilterFuncs[sym.Name]; ok {
sym.AvailableFilter = true
}
}
}
func readKallsyms() {
data, err := os.ReadFile(kallsymsPath)
if err != nil {
log.Fatal(err)
}
for _, line := range strings.Split(string(data), "\n") {
parts := strings.Fields(line)
if len(parts) < 3 {
continue
}
addr, err := strconv.ParseUint(parts[0], 16, 64)
if err != nil {
continue
}
typ, name := parts[1], parts[2]
symbol := &Symbol{typ, name, addr, false}
kallsyms = append(kallsyms, symbol)
kallsymsByName[name] = symbol
kallsymsByAddr[addr] = symbol
}
sort.Slice(kallsyms, func(i, j int) bool {
return kallsyms[i].Addr < kallsyms[j].Addr
})
}
func readAvailableFilterFunctions() {
f, err := os.Open(availableFilterFunctionsPath)
if err != nil {
log.Fatalf("Failed to open available_filter_functions: %s\n", err)
}
defer f.Close()
scanner := bufio.NewScanner(f)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
availableFilterFuncs[scanner.Text()] = struct{}{}
}
if err := scanner.Err(); err != nil {
log.Fatalf("Failed to read available_filter_functions: %s\n", err)
}
}
func NearestKsym(addr uint64) (this, next *Symbol) {
idx, _ := slices.BinarySearchFunc(kallsyms, addr, func(x *Symbol, addr uint64) int { return int(x.Addr - addr) })
if idx == len(kallsyms) {
return kallsyms[idx-1], nil
}
if kallsyms[idx].Addr == addr {
return kallsyms[idx], kallsyms[idx+1]
}
if idx == 0 {
return kallsyms[0], kallsyms[1]
}
return kallsyms[idx-1], kallsyms[idx]
}
func KsymByAddr(addr uint64) (sym *Symbol, err error) {
sym, ok := kallsymsByAddr[addr]
if !ok {
return nil, errors.New("symbol not found")
}
return sym, nil
}
func KsymByName(name string) (sym *Symbol, err error) {
name, err = normalizeKname(name)
if err != nil {
return
}
return kallsymsByName[name], nil
}
func normalizeKname(name string) (string, error) {
possibleSuffixes := []string{
"",
".cold",
".constprop.0",
".constprop.0.cold",
".constprop.0.isra.0",
".constprop.0.isra.0.cold",
".isra.0",
".isra.0.cold",
".part.0",
".part.0.cold",
".part.0.constprop.0",
".part.0.isra.0",
".part.0.isra.0.cold",
}
for _, suffix := range possibleSuffixes {
if _, ok := kallsymsByName[name+suffix]; ok {
return name + suffix, nil
}
}
return "", errors.New("symbol not found")
}