Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
365 changes: 279 additions & 86 deletions cmd/stackwhere/list.go

Large diffs are not rendered by default.

77 changes: 75 additions & 2 deletions cmd/stackwhere/list_test.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
package main

import (
"slices"
"testing"

"github.com/cilium/ebpf"
"github.com/cilium/stackwhere/internal/dwarf"
)

func TestGetStackSlotUsage(t *testing.T) {
func TestGetStackSlotUsageFromDWARF(t *testing.T) {
tree, err := dwarf.NewDWARFTree("../../testdata/basic.o")
if err != nil {
t.Fatalf("failed to parse DWARF data: %v", err)
}

stackUsage := getStackSlotUsage(tree, "cil_entry")
subProgs := tree.ByType(dwarf.TagSubprogram)
idx := slices.IndexFunc(subProgs, func(n *dwarf.Node) bool {
return n.Name() == "cil_entry"
})
if idx == -1 {
t.Fatalf("failed to find subprogram node for cil_entry")
}

stackUsage := stackSlotsFromDWARFVars(subProgs[idx])
if len(stackUsage) != 3 {
t.Fatalf("expected 3 stack slots, got %d", len(stackUsage))
}
Expand Down Expand Up @@ -72,6 +82,69 @@ func TestGetStackSlotUsage(t *testing.T) {
}
}

func TestGetStackSlotUsageFromInsns(t *testing.T) {
tree, err := dwarf.NewDWARFTree("../../testdata/spill.o")
if err != nil {
t.Fatalf("failed to parse DWARF data: %v", err)
}

spec, err := ebpf.LoadCollectionSpec("../../testdata/spill.o")
if err != nil {
t.Fatalf("failed to load collection spec: %v", err)
}

subProgs := tree.ByType(dwarf.TagSubprogram)
idx := slices.IndexFunc(subProgs, func(n *dwarf.Node) bool {
return n.Name() == "cil_entry"
})
if idx == -1 {
t.Fatalf("failed to find subprogram node for cil_entry")
}

stackUsage := stackSlotsFromInsns(spec.Programs["cil_entry"], subProgs[idx])
if len(stackUsage) != 1 {
t.Fatalf("expected 1 stack slot group, got %d", len(stackUsage))
}

// Verify each stack slot group contains expected slots
slotGroups := []struct {
index int
expected map[string]int64
}{
{
index: 0,
expected: map[string]int64{
"r2": -1,
},
},
}

for _, group := range slotGroups {
found := make(map[string]int64)
for _, slot := range stackUsage[group.index] {
found[slot.Name] = slot.ByteSize
}

// Check all expected slots are present with correct size
for name, expectedSize := range group.expected {
actualSize, ok := found[name]
if !ok {
t.Errorf("slot group %d: expected slot %q not found", group.index, name)
continue
}
if actualSize != expectedSize {
t.Errorf("slot group %d: slot %q has size %d, expected %d", group.index, name, actualSize, expectedSize)
}
delete(found, name)
}

// Check no unexpected slots are present
if len(found) > 0 {
t.Errorf("slot group %d: unexpected slots found: %v", group.index, found)
}
}
}

func TestGetProgramStackUsage(t *testing.T) {
tree, err := dwarf.NewDWARFTree("../../testdata/basic.o")
if err != nil {
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ module github.com/cilium/stackwhere
go 1.25.0

require (
github.com/davecgh/go-spew v1.1.1
github.com/cilium/ebpf v0.21.0
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/spf13/cobra v1.10.2
)

require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/pflag v1.0.9 // indirect
golang.org/x/sys v0.37.0 // indirect
)
20 changes: 18 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
github.com/cilium/ebpf v0.21.0 h1:4dpx1J/B/1apeTmWBH5BkVLayHTkFrMovVPnHEk+l3k=
github.com/cilium/ebpf v0.21.0/go.mod h1:1kHKv6Kvh5a6TePP5vvvoMa1bclRyzUXELSs272fmIQ=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6 h1:teYtXy9B7y5lHTp8V9KPxpYRAVA7dozigQcMiBust1s=
github.com/go-quicktest/qt v1.101.1-0.20240301121107-c6c8733fa1e6/go.mod h1:p4lGIVX+8Wa6ZPNDvqcxq36XpUDLh42FLetFU7odllI=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1 change: 1 addition & 0 deletions internal/dwarf/loclist.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ func NewLoclistTable(f *elf.File) (*LoclistTable, error) {
}

if f.Class != elf.ELFCLASS64 {
// Code should work, but untested
return nil, fmt.Errorf("unexpected 32-bit ELF file")
}

Expand Down
Loading