-
Notifications
You must be signed in to change notification settings - Fork 10
/
metadata.go
66 lines (60 loc) · 1.48 KB
/
metadata.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
package cmd
import (
"debug/elf"
"fmt"
"sort"
)
type Symbol struct {
Name string `json:"name"`
Start uint64 `json:"start"`
Size uint64 `json:"size"`
}
type Metadata struct {
Symbols []Symbol `json:"symbols"`
}
func MakeMetadata(elfProgram *elf.File) (*Metadata, error) {
syms, err := elfProgram.Symbols()
if err != nil {
return nil, fmt.Errorf("failed to load symbols table: %w", err)
}
// Make sure the table is sorted, Go outputs mostly sorted data, except some internal functions
sort.Slice(syms, func(i, j int) bool {
return syms[i].Value < syms[j].Value
})
out := &Metadata{Symbols: make([]Symbol, len(syms))}
for i, s := range syms {
out.Symbols[i] = Symbol{Name: s.Name, Start: s.Value, Size: s.Size}
}
return out, nil
}
func (m *Metadata) LookupSymbol(addr uint64) string {
if len(m.Symbols) == 0 {
return "!unknown"
}
// find first symbol with higher start. Or n if no such symbol exists
i := sort.Search(len(m.Symbols), func(i int) bool {
return m.Symbols[i].Start > addr
})
if i == 0 {
return "!start"
}
out := &m.Symbols[i-1]
if out.Start+out.Size < addr { // addr may be pointing to a gap between symbols
return "!gap"
}
return out.Name
}
func (m *Metadata) SymbolMatcher(name string) func(addr uint64) bool {
for _, s := range m.Symbols {
if s.Name == name {
start := s.Start
end := s.Start + s.Size
return func(addr uint64) bool {
return addr >= start && addr < end
}
}
}
return func(addr uint64) bool {
return false
}
}