]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/cgo/internal/test/callback_windows.go
cmd/internal/link: merge .pdata and .xdata sections from host object files
[gostls13.git] / src / cmd / cgo / internal / test / callback_windows.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 cgotest
6
7 /*
8 #include <windows.h>
9 USHORT backtrace(ULONG FramesToCapture, PVOID *BackTrace) {
10 #ifdef _AMD64_
11         CONTEXT context;
12         RtlCaptureContext(&context);
13         ULONG64 ControlPc;
14         ControlPc = context.Rip;
15         int i;
16         for (i = 0; i < FramesToCapture; i++) {
17                 PRUNTIME_FUNCTION FunctionEntry;
18                 ULONG64 ImageBase;
19                 VOID *HandlerData;
20                 ULONG64 EstablisherFrame;
21
22                 FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);
23
24                 if (!FunctionEntry) {
25                         // For simplicity, don't unwind leaf entries, which are not used in this test.
26                         break;
27                 } else {
28                         RtlVirtualUnwind(0, ImageBase, ControlPc, FunctionEntry, &context, &HandlerData, &EstablisherFrame, NULL);
29                 }
30
31                 ControlPc = context.Rip;
32         // Check if we left the user range.
33                 if (ControlPc < 0x10000) {
34                         break;
35                 }
36
37                 BackTrace[i] = (PVOID)(ControlPc);
38         }
39         return i;
40 #else
41         return 0;
42 #endif
43 }
44 */
45 import "C"
46
47 import (
48         "internal/testenv"
49         "reflect"
50         "runtime"
51         "strings"
52         "testing"
53         "unsafe"
54 )
55
56 // Test that the stack can be unwound through a call out and call back
57 // into Go.
58 func testCallbackCallersSEH(t *testing.T) {
59         testenv.SkipIfOptimizationOff(t) // This test requires inlining.
60         if runtime.Compiler != "gc" {
61                 // The exact function names are not going to be the same.
62                 t.Skip("skipping for non-gc toolchain")
63         }
64         if runtime.GOARCH != "amd64" {
65                 // TODO: support SEH on other architectures.
66                 t.Skip("skipping on non-amd64")
67         }
68         const cgoexpPrefix = "_cgoexp_"
69         want := []string{
70                 "runtime.asmcgocall_landingpad",
71                 "runtime.asmcgocall",
72                 "runtime.cgocall",
73                 "test._Cfunc_backtrace",
74                 "test.testCallbackCallersSEH.func1.1",
75                 "test.testCallbackCallersSEH.func1",
76                 "test.goCallback",
77                 cgoexpPrefix + "goCallback",
78                 "runtime.cgocallbackg1",
79                 "runtime.cgocallbackg",
80                 "runtime.cgocallbackg",
81                 "runtime.cgocallback",
82                 "crosscall2",
83                 "runtime.asmcgocall_landingpad",
84                 "runtime.asmcgocall",
85                 "runtime.cgocall",
86                 "test._Cfunc_callback",
87                 "test.nestedCall.func1",
88                 "test.nestedCall",
89                 "test.testCallbackCallersSEH",
90                 "test.TestCallbackCallersSEH",
91                 "testing.tRunner",
92                 "testing.(*T).Run.gowrap1",
93                 "runtime.goexit",
94         }
95         pc := make([]uintptr, 100)
96         n := 0
97         nestedCall(func() {
98                 n = int(C.backtrace(C.DWORD(len(pc)), (*C.PVOID)(unsafe.Pointer(&pc[0]))))
99         })
100         got := make([]string, 0, n)
101         for i := 0; i < n; i++ {
102                 f := runtime.FuncForPC(pc[i] - 1)
103                 if f == nil {
104                         continue
105                 }
106                 fname := f.Name()
107                 switch fname {
108                 case "goCallback", "callback":
109                         // TODO(qmuntal): investigate why these functions don't appear
110                         // when using the external linker.
111                         continue
112                 }
113                 // Skip cgo-generated functions, the runtime might not know about them,
114                 // depending on the link mode.
115                 if strings.HasPrefix(fname, "_cgo_") {
116                         continue
117                 }
118                 // Remove the cgo-generated random prefix.
119                 if strings.HasPrefix(fname, cgoexpPrefix) {
120                         idx := strings.Index(fname[len(cgoexpPrefix):], "_")
121                         if idx >= 0 {
122                                 fname = cgoexpPrefix + fname[len(cgoexpPrefix)+idx+1:]
123                         }
124                 }
125                 // In module mode, this package has a fully-qualified import path.
126                 // Remove it if present.
127                 fname = strings.TrimPrefix(fname, "cmd/cgo/internal/")
128                 got = append(got, fname)
129         }
130         if !reflect.DeepEqual(want, got) {
131                 t.Errorf("incorrect backtrace:\nwant:\t%v\ngot:\t%v", want, got)
132         }
133 }