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.
9 USHORT backtrace(ULONG FramesToCapture, PVOID *BackTrace) {
12 RtlCaptureContext(&context);
14 ControlPc = context.Rip;
16 for (i = 0; i < FramesToCapture; i++) {
17 PRUNTIME_FUNCTION FunctionEntry;
20 ULONG64 EstablisherFrame;
22 FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);
25 // For simplicity, don't unwind leaf entries, which are not used in this test.
28 RtlVirtualUnwind(0, ImageBase, ControlPc, FunctionEntry, &context, &HandlerData, &EstablisherFrame, NULL);
31 ControlPc = context.Rip;
32 // Check if we left the user range.
33 if (ControlPc < 0x10000) {
37 BackTrace[i] = (PVOID)(ControlPc);
56 // Test that the stack can be unwound through a call out and call back
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")
64 if runtime.GOARCH != "amd64" {
65 // TODO: support SEH on other architectures.
66 t.Skip("skipping on non-amd64")
68 const cgoexpPrefix = "_cgoexp_"
70 "runtime.asmcgocall_landingpad",
73 "test._Cfunc_backtrace",
74 "test.testCallbackCallersSEH.func1.1",
75 "test.testCallbackCallersSEH.func1",
77 cgoexpPrefix + "goCallback",
78 "runtime.cgocallbackg1",
79 "runtime.cgocallbackg",
80 "runtime.cgocallbackg",
81 "runtime.cgocallback",
83 "runtime.asmcgocall_landingpad",
86 "test._Cfunc_callback",
87 "test.nestedCall.func1",
89 "test.testCallbackCallersSEH",
90 "test.TestCallbackCallersSEH",
92 "testing.(*T).Run.gowrap1",
95 pc := make([]uintptr, 100)
98 n = int(C.backtrace(C.DWORD(len(pc)), (*C.PVOID)(unsafe.Pointer(&pc[0]))))
100 got := make([]string, 0, n)
101 for i := 0; i < n; i++ {
102 f := runtime.FuncForPC(pc[i] - 1)
108 case "goCallback", "callback":
109 // TODO(qmuntal): investigate why these functions don't appear
110 // when using the external linker.
113 // Skip cgo-generated functions, the runtime might not know about them,
114 // depending on the link mode.
115 if strings.HasPrefix(fname, "_cgo_") {
118 // Remove the cgo-generated random prefix.
119 if strings.HasPrefix(fname, cgoexpPrefix) {
120 idx := strings.Index(fname[len(cgoexpPrefix):], "_")
122 fname = cgoexpPrefix + fname[len(cgoexpPrefix)+idx+1:]
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)
130 if !reflect.DeepEqual(want, got) {
131 t.Errorf("incorrect backtrace:\nwant:\t%v\ngot:\t%v", want, got)