X Tutup
Skip to content

Commit b857bac

Browse files
derekparkergopherbot
authored andcommitted
dwtest: add more loclist tests
Adds tests to verify changes in CL 696575: https://go-review.googlesource.com/c/go/+/696575 Updates the dwdumploc program to search for locations with liveness in mind. For example, for return parameters (especially unnamed) they will not be live until the function return (e.g. OpMakeResult) and so trying to find the location list with a PC value at the function entry will not yield anything. Change-Id: Ia7c1455e7c875bdf29fca5e2fb540cd771555635 Reviewed-on: https://go-review.googlesource.com/c/debug/+/714340 Auto-Submit: Keith Randall <khr@golang.org> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Junyang Shao <shaojunyang@google.com> Reviewed-by: Keith Randall <khr@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
1 parent 55b825d commit b857bac

File tree

4 files changed

+387
-28
lines changed

4 files changed

+387
-28
lines changed

dwtest/dwloc_test.go

Lines changed: 306 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ func runHarness(t *testing.T, harnessPath string, exePath string, fcn string) st
113113
if err := cmd.Run(); err != nil {
114114
t.Fatalf("running 'harness -m %s -f %s': %v", exePath, fcn, err)
115115
}
116-
return strings.TrimSpace(string(b.Bytes()))
116+
return strings.TrimSpace(b.String())
117117
}
118118

119119
// gobuild is a helper to build a Go program from source code,
@@ -151,6 +151,7 @@ import (
151151
"context"
152152
"strings"
153153
"fmt"
154+
"net/http"
154155
)
155156
156157
var G int
@@ -207,11 +208,109 @@ func (a Address) String() string {
207208
return sb.String()
208209
}
209210
211+
//go:noinline
212+
func Issue65405(a int, b string) (int, error) {
213+
http.Handle("/", http.StripPrefix("/static/", http.FileServer(http.Dir("./output"))))
214+
return a + len(b), nil
215+
}
216+
217+
//go:noinline
218+
func RegisterLivenessNamedRetParam() (result int) {
219+
// This function demonstrates the register reuse issue.
220+
// The return value 'result' should only be valid in its register
221+
// after it's actually set, not throughout the entire function.
222+
223+
// Early in the function, do some work that uses registers
224+
x := 42
225+
y := 100
226+
z := x * y // Register allocator may use RAX here for multiplication
227+
228+
// Do more work that might reuse the return register
229+
for i := 0; i < 10; i++ {
230+
z += i // More register usage
231+
}
232+
233+
// Only NOW do we actually set the return value
234+
result = z // Return value is only valid in RAX from here
235+
236+
// A debugger querying 'result' before this point would get
237+
// incorrect values if the location list claims it's in RAX
238+
// for the entire function
239+
return result
240+
}
241+
242+
//go:noinline
243+
func RegisterLivenessUnnamedRetParam() int {
244+
x := 42
245+
y := 100
246+
z := x * y
247+
248+
for i := 0; i < 10; i++ {
249+
z += i // More register usage
250+
}
251+
252+
return z
253+
}
254+
255+
//go:noinline
256+
func multiReturn() (int, int, int, string, float64) {
257+
return 1, 2, 3, "test", 4.5
258+
}
259+
260+
//go:noinline
261+
func singleReturn() int {
262+
return 42
263+
}
264+
265+
//go:noinline
266+
func multiReturnStmts(i int) int {
267+
if i < 10 {
268+
return 55
269+
}
270+
i += 100
271+
i *= i
272+
return i
273+
}
274+
275+
//go:noinline
276+
func ManyArgsWithNamedReturns(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p int) (sum int, product int) {
277+
// Use all arguments in computations
278+
sum = a + b + c + d + e + f + g + h
279+
product = 1
280+
281+
// More operations to ensure all args are used
282+
temp1 := i * j
283+
temp2 := k * l
284+
temp3 := m * n
285+
temp4 := o * p
286+
287+
sum += temp1 + temp2 + temp3 + temp4
288+
289+
// Compute product using all arguments
290+
product = (a + 1) * (b + 1) * (c + 1) * (d + 1)
291+
product += (e + f) * (g + h) * (i + j) * (k + l)
292+
product += (m + n) * (o + p)
293+
294+
// Final adjustments
295+
sum = sum * 2
296+
product = product / 2
297+
298+
return sum, product
299+
}
300+
210301
func main() {
211302
Issue47354("poo")
212303
var d DB
213304
d.Issue46845(context.Background(), nil, func(error) {}, "foo", nil)
214305
Issue72053()
306+
_, _ = Issue65405(42, "test")
307+
a, b, _, _, _ := multiReturn()
308+
f := singleReturn()
309+
_ = a + b + f
310+
_ = RegisterLivenessNamedRetParam()
311+
_ = RegisterLivenessUnnamedRetParam()
312+
_, _ = ManyArgsWithNamedReturns(1, 2, 3, 4, 5, 6, a, b, f, 1, 2, 3, 4, 5, 6, 7)
313+
_ = multiReturnStmts(a+b)
215314
}
216315
217316
`
@@ -243,8 +342,10 @@ func testIssue46845(t *testing.T, harnessPath string, ppath string) {
243342
4: in-param "release" loc="{ [0: S=0 RSI] }"
244343
5: in-param "query" loc="{ [0: S=8 R8] [1: S=8 R9] }"
245344
6: in-param "args" loc="{ [0: S=8 addr=0x1000] [1: S=8 addr=0x1008] [2: S=8 addr=0x1010] }"
246-
7: out-param "res" loc="<not available>"
247-
8: out-param "err" loc="<not available>"
345+
7: out-param "res" at RET[0] loc="addr=f98"
346+
7: out-param "res" at RET[1] loc="addr=f98"
347+
8: out-param "err" at RET[0] loc="addr=fa8"
348+
8: out-param "err" at RET[1] loc="addr=fa8"
248349
`,
249350
"arm64": `
250351
1: in-param "db" loc="{ [0: S=0 R0] }"
@@ -261,7 +362,7 @@ func testIssue46845(t *testing.T, harnessPath string, ppath string) {
261362
got := runHarness(t, harnessPath, ppath, "main."+fname)
262363
want := strings.TrimSpace(expected[runtime.GOARCH])
263364
if got != want {
264-
t.Errorf("failed Issue47354 arch %s:\ngot: %s\nwant: %s",
365+
t.Errorf("failed Issue46845 arch %s:\ngot: %s\nwant: %s",
265366
runtime.GOARCH, got, want)
266367
}
267368
}
@@ -270,7 +371,7 @@ func testIssue72053(t *testing.T, harnessPath string, ppath string) {
270371
testenv.NeedsGo1Point(t, 25)
271372
testenv.NeedsArch(t, "amd64")
272373

273-
want := "1: in-param \"a\" loc=\"{ [0: S=1 RAX] [1: S=7 addr=0x0] [2: S=8 RBX] [3: S=8 RCX] }\"\n2: out-param \"~r0\" loc=\"addr=fa8\""
374+
want := "1: in-param \"a\" loc=\"{ [0: S=1 RAX] [1: S=7 addr=0x0] [2: S=8 RBX] [3: S=8 RCX] }\"\n2: out-param \"~r0\" at RET[0] loc=\"addr=fa8\""
274375
got := runHarness(t, harnessPath, ppath, "main.Address.String")
275376
if got != want {
276377
t.Errorf("failed Issue72053 arch %s:\ngot: %q\nwant: %q",
@@ -300,6 +401,182 @@ func testRuntimeThrow(t *testing.T, harnessPath, nooptHarnessPath, ppath string)
300401
}
301402
}
302403

404+
func testIssue65405(t *testing.T, harnessPath string, ppath string) {
405+
// Test that function parameters have location lists
406+
expected := map[string]string{
407+
"amd64": `1: in-param "a" loc="{ [0: S=0 RAX] }"
408+
2: in-param "b" loc="{ [0: S=8 RBX] [1: S=8 RCX] }"
409+
3: out-param "~r0" at RET[0] loc="{ [0: S=0 RAX] }"
410+
4: out-param "~r1" at RET[0] loc="{ [0: S=8 RBX] [1: S=8 RCX] }"`,
411+
"arm64": `1: in-param "a" loc="{ [0: S=0 R0] }"
412+
2: in-param "b" loc="{ [0: S=8 R1] [1: S=8 R2] }"
413+
3: out-param "~r0" at RET[0] loc="{ [0: S=0 R0] }"
414+
4: out-param "~r1" at RET[0] loc="{ [0: S=8 R1] [1: S=8 R2] }"`,
415+
}
416+
fname := "Issue65405"
417+
got := runHarness(t, harnessPath, ppath, "main."+fname)
418+
want := expected[runtime.GOARCH]
419+
if got != want {
420+
t.Errorf("failed Issue65405 arch %s:\ngot: %q\nwant: %q",
421+
runtime.GOARCH, got, want)
422+
}
423+
}
424+
425+
func testReturnValueRegisters(t *testing.T, harnessPath string, ppath string) {
426+
// Test return value register assignments for multiReturn function
427+
// Verify that return values follow ABI conventions
428+
expected := map[string]string{
429+
"amd64": `1: out-param "~r0" at RET[0] loc="{ [0: S=0 RAX] }"
430+
2: out-param "~r1" at RET[0] loc="{ [0: S=0 RBX] }"
431+
3: out-param "~r2" at RET[0] loc="{ [0: S=0 RCX] }"
432+
4: out-param "~r3" at RET[0] loc="{ [0: S=8 RDI] [1: S=8 RSI] }"
433+
5: out-param "~r4" at RET[0] loc="{ [0: S=0 X0] }"`,
434+
"arm64": `1: out-param "~r0" at RET[0] loc="{ [0: S=0 R0] }"
435+
2: out-param "~r1" at RET[0] loc="{ [0: S=0 R1] }"
436+
3: out-param "~r2" at RET[0] loc="{ [0: S=0 R2] }"
437+
4: out-param "~r3" at RET[0] loc="{ [0: S=8 R3] [1: S=8 R4] }"
438+
5: out-param "~r4" at RET[0] loc="{ [0: S=0 F0] }"`,
439+
}
440+
fname := "multiReturn"
441+
got := runHarness(t, harnessPath, ppath, "main."+fname)
442+
want := expected[runtime.GOARCH]
443+
if got != want {
444+
t.Errorf("failed ReturnValueRegisters arch %s:\ngot: %q\nwant: %q",
445+
runtime.GOARCH, got, want)
446+
}
447+
}
448+
449+
func testRegisterLivenessNamedRetParam(t *testing.T, harnessPath, nooptHarnessPath, ppath, nooppath string) {
450+
fname := "RegisterLivenessNamedRetParam"
451+
expected := map[string]string{
452+
"amd64": `1: out-param "result" at RET[0] loc="{ [0: S=0 RAX] }"`,
453+
"arm64": ``,
454+
}
455+
456+
// Test only optimized builds (non-optimized results are passed on the stack)
457+
testCases := []struct {
458+
name string
459+
harness string
460+
binary string
461+
}{
462+
{"optimized", harnessPath, ppath},
463+
}
464+
465+
for _, tc := range testCases {
466+
t.Run(tc.name, func(t *testing.T) {
467+
got := runHarness(t, tc.harness, tc.binary, "main."+fname)
468+
want := expected[runtime.GOARCH]
469+
if got != want {
470+
t.Fatalf("return parameter 'result' has incorrect location in %s build:\ngot:\n%s\nwant:\n%s", tc.name, got, want)
471+
}
472+
})
473+
}
474+
}
475+
476+
func testLivenessForUnnamedRetParams(t *testing.T, harnessPath, nooptHarnessPath, ppath, nooppath string) {
477+
// This test verifies that return parameters have precise location lists.
478+
// Return parameters should only be valid in their ABI register after assignment,
479+
// not throughout the entire function. The location list should start from the
480+
// assignment point, not from function entry.
481+
482+
fname := "RegisterLivenessUnnamedRetParam"
483+
expected := map[string]string{
484+
"amd64": `1: out-param "~r0" at RET[0] loc="{ [0: S=0 RAX] }"`,
485+
"arm64": ``,
486+
}
487+
488+
// Test only optimized builds (non-optimized results are passed on the stack)
489+
testCases := []struct {
490+
name string
491+
harness string
492+
binary string
493+
}{
494+
{"optimized", harnessPath, ppath},
495+
}
496+
497+
for _, tc := range testCases {
498+
t.Run(tc.name, func(t *testing.T) {
499+
got := runHarness(t, tc.harness, tc.binary, "main."+fname)
500+
want := expected[runtime.GOARCH]
501+
if got != want {
502+
t.Fatalf("return parameter 'result' has incorrect location in %s build:\ngot:\n%s\nwant:\n%s", tc.name, got, want)
503+
}
504+
})
505+
}
506+
}
507+
508+
func testManyArgsWithNamedReturns(t *testing.T, harnessPath, nooptHarnessPath, ppath, nooppath string) {
509+
fname := "ManyArgsWithNamedReturns"
510+
expected := map[string]string{
511+
"amd64": `1: in-param "a" loc="{ [0: S=0 RAX] }"
512+
2: in-param "b" loc="{ [0: S=0 RBX] }"
513+
3: in-param "c" loc="{ [0: S=0 RCX] }"
514+
4: in-param "d" loc="{ [0: S=0 RDI] }"
515+
5: in-param "e" loc="{ [0: S=0 RSI] }"
516+
6: in-param "f" loc="{ [0: S=0 R8] }"
517+
7: in-param "g" loc="{ [0: S=0 R9] }"
518+
8: in-param "h" loc="{ [0: S=0 R10] }"
519+
9: in-param "i" loc="{ [0: S=0 R11] }"
520+
10: in-param "j" loc="addr=1000"
521+
11: in-param "k" loc="addr=1008"
522+
12: in-param "l" loc="addr=1010"
523+
13: in-param "m" loc="addr=1018"
524+
14: in-param "n" loc="addr=1020"
525+
15: in-param "o" loc="addr=1028"
526+
16: in-param "p" loc="addr=1030"
527+
17: out-param "sum" at RET[0] loc="{ [0: S=0 RAX] }"
528+
18: out-param "product" at RET[0] loc="{ [0: S=0 RBX] }"`,
529+
"arm64": ``,
530+
}
531+
532+
testCases := []struct {
533+
name string
534+
harness string
535+
binary string
536+
}{
537+
{"optimized", harnessPath, ppath},
538+
}
539+
540+
for _, tc := range testCases {
541+
t.Run(tc.name, func(t *testing.T) {
542+
got := runHarness(t, tc.harness, tc.binary, "main."+fname)
543+
want := expected[runtime.GOARCH]
544+
if got != want {
545+
t.Fatalf("return parameter 'result' has incorrect location in %s build:\ngot:\n%s\nwant:\n%s", tc.name, got, want)
546+
}
547+
})
548+
}
549+
}
550+
551+
func testMultipleReturnStmts(t *testing.T, harnessPath, nooptHarnessPath, ppath, nooppath string) {
552+
fname := "multiReturnStmts"
553+
expected := map[string]string{
554+
"amd64": `1: in-param "i" loc="{ [0: S=0 RAX] }"
555+
2: out-param "~r0" at RET[0] loc="{ [0: S=0 RAX] }"
556+
2: out-param "~r0" at RET[1] loc="{ [0: S=0 RAX] }"`,
557+
"arm64": ``,
558+
}
559+
560+
// Test only optimized builds (non-optimized results are passed on the stack)
561+
testCases := []struct {
562+
name string
563+
harness string
564+
binary string
565+
}{
566+
{"optimized", harnessPath, ppath},
567+
}
568+
569+
for _, tc := range testCases {
570+
t.Run(tc.name, func(t *testing.T) {
571+
got := runHarness(t, tc.harness, tc.binary, "main."+fname)
572+
want := expected[runtime.GOARCH]
573+
if got != want {
574+
t.Fatalf("return parameter 'result' has incorrect location in %s build:\ngot:\n%s\nwant:\n%s", tc.name, got, want)
575+
}
576+
})
577+
}
578+
}
579+
303580
func TestDwarfVariableLocations(t *testing.T) {
304581
testenv.NeedsGo1Point(t, 18)
305582
testenv.MustHaveGoBuild(t)
@@ -354,4 +631,28 @@ func TestDwarfVariableLocations(t *testing.T) {
354631
t.Parallel()
355632
testRuntimeThrow(t, harnessPath, nooptHarnessPath, ppath)
356633
})
634+
t.Run("Issue65405", func(t *testing.T) {
635+
t.Parallel()
636+
testIssue65405(t, harnessPath, ppath)
637+
})
638+
t.Run("ReturnValueRegisters", func(t *testing.T) {
639+
t.Parallel()
640+
testReturnValueRegisters(t, harnessPath, ppath)
641+
})
642+
t.Run("RegisterLivenessNamedRetParam", func(t *testing.T) {
643+
t.Parallel()
644+
testRegisterLivenessNamedRetParam(t, harnessPath, nooptHarnessPath, ppath, nooppath)
645+
})
646+
t.Run("RegisterLivenessUnnamedRetParam", func(t *testing.T) {
647+
t.Parallel()
648+
testLivenessForUnnamedRetParams(t, harnessPath, nooptHarnessPath, ppath, nooppath)
649+
})
650+
t.Run("ManyArgsWithNamedReturns", func(t *testing.T) {
651+
t.Parallel()
652+
testManyArgsWithNamedReturns(t, harnessPath, nooptHarnessPath, ppath, nooppath)
653+
})
654+
t.Run("multiReturnStmts", func(t *testing.T) {
655+
t.Parallel()
656+
testMultipleReturnStmts(t, harnessPath, nooptHarnessPath, ppath, nooppath)
657+
})
357658
}

0 commit comments

Comments
 (0)
X Tutup