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 0000000..abcb079 Binary files /dev/null and b/testdata/noinline.o differ