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  	"internal/stringslite"
    10  	"runtime/internal/sys"
    11  )
    12  
    13  func XTestInlineUnwinder(t TestingT) {
    14  	if TestenvOptimizationOff() {
    15  		t.Skip("skipping test with inlining optimizations disabled")
    16  	}
    17  
    18  	pc1 := abi.FuncPCABIInternal(tiuTest)
    19  	f := findfunc(pc1)
    20  	if !f.valid() {
    21  		t.Fatalf("failed to resolve tiuTest at PC %#x", pc1)
    22  	}
    23  
    24  	want := map[string]int{
    25  		"tiuInlined1:3 tiuTest:10":               0,
    26  		"tiuInlined1:3 tiuInlined2:6 tiuTest:11": 0,
    27  		"tiuInlined2:7 tiuTest:11":               0,
    28  		"tiuTest:12":                             0,
    29  	}
    30  	wantStart := map[string]int{
    31  		"tiuInlined1": 2,
    32  		"tiuInlined2": 5,
    33  		"tiuTest":     9,
    34  	}
    35  
    36  	// Iterate over the PCs in tiuTest and walk the inline stack for each.
    37  	prevStack := "x"
    38  	for pc := pc1; pc < pc1+1024 && findfunc(pc) == f; pc += sys.PCQuantum {
    39  		stack := ""
    40  		u, uf := newInlineUnwinder(f, pc)
    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 !stringslite.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 stringslite.HasPrefix(name, namePrefix) {
    63  				name = name[len(namePrefix):]
    64  			}
    65  			if !stringslite.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
   123  

View as plain text