From ca30b376278bf65d82f81b9e54191b52816c931c Mon Sep 17 00:00:00 2001 From: immanuwell Date: Wed, 15 Jul 2026 11:35:28 +0400 Subject: [PATCH] fix: support DW_RLE_startx_length range entries Signed-off-by: immanuwell --- cmd/stackwhere/list_test.go | 27 +++++++++++++++++++++++++++ internal/dwarf/rangelist.go | 27 +++++++++++++++++++++++++-- testdata/Makefile | 1 + testdata/noinline.c | 15 +++++++++++++++ testdata/noinline.o | Bin 0 -> 3984 bytes 5 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 testdata/noinline.c create mode 100644 testdata/noinline.o diff --git a/cmd/stackwhere/list_test.go b/cmd/stackwhere/list_test.go index 3e8601a..1180e23 100644 --- a/cmd/stackwhere/list_test.go +++ b/cmd/stackwhere/list_test.go @@ -282,3 +282,30 @@ func TestListCollectionJSONOrdersEqualUsageByName(t *testing.T) { t.Fatalf("unexpected JSON output: got %#v want %#v", got, want) } } + +func TestListProgramSupportsStartXLengthRangeLists(t *testing.T) { + cmd := root() + cmd.SetArgs([]string{"list", "../../testdata/noinline.o", "entry", "-j"}) + + var stdout bytes.Buffer + cmd.SetOut(&stdout) + + if err := cmd.Execute(); err != nil { + t.Fatalf("list command failed: %v", err) + } + + var got slotList + if err := json.Unmarshal(stdout.Bytes(), &got); err != nil { + t.Fatalf("failed to decode JSON output: %v", err) + } + + want := slotList{ + { + {Offset: 4, Name: "r1", ByteSize: -1}, + }, + } + if len(got) != len(want) || len(got[0]) != len(want[0]) || + got[0][0].Offset != want[0][0].Offset || got[0][0].Name != want[0][0].Name || got[0][0].ByteSize != want[0][0].ByteSize { + t.Fatalf("unexpected JSON output: got %#v want %#v", got, want) + } +} diff --git a/internal/dwarf/rangelist.go b/internal/dwarf/rangelist.go index e63df32..5fc0d6e 100644 --- a/internal/dwarf/rangelist.go +++ b/internal/dwarf/rangelist.go @@ -42,8 +42,8 @@ const ( DW_RLE_end_of_list rangelistDescriptorCode = 0x00 DW_RLE_base_addressx rangelistDescriptorCode = 0x01 // DW_RLE_startx_endx = 0x02 - // DW_RLE_startx_length = 0x03 - DW_RLE_offset_pair rangelistDescriptorCode = 0x04 + DW_RLE_startx_length rangelistDescriptorCode = 0x03 + DW_RLE_offset_pair rangelistDescriptorCode = 0x04 // DW_RLE_base_address = 0x05 // DW_RLE_start_end = 0x06 // DW_RLE_start_length = 0x07 @@ -167,6 +167,29 @@ loop: if idx < uint64(len(debugAddrs)) { currentBase = debugAddrs[idx] } + case DW_RLE_startx_length: + var startIdx, length uint64 + var l uint32 + startIdx, l, err = leb128.DecodeUnsigned(r) + if err != nil { + return nil, fmt.Errorf("error parsing startx length entry: %w", err) + } + off += uint64(l) + + length, l, err = leb128.DecodeUnsigned(r) + if err != nil { + return nil, fmt.Errorf("error parsing startx length entry: %w", err) + } + off += uint64(l) + + if startIdx >= uint64(len(debugAddrs)) { + return nil, fmt.Errorf("startx length entry references invalid debug address index: %d", startIdx) + } + + entry.Ranges = append(entry.Ranges, Range{ + Start: debugAddrs[startIdx], + End: debugAddrs[startIdx] + length, + }) case DW_RLE_offset_pair: var rng Range var l uint32 diff --git a/testdata/Makefile b/testdata/Makefile index d22f7b7..d0bdcf3 100644 --- a/testdata/Makefile +++ b/testdata/Makefile @@ -20,6 +20,7 @@ docker: TARGETS := \ basic \ equal \ + noinline \ spill .PHONY: all diff --git a/testdata/noinline.c b/testdata/noinline.c new file mode 100644 index 0000000..cff74aa --- /dev/null +++ b/testdata/noinline.c @@ -0,0 +1,15 @@ +#define __section(X) __attribute__((section(X), used)) +#define __noinline __attribute__((noinline)) + +static __noinline void helper(int *value) +{ + *value = 42; +} + +__section("tc") int entry(void *ctx) +{ + int value = 0; + + helper(&value); + return value; +} diff --git a/testdata/noinline.o b/testdata/noinline.o new file mode 100644 index 0000000000000000000000000000000000000000..abcb0798392a653b00de524439b2717ed0d046b0 GIT binary patch literal 3984 zcmbVPO>7%g5T5mVlQ?N;(f~=-LN;kbofcfjP1}_46Cqk!sS*WIsp`db>`iQN>|$@C zw)7_;ia2m6Afz5Z1<^x#sziI>1_uz_kT@ZZTtI>g;=qAQ;rrgcXK!CD4vaMW=9`%} zGw;3GxAv98$B!f&M+`agx3rPbid;*z&X@6vu`{lGC!izYV>ka%Je!Hj%E4vqic+NsP3edv+qwGktx1BB{+N zsduw5q}0KlI6WA!z(=$MfTe1pZ4)>lX*`|NuB6Hk+-^x#F(#!;`l#?;rdhfYBOFhA zlI(U~>XPIVp!6iYWU7~L!nB_BsGUzjb|vj%&Q7Jq19TF61{{E21GCB%@I~S@7a^f<_=_YxqaC~`?CA9dy1v~GlvdN9o%2amY$fp z9Gp8lbvfpen?8`q%}h$IUa3_pwIEZJz0F2Zf?C)(FO^y-<)C^tXvj*Tx*SL`JSW>x z1IstW)mn7pcL)6v5tmH9t1*Vw)}medT_`Xr_97pLyW&H|HiT_cYXaudpTxNw7r~sT zb{W21RI*MMA1xz{7PU9F$b7yT6hrJ>dOR$SPx^57m2-NfUMcyz5nvL>tk#}>Of7zL zR#J^1TyE5Sg=h7i=ncw*!MRYHVIiy({e0f!@>M(?h*@?=!6X$4{?q<+ZdNV{_snPQ zAhrVeZSWeH#0_WTV%>_kMAgqJQ5S6>Hm)oE=sxH7m=35~1nuZ<>G9@?PfF>Q&h z*PJ_hhSUq@A+e`O>^GjK$xO_?Hj#XYv_r;uDh}2b0j0%Ks^aB24><7-qaP7Cvj?RSRE_ zVa8jt@Rt^j?+4E)UN7^TdMVSM1(VEr#v`cK!oAN}_^8J8XN+R)&GC^ z5mUK;Hr>(<_^V}5*Jez|_li38&5Y^iv~14Zm~>bJ6T|C*z>=Jn(yx% zI8N{Cg3Nn^Ux;d*X1>w$Zm`$HIIDbsK8%Le)Aqdzi>;&ckXANZGb6$FeG}?V^|oRR3?f{#8Ahb6@9A{t!iurli!TXFc{hRa6HUQ0OYG@`(gXO4pXQ4%WMpgsf+dV9 zR8rRYr!6Dz=Qxc5ST4%^v3@DPk2^!Q=i|Ri$NI19`mgEvte?OA?E3FO*C~HlCz^vj zPG-K*-GdGlT7W1BOod%N_FbUz45xG<1w< z&KaVj3H6h({oOTsli!T*!{8oYuVYv>J{;F{BIC#PlMIfK$j=aTs~D9UXLSA(dIAUj KSuypSd-Y$``7uZU literal 0 HcmV?d00001