github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/runtime/symtabinl_test.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package runtime 6 7 import ( 8 "internal/abi" 9 "runtime/internal/sys" 10 ) 11 12 func XTestInlineUnwinder(t TestingT) { 13 if TestenvOptimizationOff() { 14 t.Skip("skipping test with inlining optimizations disabled") 15 } 16 17 pc1 := abi.FuncPCABIInternal(tiuTest) 18 f := findfunc(pc1) 19 if !f.valid() { 20 t.Fatalf("failed to resolve tiuTest at PC %#x", pc1) 21 } 22 23 want := map[string]int{ 24 "tiuInlined1:3 tiuTest:10": 0, 25 "tiuInlined1:3 tiuInlined2:6 tiuTest:11": 0, 26 "tiuInlined2:7 tiuTest:11": 0, 27 "tiuTest:12": 0, 28 } 29 wantStart := map[string]int{ 30 "tiuInlined1": 2, 31 "tiuInlined2": 5, 32 "tiuTest": 9, 33 } 34 35 // Iterate over the PCs in tiuTest and walk the inline stack for each. 36 prevStack := "x" 37 var cache pcvalueCache 38 for pc := pc1; pc < pc1+1024 && findfunc(pc) == f; pc += sys.PCQuantum { 39 stack := "" 40 u, uf := newInlineUnwinder(f, pc, &cache) 41 if file, _ := u.fileLine(uf); file == "?" { 42 // We're probably in the trailing function padding, where findfunc 43 // still returns f but there's no symbolic information. Just keep 44 // going until we definitely hit the end. If we see a "?" in the 45 // middle of unwinding, that's a real problem. 46 // 47 // TODO: If we ever have function end information, use that to make 48 // this robust. 49 continue 50 } 51 for ; uf.valid(); uf = u.next(uf) { 52 file, line := u.fileLine(uf) 53 const wantFile = "symtabinl_test.go" 54 if !hasSuffix(file, wantFile) { 55 t.Errorf("tiuTest+%#x: want file ...%s, got %s", pc-pc1, wantFile, file) 56 } 57 58 sf := u.srcFunc(uf) 59 60 name := sf.name() 61 const namePrefix = "runtime." 62 if hasPrefix(name, namePrefix) { 63 name = name[len(namePrefix):] 64 } 65 if !hasPrefix(name, "tiu") { 66 t.Errorf("tiuTest+%#x: unexpected function %s", pc-pc1, name) 67 } 68 69 start := int(sf.startLine) - tiuStart 70 if start != wantStart[name] { 71 t.Errorf("tiuTest+%#x: want startLine %d, got %d", pc-pc1, wantStart[name], start) 72 } 73 if sf.funcID != abi.FuncIDNormal { 74 t.Errorf("tiuTest+%#x: bad funcID %v", pc-pc1, sf.funcID) 75 } 76 77 if len(stack) > 0 { 78 stack += " " 79 } 80 stack += FmtSprintf("%s:%d", name, line-tiuStart) 81 } 82 83 if stack != prevStack { 84 prevStack = stack 85 86 t.Logf("tiuTest+%#x: %s", pc-pc1, stack) 87 88 if _, ok := want[stack]; ok { 89 want[stack]++ 90 } 91 } 92 } 93 94 // Check that we got all the stacks we wanted. 95 for stack, count := range want { 96 if count == 0 { 97 t.Errorf("missing stack %s", stack) 98 } 99 } 100 } 101 102 func lineNumber() int { 103 _, _, line, _ := Caller(1) 104 return line // return 0 for error 105 } 106 107 // Below here is the test data for XTestInlineUnwinder 108 109 var tiuStart = lineNumber() // +0 110 var tiu1, tiu2, tiu3 int // +1 111 func tiuInlined1() { // +2 112 tiu1++ // +3 113 } // +4 114 func tiuInlined2() { // +5 115 tiuInlined1() // +6 116 tiu2++ // +7 117 } // +8 118 func tiuTest() { // +9 119 tiuInlined1() // +10 120 tiuInlined2() // +11 121 tiu3++ // +12 122 } // +13