Source file src/runtime/symtabinl_test.go

     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  	for pc := pc1; pc < pc1+1024 && findfunc(pc) == f; pc += sys.PCQuantum {
    38  		stack := ""
    39  		u, uf := newInlineUnwinder(f, pc)
    40  		if file, _ := u.fileLine(uf); file == "?" {
    41  			// We're probably in the trailing function padding, where findfunc
    42  			// still returns f but there's no symbolic information. Just keep
    43  			// going until we definitely hit the end. If we see a "?" in the
    44  			// middle of unwinding, that's a real problem.
    45  			//
    46  			// TODO: If we ever have function end information, use that to make
    47  			// this robust.
    48  			continue
    49  		}
    50  		for ; uf.valid(); uf = u.next(uf) {
    51  			file, line := u.fileLine(uf)
    52  			const wantFile = "symtabinl_test.go"
    53  			if !hasSuffix(file, wantFile) {
    54  				t.Errorf("tiuTest+%#x: want file ...%s, got %s", pc-pc1, wantFile, file)
    55  			}
    56  
    57  			sf := u.srcFunc(uf)
    58  
    59  			name := sf.name()
    60  			const namePrefix = "runtime."
    61  			if hasPrefix(name, namePrefix) {
    62  				name = name[len(namePrefix):]
    63  			}
    64  			if !hasPrefix(name, "tiu") {
    65  				t.Errorf("tiuTest+%#x: unexpected function %s", pc-pc1, name)
    66  			}
    67  
    68  			start := int(sf.startLine) - tiuStart
    69  			if start != wantStart[name] {
    70  				t.Errorf("tiuTest+%#x: want startLine %d, got %d", pc-pc1, wantStart[name], start)
    71  			}
    72  			if sf.funcID != abi.FuncIDNormal {
    73  				t.Errorf("tiuTest+%#x: bad funcID %v", pc-pc1, sf.funcID)
    74  			}
    75  
    76  			if len(stack) > 0 {
    77  				stack += " "
    78  			}
    79  			stack += FmtSprintf("%s:%d", name, line-tiuStart)
    80  		}
    81  
    82  		if stack != prevStack {
    83  			prevStack = stack
    84  
    85  			t.Logf("tiuTest+%#x: %s", pc-pc1, stack)
    86  
    87  			if _, ok := want[stack]; ok {
    88  				want[stack]++
    89  			}
    90  		}
    91  	}
    92  
    93  	// Check that we got all the stacks we wanted.
    94  	for stack, count := range want {
    95  		if count == 0 {
    96  			t.Errorf("missing stack %s", stack)
    97  		}
    98  	}
    99  }
   100  
   101  func lineNumber() int {
   102  	_, _, line, _ := Caller(1)
   103  	return line // return 0 for error
   104  }
   105  
   106  // Below here is the test data for XTestInlineUnwinder
   107  
   108  var tiuStart = lineNumber() // +0
   109  var tiu1, tiu2, tiu3 int    // +1
   110  func tiuInlined1() { // +2
   111  	tiu1++ // +3
   112  } // +4
   113  func tiuInlined2() { // +5
   114  	tiuInlined1() // +6
   115  	tiu2++        // +7
   116  } // +8
   117  func tiuTest() { // +9
   118  	tiuInlined1() // +10
   119  	tiuInlined2() // +11
   120  	tiu3++        // +12
   121  } // +13
   122  

View as plain text