aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/testdata/testprogcgo/tracebackctxt.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2016-04-27 14:18:29 -0700
committerIan Lance Taylor <iant@golang.org>2016-04-29 22:07:36 +0000
commit5f9a870bf1bf461ca3609502608b12cc4aab189a (patch)
tree8acea9b2b421e8a188b27872a00c935f3f8776c3 /src/runtime/testdata/testprogcgo/tracebackctxt.go
parentc717675c35cb436bdab62091a6288843aa1c863c (diff)
downloadgo-5f9a870bf1bf461ca3609502608b12cc4aab189a.tar.gz
go-5f9a870bf1bf461ca3609502608b12cc4aab189a.zip
cmd/cgo, runtime, runtime/cgo: use cgo context function
Add support for the context function set by runtime.SetCgoTraceback. The context function was added in CL 17761, without support. This CL is the support. This CL has not been tested for real C code, as a working context function for C code requires unwind support that does not seem to exist. I wanted to get the CL out before the freeze. I apologize for the length of this CL. It's mostly plumbing, but unfortunately the plumbing is processor-specific. Change-Id: I8ce11a0de9b3dafcc29efd2649d776e93bff0e90 Reviewed-on: https://go-review.googlesource.com/22508 Reviewed-by: Austin Clements <austin@google.com> Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/runtime/testdata/testprogcgo/tracebackctxt.go')
-rw-r--r--src/runtime/testdata/testprogcgo/tracebackctxt.go191
1 files changed, 191 insertions, 0 deletions
diff --git a/src/runtime/testdata/testprogcgo/tracebackctxt.go b/src/runtime/testdata/testprogcgo/tracebackctxt.go
new file mode 100644
index 0000000000..4b2e486304
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/tracebackctxt.go
@@ -0,0 +1,191 @@
+// Copyright 2016 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.
+
+// The __attribute__((weak)) used below doesn't seem to work on Windows.
+
+// +build !windows
+
+package main
+
+// Test the context argument to SetCgoTraceback.
+// Use fake context, traceback, and symbolizer functions.
+
+/*
+#include <stdlib.h>
+#include <stdint.h>
+
+// Use weak declarations so that we can define functions here even
+// though we use //export in the Go code.
+extern void tcContext(void*) __attribute__((weak));
+extern void tcTraceback(void*) __attribute__((weak));
+extern void tcSymbolizer(void*) __attribute__((weak));
+
+extern void G1(void);
+extern void G2(void);
+
+static void C1() {
+ G1();
+}
+
+static void C2() {
+ G2();
+}
+
+struct cgoContextArg {
+ uintptr_t context;
+};
+
+struct cgoTracebackArg {
+ uintptr_t context;
+ uintptr_t* buf;
+ uintptr_t max;
+};
+
+struct cgoSymbolizerArg {
+ uintptr_t pc;
+ const char* file;
+ uintptr_t lineno;
+ const char* func;
+ uintptr_t entry;
+ uintptr_t more;
+ uintptr_t data;
+};
+
+// Global so that there is only one, weak so that //export works.
+// Uses atomic adds and subtracts to catch the possibility of
+// erroneous calls from multiple threads; that should be impossible in
+// this test case, but we check just in case.
+int contextCount __attribute__((weak));
+
+static int getContextCount() {
+ return __sync_add_and_fetch(&contextCount, 0);
+}
+
+void tcContext(void* parg) {
+ struct cgoContextArg* arg = (struct cgoContextArg*)(parg);
+ if (arg->context == 0) {
+ arg->context = __sync_add_and_fetch(&contextCount, 1);
+ } else {
+ if (arg->context != __sync_add_and_fetch(&contextCount, 0)) {
+ abort();
+ }
+ __sync_sub_and_fetch(&contextCount, 1);
+ }
+}
+
+void tcTraceback(void* parg) {
+ int base, i;
+ struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg);
+ if (arg->context == 0) {
+ // This shouldn't happen in this program.
+ abort();
+ }
+ // Return a variable number of PC values.
+ base = arg->context << 8;
+ for (i = 0; i < arg->context; i++) {
+ if (i < arg->max) {
+ arg->buf[i] = base + i;
+ }
+ }
+}
+
+void tcSymbolizer(void *parg) {
+ struct cgoSymbolizerArg* arg = (struct cgoSymbolizerArg*)(parg);
+ if (arg->pc == 0) {
+ return;
+ }
+ // Report two lines per PC returned by traceback, to test more handling.
+ arg->more = arg->file == NULL;
+ arg->file = "tracebackctxt.go";
+ arg->func = "cFunction";
+ arg->lineno = arg->pc + (arg->more << 16);
+}
+*/
+import "C"
+
+import (
+ "fmt"
+ "runtime"
+ "unsafe"
+)
+
+func init() {
+ register("TracebackContext", TracebackContext)
+}
+
+var tracebackOK bool
+
+func TracebackContext() {
+ runtime.SetCgoTraceback(0, unsafe.Pointer(C.tcTraceback), unsafe.Pointer(C.tcContext), unsafe.Pointer(C.tcSymbolizer))
+ C.C1()
+ if got := C.getContextCount(); got != 0 {
+ fmt.Printf("at end contextCount == %d, expected 0\n", got)
+ tracebackOK = false
+ }
+ if tracebackOK {
+ fmt.Println("OK")
+ }
+}
+
+//export G1
+func G1() {
+ C.C2()
+}
+
+//export G2
+func G2() {
+ pc := make([]uintptr, 32)
+ n := runtime.Callers(0, pc)
+ cf := runtime.CallersFrames(pc[:n])
+ var frames []runtime.Frame
+ for {
+ frame, more := cf.Next()
+ frames = append(frames, frame)
+ if !more {
+ break
+ }
+ }
+
+ want := []struct {
+ function string
+ line int
+ }{
+ {"main.G2", 0},
+ {"cFunction", 0x10200},
+ {"cFunction", 0x200},
+ {"cFunction", 0x10201},
+ {"cFunction", 0x201},
+ {"main.G1", 0},
+ {"cFunction", 0x10100},
+ {"cFunction", 0x100},
+ {"main.TracebackContext", 0},
+ }
+
+ ok := true
+ i := 0
+wantLoop:
+ for _, w := range want {
+ for ; i < len(frames); i++ {
+ if w.function == frames[i].Function {
+ if w.line != 0 && w.line != frames[i].Line {
+ fmt.Printf("found function %s at wrong line %#x (expected %#x)\n", w.function, frames[i].Line, w.line)
+ ok = false
+ }
+ i++
+ continue wantLoop
+ }
+ }
+ fmt.Printf("did not find function %s in\n", w.function)
+ for _, f := range frames {
+ fmt.Println(f)
+ }
+ ok = false
+ break
+ }
+ tracebackOK = ok
+ if got := C.getContextCount(); got != 2 {
+ fmt.Printf("at bottom contextCount == %d, expected 2\n", got)
+ tracebackOK = false
+ }
+}