Skip to content

Commit 7152631

Browse files
authored
Merge pull request #26 from parca-dev/parse-modules
proc: Fix parsing Kernel Module lines where refcount is "-"
2 parents 1aae367 + 3a0fd6c commit 7152631

File tree

8 files changed

+151
-33
lines changed

8 files changed

+151
-33
lines changed

interpreter/loaderinfo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func (i *LoaderInfo) GetSymbolAsRanges(symbol libpf.SymbolName) ([]util.Range, e
5555
start := uint64(sym.Address)
5656
return []util.Range{{
5757
Start: start,
58-
End: start + uint64(sym.Size)},
58+
End: start + sym.Size},
5959
}, nil
6060
}
6161

interpreter/luajit/offsets.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,10 +323,10 @@ func (o *offsetData) findTraceInfoFromLuaOpen() (*libpf.Symbol, error) {
323323
slices.Sort(funcAddrs)
324324

325325
// Its a tiny function, give it reasonable default.
326-
traceInfoSize := 100
326+
traceInfoSize := uint64(100)
327327
for i, addr := range funcAddrs {
328328
if addr == traceInfoAddr && i != len(funcAddrs)-1 {
329-
traceInfoSize = int(funcAddrs[i+1] - funcAddrs[i])
329+
traceInfoSize = funcAddrs[i+1] - funcAddrs[i]
330330
break
331331
}
332332
}

libpf/pfelf/file.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ func (f *File) readAndMatchSymbol(n uint32, name libpf.SymbolName) (libpf.Symbol
786786
return libpf.Symbol{
787787
Name: name,
788788
Address: libpf.SymbolValue(sym.Value),
789-
Size: int(sym.Size),
789+
Size: sym.Size,
790790
}, true
791791
}
792792

@@ -946,7 +946,7 @@ func (f *File) loadSymbolTable(name string) (*libpf.SymbolMap, error) {
946946
symMap.Add(libpf.Symbol{
947947
Name: libpf.SymbolName(name),
948948
Address: libpf.SymbolValue(sym.Value),
949-
Size: int(sym.Size),
949+
Size: sym.Size,
950950
})
951951
}
952952
symMap.Finalize()

libpf/pfelf/pfelf.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ func symbolMapFromELFSymbols(syms []elf.Symbol) *libpf.SymbolMap {
256256
symmap.Add(libpf.Symbol{
257257
Name: libpf.SymbolName(sym.Name),
258258
Address: libpf.SymbolValue(sym.Value),
259-
Size: int(sym.Size),
259+
Size: sym.Size,
260260
})
261261
}
262262
symmap.Finalize()

libpf/symbol.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ type SymbolFinder interface {
3232
type Symbol struct {
3333
Name SymbolName
3434
Address SymbolValue
35-
Size int
35+
Size uint64
3636
}
3737

3838
var _ SymbolFinder = &SymbolMap{}

proc/proc.go

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -106,51 +106,104 @@ func GetKernelModules(modulesPath string,
106106
symmap.Add(libpf.Symbol{
107107
Name: "vmlinux",
108108
Address: stext.Address,
109-
Size: int(etext.Address - stext.Address),
109+
Size: uint64(etext.Address - stext.Address),
110110
})
111111

112-
atLeastOneValidAddress := false
113-
count := 0
112+
modules, err := parseKernelModules(bufio.NewScanner(file))
113+
if err != nil {
114+
return nil, fmt.Errorf("failed to parse kernel modules: %v", err)
115+
}
114116

115-
var scanner = bufio.NewScanner(file)
116-
for scanner.Scan() {
117-
var size, address uint64
118-
var refcount int64
119-
var name, dependencies, state string
117+
for _, kmod := range modules {
118+
symmap.Add(libpf.Symbol{
119+
Name: libpf.SymbolName(kmod.name),
120+
Address: libpf.SymbolValue(kmod.address),
121+
Size: kmod.size,
122+
})
123+
}
124+
125+
symmap.Finalize()
126+
127+
return &symmap, nil
128+
}
129+
130+
func parseKernelModules(scanner *bufio.Scanner) ([]kernelModule, error) {
131+
var (
132+
modules []kernelModule
133+
atLeastOneValidAddress = false
134+
count = 0
135+
)
120136

137+
for scanner.Scan() {
121138
line := scanner.Text()
122139

123140
count++
124141

125-
nFields, err := fmt.Sscanf(line, "%s %d %d %s %s 0x%x",
126-
&name, &size, &refcount, &dependencies, &state, &address)
142+
kmod, err := parseKernelModuleLine(line)
127143
if err != nil {
128-
log.Warnf("err parsing line in modules: '%s'", err)
129-
continue
130-
}
131-
if nFields < 6 {
132-
log.Warnf("unexpected line in modules: '%s'", line)
133-
continue
144+
return nil, fmt.Errorf("failed to parse kernel module line: %v", err)
134145
}
135-
if address == 0 {
146+
if kmod.address == 0 {
136147
continue
137148
}
138149
atLeastOneValidAddress = true
139150

140-
symmap.Add(libpf.Symbol{
141-
Name: libpf.SymbolName(name),
142-
Address: libpf.SymbolValue(address),
143-
Size: int(size),
144-
})
151+
modules = append(modules, kmod)
145152
}
146153

147154
if count > 0 && !atLeastOneValidAddress {
148155
return nil, errors.New("addresses from all modules is zero - check process permissions")
149156
}
150157

151-
symmap.Finalize()
158+
return modules, nil
159+
}
152160

153-
return &symmap, nil
161+
type kernelModule struct {
162+
name string
163+
size uint64
164+
address uint64
165+
}
166+
167+
func parseKernelModuleLine(line string) (kernelModule, error) {
168+
// The format is: "name size refcount dependencies state address"
169+
parts := strings.SplitN(line, " ", 6)
170+
if len(parts) < 6 {
171+
return kernelModule{}, fmt.Errorf("unexpected line in modules: '%s'", line)
172+
}
173+
174+
size, err := parseSize(parts[1])
175+
if err != nil {
176+
return kernelModule{}, fmt.Errorf("failed to parse size value: '%s'", parts[1])
177+
}
178+
179+
address, err := parseAddress(parts[5])
180+
if err != nil {
181+
return kernelModule{}, fmt.Errorf("failed to parse address value: '%s'", parts[5])
182+
}
183+
184+
return kernelModule{
185+
name: parts[0],
186+
size: size,
187+
address: address,
188+
}, nil
189+
}
190+
191+
func parseAddress(addressStr string) (uint64, error) {
192+
address, err := strconv.ParseUint(strings.TrimPrefix(addressStr, "0x"), 16, 64)
193+
if err != nil {
194+
return 0, fmt.Errorf("failed to parse address as hex value: '%s'", addressStr)
195+
}
196+
197+
return address, nil
198+
}
199+
200+
func parseSize(sizeStr string) (uint64, error) {
201+
size, err := strconv.ParseUint(sizeStr, 10, 64)
202+
if err != nil {
203+
return 0, fmt.Errorf("failed to parse size int value: %q", sizeStr)
204+
}
205+
206+
return size, nil
154207
}
155208

156209
// IsPIDLive checks if a PID belongs to a live process. It will never produce a false negative but

proc/proc_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
package proc
55

66
import (
7+
"bufio"
8+
"bytes"
79
"testing"
810

911
"go.opentelemetry.io/ebpf-profiler/libpf"
@@ -38,3 +40,66 @@ func TestParseKallSyms(t *testing.T) {
3840
assertSymbol(t, symmap, "cpu_tss_rw", 0x6000)
3941
assertSymbol(t, symmap, "hid_add_device", 0xffffffffc033e550)
4042
}
43+
44+
func TestParseKernelModules(t *testing.T) {
45+
content := []byte(`i40e 589824 - - Live 0xffffffffc0321000
46+
mpt3sas 405504 - - Live 0xffffffffc02ab000
47+
ahci 45056 - - Live 0xffffffffc0294000
48+
libahci 49152 - - Live 0xffffffffc027f000
49+
sp5100_tco 12288 - - Live 0xffffffffc0274000
50+
watchdog 40960 - - Live 0xffffffffc025f000
51+
k10temp 12288 - - Live 0xffffffffc0254000`)
52+
53+
kmods, err := parseKernelModules(bufio.NewScanner(bytes.NewReader(content)))
54+
require.NoError(t, err)
55+
56+
require.Len(t, kmods, 7)
57+
require.Equal(t, []kernelModule{
58+
{
59+
name: "i40e",
60+
size: 589824,
61+
address: 0xffffffffc0321000,
62+
},
63+
{
64+
name: "mpt3sas",
65+
size: 405504,
66+
address: 0xffffffffc02ab000,
67+
},
68+
{
69+
name: "ahci",
70+
size: 45056,
71+
address: 0xffffffffc0294000,
72+
},
73+
{
74+
name: "libahci",
75+
size: 49152,
76+
address: 0xffffffffc027f000,
77+
},
78+
{
79+
name: "sp5100_tco",
80+
size: 12288,
81+
address: 0xffffffffc0274000,
82+
},
83+
{
84+
name: "watchdog",
85+
size: 40960,
86+
address: 0xffffffffc025f000,
87+
},
88+
{
89+
name: "k10temp",
90+
size: 12288,
91+
address: 0xffffffffc0254000,
92+
},
93+
}, kmods)
94+
}
95+
96+
func TestParseKernelModuleLine(t *testing.T) {
97+
line := "i40e 589824 - - Live 0xffffffffc0364000"
98+
kmod, err := parseKernelModuleLine(line)
99+
require.NoError(t, err)
100+
require.Equal(t, kernelModule{
101+
name: "i40e",
102+
size: 589824,
103+
address: 0xffffffffc0364000,
104+
}, kmod)
105+
}

processmanager/synthdeltas.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func createVDSOSyntheticRecordArm64(ef *pfelf.File) sdtypes.IntervalData {
4848
deltas = append(
4949
deltas,
5050
sdtypes.StackDelta{Address: addr, Info: sdtypes.UnwindInfoSignal},
51-
sdtypes.StackDelta{Address: addr + uint64(sym.Size), Info: sdtypes.UnwindInfoLR},
51+
sdtypes.StackDelta{Address: addr + sym.Size, Info: sdtypes.UnwindInfoLR},
5252
)
5353
return
5454
}
@@ -60,7 +60,7 @@ func createVDSOSyntheticRecordArm64(ef *pfelf.File) sdtypes.IntervalData {
6060

6161
var frameStart uint64
6262
var frameSize int
63-
for offs := uint64(0); offs < uint64(sym.Size); offs += 4 {
63+
for offs := uint64(0); offs < sym.Size; offs += 4 {
6464
inst, err := aa.Decode(code[offs:])
6565
if err != nil {
6666
continue

0 commit comments

Comments
 (0)