From 17e6d6f50becee93d2db6bd7fc8bf96339189a08 Mon Sep 17 00:00:00 2001 From: immanuwell Date: Thu, 20 Aug 2026 20:27:04 +0400 Subject: [PATCH 1/2] fix: re-sort collection summaries after inferring usage Signed-off-by: immanuwell --- cmd/stackwhere/list_test.go | 26 ++++++++++++++++++++++++++ internal/stackview/stackview.go | 6 +++--- testdata/noinline.c | 9 +++++++++ testdata/noinline.o | Bin 3984 -> 4680 bytes 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/cmd/stackwhere/list_test.go b/cmd/stackwhere/list_test.go index 4fe1bf3..aedaa72 100644 --- a/cmd/stackwhere/list_test.go +++ b/cmd/stackwhere/list_test.go @@ -110,6 +110,32 @@ func TestListCollectionIncludesInstructionOnlyStackUsage(t *testing.T) { } } +func TestListCollectionSortsAfterInferringStackUsage(t *testing.T) { + cmd := root() + cmd.SetArgs([]string{"list", "../../testdata/noinline.o", "-j"}) + + var stdout bytes.Buffer + cmd.SetOut(&stdout) + + if err := cmd.Execute(); err != nil { + t.Fatalf("list command failed: %v", err) + } + + var got []stackview.ProgramStackUsage + if err := json.Unmarshal(stdout.Bytes(), &got); err != nil { + t.Fatalf("failed to decode JSON output: %v", err) + } + + want := []stackview.ProgramStackUsage{ + {Name: "entry", StackUsage: 8}, + {Name: "z_known", StackUsage: 8}, + {Name: "helper", StackUsage: 0}, + } + if !slices.Equal(got, want) { + t.Fatalf("unexpected JSON output: got %#v want %#v", got, want) + } +} + func TestListCollectionIncludesVoidFunction(t *testing.T) { cmd := root() cmd.SetArgs([]string{"list", "../../testdata/noinline.o"}) diff --git a/internal/stackview/stackview.go b/internal/stackview/stackview.go index aeb1c48..fc7fcb6 100644 --- a/internal/stackview/stackview.go +++ b/internal/stackview/stackview.go @@ -112,7 +112,7 @@ func (a *Analyzer) CollectionSummaryInCollection() ([]ProgramStackUsage, error) } summary := a.CollectionSummary() - filtered := make([]ProgramStackUsage, 0, len(summary)) + stackUsagePerProgram := make(map[string]int64, len(summary)) subProgsDwarf := a.tree.ByType(dbgdwarf.TagSubprogram) for _, prog := range summary { fn, ok := a.functions[prog.Name] @@ -128,10 +128,10 @@ func (a *Analyzer) CollectionSummaryInCollection() ([]ProgramStackUsage, error) prog.StackUsage = max(prog.StackUsage, inferredUsage) } - filtered = append(filtered, prog) + stackUsagePerProgram[prog.Name] = prog.StackUsage } - return filtered, nil + return SortProgramStackUsage(stackUsagePerProgram), nil } func stackUsageFromSlots(slots slotList) int64 { diff --git a/testdata/noinline.c b/testdata/noinline.c index cff74aa..becd6c1 100644 --- a/testdata/noinline.c +++ b/testdata/noinline.c @@ -1,5 +1,6 @@ #define __section(X) __attribute__((section(X), used)) #define __noinline __attribute__((noinline)) +#define force_on_stack(x) asm volatile("" :: "r"(&(x))) static __noinline void helper(int *value) { @@ -13,3 +14,11 @@ __section("tc") int entry(void *ctx) helper(&value); return value; } + +__section("tc/known") int z_known(void *ctx) +{ + long value = 0; + + force_on_stack(value); + return value; +} diff --git a/testdata/noinline.o b/testdata/noinline.o index abcb0798392a653b00de524439b2717ed0d046b0..13fe0ba7eafc8b1186a87822c53900c5a656c2e7 100644 GIT binary patch literal 4680 zcmbtXO>9(E6h800zILX=Z;O^c73~; z(&dZ0uxXqaY=OyDh`T+NN{MvO#g0;Qg)7K=U|*aB2Gr*fJp(|cG*QQTx{}6U=a47e zZ(-skr28F=9nvMUDDd}FEuHQ{j)#2lyPW5`#J>b6u9sEPPU+FkJ#JdBAi33a|5n0u1;utCIGuQd1rIsiTlE`g7MC%}{7^WfLPZ-RG}M$3h2 zP^=WHI8(JgPiE_14u9h-I*-)<)rBn@TXQW&W)9LK@*J5B)G&S+HncR4nS{j+(c!eD7|C>^`uJK>V6bq$3^iF0eZ!>V6O(1ShwN%Ee$8 zm}{A{ru-~e7DRawe+Eu2ZN~i^*a@PX;_H74x$JKG{Q=muuXVlT3o1pGFY|GM**4fm zJ5Y(lD=9ABLfDcbTW;>XEoToQeFWws+JZ6RIDgNXEe;3>jL9-paL-xh&h;O4)QkA% z`mgt{p4@Zm!W%#QGPP{idTcM*coJT>`nb>;hB!mG*>fE z%qwqIc*0valhF2O3L){-DbG}SQEQo@@YD^NAx0egv?Ci&eF<9adAvQbI+%NOS;=(= z#N6B$z9|xSz(Y?EfcQ38h4};^V(K0u01@*JuOt8wGsbEH5Ha6yJRYk@9}@NEO~ zsnMJBG8j)%k->q5S6SHX-`KCW^d>*nu_w@f8<<2)o4o`e zV%i@DlZ^d|2sZGPg)dq7S`0J(O$&c#;oC9H^?$c8+XBhtH_yWH^GLxiUJvfq?4NV$ zvtSZ)Bkv#p8U5}EHtM%RW9s?A%~&{YPn)A!Z{oie!`$DTx%#V{87qyR8qXI-M{A`? zi9U~+TB(wG`uUw1ek-*>tvX&Q*TcFfW#m*3Yx#*IN9rYt8zM91Z<{KK^#$SD18kqfoGP{G0XbW?HG;H(-gMY%Lo&P~?kT!;TOj!6wVD^;} zOFpCx=V>|f;69DNk$(VLyY;6aCz<;lp{BpV?0I%gsJpHWuIkYYw(UhIY#D9$YvG5+ zQIEFmtB|+b|8Bj}ecF%vkN0P@|1{)wOuF3F!o>tJvTfP_Y#Gfv`CvhI{cPJI*tE<4 zeVzXm1_3dDesApadloXrwAb0J*MA$jIGOd$cnV50kK28%{aK$l*|sO4Y?uEKg`g4j zH_D&=&d&c&$n2POxvSUz)Kao<$7vaWWunxVv|(T=ZGZd^-8TQzI{(`$T9iNUjGg~C zkXcJ8kLzsCpo7uS_-p));44hp)$gGGiFH^T^8EQb-T0gPdjqm|>nC(Wx&nQiY}@Nl zwp;(EUVoo<=KB0L+Up;Jj4`v|I9=20n>>xqtZ&AvP6h3ob$=u{Ni80<-iZ?YWrY$MfK9Y?ZDn$erK0u@!6)m(_DWa7YTPz~d zg+k&H=|U;e3XO;r>rYUuD^U={r6^i-BO)&KoZGo2lzwnB=R1!tGiTN$t!0@#s=Z+<#A|I z#eff^F0N`ZUxRgC0BZVqysa-c&ixROp%5dd>;|oifRBwf{9%bTjs#o>mce4tn! zYYoNJchxn`LIm!T_=mb)sk&)wjTL3TdPf-?jui_-eB*>*2HeGG4lXs=^=FC+|C~dr zzZ+L$Mf*MviLe6L7Vj<0D!Iy9)ZYYu_8aAvDW>H3z6fQkMZNwd^7xIF$?B0;0%aBC zZSuR_s5?)wHQhy}J4M&w73L_uneNagx=9>Mw96L$Gzf7Tn%7z-Pe1%`l$L3-bu6lW eHDPe^V$?N1QC{O= Date: Thu, 20 Aug 2026 20:38:30 +0400 Subject: [PATCH 2/2] ci: update golangci-lint for Go 1.27 Signed-off-by: immanuwell --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index b091456..107bdb5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,7 +22,7 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v9 with: - version: v2.11 + version: v2.13 # Run go test to ensure tests pass gotest: name: tests