blob: ab58c053805e24dc5a29852a5fc6244cfc1960c6 [file] [log] [blame]
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
import (
"internal/abi"
"internal/runtime/sys"
"internal/stringslite"
)
func XTestInlineUnwinder(t TestingT) {
if TestenvOptimizationOff() {
t.Skip("skipping test with inlining optimizations disabled")
}
pc1 := abi.FuncPCABIInternal(tiuTest)
f := findfunc(pc1)
if !f.valid() {
t.Fatalf("failed to resolve tiuTest at PC %#x", pc1)
}
want := map[string]int{
"tiuInlined1:3 tiuTest:10": 0,
"tiuInlined1:3 tiuInlined2:6 tiuTest:11": 0,
"tiuInlined2:7 tiuTest:11": 0,
"tiuTest:12": 0,
}
wantStart := map[string]int{
"tiuInlined1": 2,
"tiuInlined2": 5,
"tiuTest": 9,
}
// Iterate over the PCs in tiuTest and walk the inline stack for each.
prevStack := "x"
for pc := pc1; pc < pc1+1024 && findfunc(pc) == f; pc += sys.PCQuantum {
stack := ""
u, uf := newInlineUnwinder(f, pc)
if file, _ := u.fileLine(uf); file == "?" {
// We're probably in the trailing function padding, where findfunc
// still returns f but there's no symbolic information. Just keep
// going until we definitely hit the end. If we see a "?" in the
// middle of unwinding, that's a real problem.
//
// TODO: If we ever have function end information, use that to make
// this robust.
continue
}
for ; uf.valid(); uf = u.next(uf) {
file, line := u.fileLine(uf)
const wantFile = "symtabinl_test.go"
if !stringslite.HasSuffix(file, wantFile) {
t.Errorf("tiuTest+%#x: want file ...%s, got %s", pc-pc1, wantFile, file)
}
sf := u.srcFunc(uf)
name := sf.name()
const namePrefix = "runtime."
if stringslite.HasPrefix(name, namePrefix) {
name = name[len(namePrefix):]
}
if !stringslite.HasPrefix(name, "tiu") {
t.Errorf("tiuTest+%#x: unexpected function %s", pc-pc1, name)
}
start := int(sf.startLine) - tiuStart
if start != wantStart[name] {
t.Errorf("tiuTest+%#x: want startLine %d, got %d", pc-pc1, wantStart[name], start)
}
if sf.funcID != abi.FuncIDNormal {
t.Errorf("tiuTest+%#x: bad funcID %v", pc-pc1, sf.funcID)
}
if len(stack) > 0 {
stack += " "
}
stack += FmtSprintf("%s:%d", name, line-tiuStart)
}
if stack != prevStack {
prevStack = stack
t.Logf("tiuTest+%#x: %s", pc-pc1, stack)
if _, ok := want[stack]; ok {
want[stack]++
}
}
}
// Check that we got all the stacks we wanted.
for stack, count := range want {
if count == 0 {
t.Errorf("missing stack %s", stack)
}
}
}
func lineNumber() int {
_, _, line, _ := Caller(1)
return line // return 0 for error
}
// Below here is the test data for XTestInlineUnwinder
var tiuStart = lineNumber() // +0
var tiu2, tiu3 int // +1
func tiuInlined1(i int) { // +2
tiu1[i]++ // +3
} // +4
func tiuInlined2() { // +5
tiuInlined1(1) // +6
tiu2++ // +7
} // +8
func tiuTest() { // +9
tiuInlined1(0) // +10
tiuInlined2() // +11
tiu3++ // +12
} // +13
var tiu1 [2]int // +14