mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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>
This commit is contained in:
parent
c717675c35
commit
5f9a870bf1
27 changed files with 714 additions and 227 deletions
|
|
@ -511,7 +511,6 @@ file compiled by gcc, the file x.cgo2.c:
|
||||||
void
|
void
|
||||||
_cgo_be59f0f25121_Cfunc_puts(void *v)
|
_cgo_be59f0f25121_Cfunc_puts(void *v)
|
||||||
{
|
{
|
||||||
_cgo_wait_runtime_init_done();
|
|
||||||
struct {
|
struct {
|
||||||
char* p0;
|
char* p0;
|
||||||
int r;
|
int r;
|
||||||
|
|
@ -520,8 +519,7 @@ file compiled by gcc, the file x.cgo2.c:
|
||||||
a->r = puts((void*)a->p0);
|
a->r = puts((void*)a->p0);
|
||||||
}
|
}
|
||||||
|
|
||||||
It waits for Go runtime to be initialized (required for shared libraries),
|
It extracts the arguments from the pointer to _Cfunc_puts's argument
|
||||||
extracts the arguments from the pointer to _Cfunc_puts's argument
|
|
||||||
frame, invokes the system C function (in this case, puts), stores the
|
frame, invokes the system C function (in this case, puts), stores the
|
||||||
result in the frame, and returns.
|
result in the frame, and returns.
|
||||||
|
|
||||||
|
|
@ -539,8 +537,8 @@ linkage to the desired libraries. The main function is provided by
|
||||||
_cgo_main.c:
|
_cgo_main.c:
|
||||||
|
|
||||||
int main() { return 0; }
|
int main() { return 0; }
|
||||||
void crosscall2(void(*fn)(void*, int), void *a, int c) { }
|
void crosscall2(void(*fn)(void*, int, uintptr_t), void *a, int c, uintptr_t ctxt) { }
|
||||||
void _cgo_wait_runtime_init_done() { }
|
uintptr_t _cgo_wait_runtime_init_done() { }
|
||||||
void _cgo_allocate(void *a, int c) { }
|
void _cgo_allocate(void *a, int c) { }
|
||||||
void _cgo_panic(void *a, int c) { }
|
void _cgo_panic(void *a, int c) { }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,14 +50,16 @@ func (p *Package) writeDefs() {
|
||||||
// Write C main file for using gcc to resolve imports.
|
// Write C main file for using gcc to resolve imports.
|
||||||
fmt.Fprintf(fm, "int main() { return 0; }\n")
|
fmt.Fprintf(fm, "int main() { return 0; }\n")
|
||||||
if *importRuntimeCgo {
|
if *importRuntimeCgo {
|
||||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
|
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt) { }\n")
|
||||||
fmt.Fprintf(fm, "void _cgo_wait_runtime_init_done() { }\n")
|
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done() { return 0; }\n")
|
||||||
|
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__ ctxt) { }\n")
|
||||||
fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
|
fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
|
||||||
} else {
|
} else {
|
||||||
// If we're not importing runtime/cgo, we *are* runtime/cgo,
|
// If we're not importing runtime/cgo, we *are* runtime/cgo,
|
||||||
// which provides these functions. We just need a prototype.
|
// which provides these functions. We just need a prototype.
|
||||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c);\n")
|
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt);\n")
|
||||||
fmt.Fprintf(fm, "void _cgo_wait_runtime_init_done();\n")
|
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done();\n")
|
||||||
|
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__);\n")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
|
fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
|
||||||
fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
|
fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
|
||||||
|
|
@ -700,8 +702,9 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
|
fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
|
||||||
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n")
|
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n")
|
||||||
|
|
||||||
fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int), void *, int);\n")
|
fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int, __SIZE_TYPE__), void *, int, __SIZE_TYPE__);\n")
|
||||||
fmt.Fprintf(fgcc, "extern void _cgo_wait_runtime_init_done();\n\n")
|
fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done();\n")
|
||||||
|
fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
|
||||||
fmt.Fprintf(fgcc, "%s\n", tsanProlog)
|
fmt.Fprintf(fgcc, "%s\n", tsanProlog)
|
||||||
|
|
||||||
for _, exp := range p.ExpFunc {
|
for _, exp := range p.ExpFunc {
|
||||||
|
|
@ -803,10 +806,10 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
}
|
}
|
||||||
fmt.Fprintf(fgcch, "\nextern %s;\n", s)
|
fmt.Fprintf(fgcch, "\nextern %s;\n", s)
|
||||||
|
|
||||||
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName)
|
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName)
|
||||||
fmt.Fprintf(fgcc, "\n%s\n", s)
|
fmt.Fprintf(fgcc, "\n%s\n", s)
|
||||||
fmt.Fprintf(fgcc, "{\n")
|
fmt.Fprintf(fgcc, "{\n")
|
||||||
fmt.Fprintf(fgcc, "\t_cgo_wait_runtime_init_done();\n")
|
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
|
||||||
fmt.Fprintf(fgcc, "\t%s %v a;\n", ctype, p.packedAttribute())
|
fmt.Fprintf(fgcc, "\t%s %v a;\n", ctype, p.packedAttribute())
|
||||||
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
|
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
|
||||||
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
|
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
|
||||||
|
|
@ -819,8 +822,9 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
|
fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
|
||||||
})
|
})
|
||||||
fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
|
fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
|
||||||
fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d);\n", cPrefix, exp.ExpName, off)
|
fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d, _cgo_ctxt);\n", cPrefix, exp.ExpName, off)
|
||||||
fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
|
fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
|
||||||
|
fmt.Fprintf(fgcc, "\t_cgo_release_context(_cgo_ctxt);\n")
|
||||||
if gccResult != "void" {
|
if gccResult != "void" {
|
||||||
if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
|
if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
|
||||||
fmt.Fprintf(fgcc, "\treturn a.r0;\n")
|
fmt.Fprintf(fgcc, "\treturn a.r0;\n")
|
||||||
|
|
@ -845,10 +849,10 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||||
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
|
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
|
||||||
fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
|
fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
|
||||||
fmt.Fprintf(fgo2, "//go:norace\n") // must not have race detector calls inserted
|
fmt.Fprintf(fgo2, "//go:norace\n") // must not have race detector calls inserted
|
||||||
fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32) {\n", cPrefix, exp.ExpName)
|
fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32, ctxt uintptr) {\n", cPrefix, exp.ExpName)
|
||||||
fmt.Fprintf(fgo2, "\tfn := %s\n", goname)
|
fmt.Fprintf(fgo2, "\tfn := %s\n", goname)
|
||||||
// The indirect here is converting from a Go function pointer to a C function pointer.
|
// The indirect here is converting from a Go function pointer to a C function pointer.
|
||||||
fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n));\n")
|
fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n), ctxt);\n")
|
||||||
fmt.Fprintf(fgo2, "}\n")
|
fmt.Fprintf(fgo2, "}\n")
|
||||||
|
|
||||||
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
|
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
|
||||||
|
|
@ -1337,7 +1341,7 @@ func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
|
||||||
func _cgo_runtime_cmalloc(uintptr) unsafe.Pointer
|
func _cgo_runtime_cmalloc(uintptr) unsafe.Pointer
|
||||||
|
|
||||||
//go:linkname _cgo_runtime_cgocallback runtime.cgocallback
|
//go:linkname _cgo_runtime_cgocallback runtime.cgocallback
|
||||||
func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
|
func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
|
||||||
|
|
||||||
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
|
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
|
||||||
func _cgoCheckPointer(interface{}, ...interface{}) interface{}
|
func _cgoCheckPointer(interface{}, ...interface{}) interface{}
|
||||||
|
|
@ -1580,5 +1584,5 @@ static void GoInit(void) {
|
||||||
runtime_iscgo = 1;
|
runtime_iscgo = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void _cgo_wait_runtime_init_done() __attribute__ ((weak));
|
extern __SIZE_TYPE__ _cgo_wait_runtime_init_done() __attribute__ ((weak));
|
||||||
`
|
`
|
||||||
|
|
|
||||||
|
|
@ -612,23 +612,25 @@ noswitch:
|
||||||
MOVL AX, ret+8(FP)
|
MOVL AX, ret+8(FP)
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
|
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
|
||||||
// Turn the fn into a Go func (by taking its address) and call
|
// Turn the fn into a Go func (by taking its address) and call
|
||||||
// cgocallback_gofunc.
|
// cgocallback_gofunc.
|
||||||
TEXT runtime·cgocallback(SB),NOSPLIT,$12-12
|
TEXT runtime·cgocallback(SB),NOSPLIT,$16-16
|
||||||
LEAL fn+0(FP), AX
|
LEAL fn+0(FP), AX
|
||||||
MOVL AX, 0(SP)
|
MOVL AX, 0(SP)
|
||||||
MOVL frame+4(FP), AX
|
MOVL frame+4(FP), AX
|
||||||
MOVL AX, 4(SP)
|
MOVL AX, 4(SP)
|
||||||
MOVL framesize+8(FP), AX
|
MOVL framesize+8(FP), AX
|
||||||
MOVL AX, 8(SP)
|
MOVL AX, 8(SP)
|
||||||
|
MOVL ctxt+12(FP), AX
|
||||||
|
MOVL AX, 12(SP)
|
||||||
MOVL $runtime·cgocallback_gofunc(SB), AX
|
MOVL $runtime·cgocallback_gofunc(SB), AX
|
||||||
CALL AX
|
CALL AX
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
|
// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
|
||||||
// See cgocall.go for more details.
|
// See cgocall.go for more details.
|
||||||
TEXT ·cgocallback_gofunc(SB),NOSPLIT,$12-12
|
TEXT ·cgocallback_gofunc(SB),NOSPLIT,$12-16
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
||||||
// If g is nil, Go did not create the current thread.
|
// If g is nil, Go did not create the current thread.
|
||||||
|
|
@ -696,17 +698,19 @@ havem:
|
||||||
// so that the traceback will seamlessly trace back into
|
// so that the traceback will seamlessly trace back into
|
||||||
// the earlier calls.
|
// the earlier calls.
|
||||||
//
|
//
|
||||||
// In the new goroutine, 0(SP) holds the saved oldm (DX) register.
|
// In the new goroutine, 4(SP) holds the saved oldm (DX) register.
|
||||||
// 4(SP) and 8(SP) are unused.
|
// 8(SP) is unused.
|
||||||
MOVL m_curg(BP), SI
|
MOVL m_curg(BP), SI
|
||||||
MOVL SI, g(CX)
|
MOVL SI, g(CX)
|
||||||
MOVL (g_sched+gobuf_sp)(SI), DI // prepare stack as DI
|
MOVL (g_sched+gobuf_sp)(SI), DI // prepare stack as DI
|
||||||
MOVL (g_sched+gobuf_pc)(SI), BP
|
MOVL (g_sched+gobuf_pc)(SI), BP
|
||||||
MOVL BP, -4(DI)
|
MOVL BP, -4(DI)
|
||||||
|
MOVL ctxt+12(FP), CX
|
||||||
LEAL -(4+12)(DI), SP
|
LEAL -(4+12)(DI), SP
|
||||||
MOVL DX, 0(SP)
|
MOVL DX, 4(SP)
|
||||||
|
MOVL CX, 0(SP)
|
||||||
CALL runtime·cgocallbackg(SB)
|
CALL runtime·cgocallbackg(SB)
|
||||||
MOVL 0(SP), DX
|
MOVL 4(SP), DX
|
||||||
|
|
||||||
// Restore g->sched (== m->curg->sched) from saved values.
|
// Restore g->sched (== m->curg->sched) from saved values.
|
||||||
get_tls(CX)
|
get_tls(CX)
|
||||||
|
|
|
||||||
|
|
@ -622,23 +622,25 @@ nosave:
|
||||||
MOVL AX, ret+16(FP)
|
MOVL AX, ret+16(FP)
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
|
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
|
||||||
// Turn the fn into a Go func (by taking its address) and call
|
// Turn the fn into a Go func (by taking its address) and call
|
||||||
// cgocallback_gofunc.
|
// cgocallback_gofunc.
|
||||||
TEXT runtime·cgocallback(SB),NOSPLIT,$24-24
|
TEXT runtime·cgocallback(SB),NOSPLIT,$32-32
|
||||||
LEAQ fn+0(FP), AX
|
LEAQ fn+0(FP), AX
|
||||||
MOVQ AX, 0(SP)
|
MOVQ AX, 0(SP)
|
||||||
MOVQ frame+8(FP), AX
|
MOVQ frame+8(FP), AX
|
||||||
MOVQ AX, 8(SP)
|
MOVQ AX, 8(SP)
|
||||||
MOVQ framesize+16(FP), AX
|
MOVQ framesize+16(FP), AX
|
||||||
MOVQ AX, 16(SP)
|
MOVQ AX, 16(SP)
|
||||||
|
MOVQ ctxt+24(FP), AX
|
||||||
|
MOVQ AX, 24(SP)
|
||||||
MOVQ $runtime·cgocallback_gofunc(SB), AX
|
MOVQ $runtime·cgocallback_gofunc(SB), AX
|
||||||
CALL AX
|
CALL AX
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
|
// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
|
||||||
// See cgocall.go for more details.
|
// See cgocall.go for more details.
|
||||||
TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-24
|
TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-32
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
||||||
// If g is nil, Go did not create the current thread.
|
// If g is nil, Go did not create the current thread.
|
||||||
|
|
@ -706,7 +708,7 @@ havem:
|
||||||
// so that the traceback will seamlessly trace back into
|
// so that the traceback will seamlessly trace back into
|
||||||
// the earlier calls.
|
// the earlier calls.
|
||||||
//
|
//
|
||||||
// In the new goroutine, 0(SP) holds the saved R8.
|
// In the new goroutine, 8(SP) holds the saved R8.
|
||||||
MOVQ m_curg(BX), SI
|
MOVQ m_curg(BX), SI
|
||||||
MOVQ SI, g(CX)
|
MOVQ SI, g(CX)
|
||||||
MOVQ (g_sched+gobuf_sp)(SI), DI // prepare stack as DI
|
MOVQ (g_sched+gobuf_sp)(SI), DI // prepare stack as DI
|
||||||
|
|
@ -714,14 +716,16 @@ havem:
|
||||||
MOVQ BX, -8(DI)
|
MOVQ BX, -8(DI)
|
||||||
// Compute the size of the frame, including return PC and, if
|
// Compute the size of the frame, including return PC and, if
|
||||||
// GOEXPERIMENT=framepointer, the saved based pointer
|
// GOEXPERIMENT=framepointer, the saved based pointer
|
||||||
|
MOVQ ctxt+24(FP), BX
|
||||||
LEAQ fv+0(FP), AX
|
LEAQ fv+0(FP), AX
|
||||||
SUBQ SP, AX
|
SUBQ SP, AX
|
||||||
SUBQ AX, DI
|
SUBQ AX, DI
|
||||||
MOVQ DI, SP
|
MOVQ DI, SP
|
||||||
|
|
||||||
MOVQ R8, 0(SP)
|
MOVQ R8, 8(SP)
|
||||||
|
MOVQ BX, 0(SP)
|
||||||
CALL runtime·cgocallbackg(SB)
|
CALL runtime·cgocallbackg(SB)
|
||||||
MOVQ 0(SP), R8
|
MOVQ 8(SP), R8
|
||||||
|
|
||||||
// Compute the size of the frame again. FP and SP have
|
// Compute the size of the frame again. FP and SP have
|
||||||
// completely different values here than they did above,
|
// completely different values here than they did above,
|
||||||
|
|
|
||||||
|
|
@ -530,23 +530,25 @@ g0:
|
||||||
MOVW R0, ret+8(FP)
|
MOVW R0, ret+8(FP)
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
|
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
|
||||||
// Turn the fn into a Go func (by taking its address) and call
|
// Turn the fn into a Go func (by taking its address) and call
|
||||||
// cgocallback_gofunc.
|
// cgocallback_gofunc.
|
||||||
TEXT runtime·cgocallback(SB),NOSPLIT,$12-12
|
TEXT runtime·cgocallback(SB),NOSPLIT,$16-16
|
||||||
MOVW $fn+0(FP), R0
|
MOVW $fn+0(FP), R0
|
||||||
MOVW R0, 4(R13)
|
MOVW R0, 4(R13)
|
||||||
MOVW frame+4(FP), R0
|
MOVW frame+4(FP), R0
|
||||||
MOVW R0, 8(R13)
|
MOVW R0, 8(R13)
|
||||||
MOVW framesize+8(FP), R0
|
MOVW framesize+8(FP), R0
|
||||||
MOVW R0, 12(R13)
|
MOVW R0, 12(R13)
|
||||||
|
MOVW ctxt+12(FP), R0
|
||||||
|
MOVW R0, 16(R13)
|
||||||
MOVW $runtime·cgocallback_gofunc(SB), R0
|
MOVW $runtime·cgocallback_gofunc(SB), R0
|
||||||
BL (R0)
|
BL (R0)
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// cgocallback_gofunc(void (*fn)(void*), void *frame, uintptr framesize)
|
// cgocallback_gofunc(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
|
||||||
// See cgocall.go for more details.
|
// See cgocall.go for more details.
|
||||||
TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-12
|
TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-16
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
||||||
// Load m and g from thread-local storage.
|
// Load m and g from thread-local storage.
|
||||||
|
|
@ -611,17 +613,20 @@ havem:
|
||||||
// so that the traceback will seamlessly trace back into
|
// so that the traceback will seamlessly trace back into
|
||||||
// the earlier calls.
|
// the earlier calls.
|
||||||
//
|
//
|
||||||
// In the new goroutine, -8(SP) and -4(SP) are unused.
|
// In the new goroutine, -4(SP) is unused (where SP refers to
|
||||||
|
// m->curg's SP while we're setting it up, before we've adjusted it).
|
||||||
MOVW m_curg(R8), R0
|
MOVW m_curg(R8), R0
|
||||||
BL setg<>(SB)
|
BL setg<>(SB)
|
||||||
MOVW (g_sched+gobuf_sp)(g), R4 // prepare stack as R4
|
MOVW (g_sched+gobuf_sp)(g), R4 // prepare stack as R4
|
||||||
MOVW (g_sched+gobuf_pc)(g), R5
|
MOVW (g_sched+gobuf_pc)(g), R5
|
||||||
MOVW R5, -12(R4)
|
MOVW R5, -12(R4)
|
||||||
|
MOVW ctxt+12(FP), R0
|
||||||
|
MOVW R0, -8(R4)
|
||||||
MOVW $-12(R4), R13
|
MOVW $-12(R4), R13
|
||||||
BL runtime·cgocallbackg(SB)
|
BL runtime·cgocallbackg(SB)
|
||||||
|
|
||||||
// Restore g->sched (== m->curg->sched) from saved values.
|
// Restore g->sched (== m->curg->sched) from saved values.
|
||||||
MOVW 0(R13), R5
|
MOVW 4(R13), R5
|
||||||
MOVW R5, (g_sched+gobuf_pc)(g)
|
MOVW R5, (g_sched+gobuf_pc)(g)
|
||||||
MOVW $12(R13), R4
|
MOVW $12(R13), R4
|
||||||
MOVW R4, (g_sched+gobuf_sp)(g)
|
MOVW R4, (g_sched+gobuf_sp)(g)
|
||||||
|
|
|
||||||
|
|
@ -554,23 +554,25 @@ g0:
|
||||||
MOVW R0, ret+16(FP)
|
MOVW R0, ret+16(FP)
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
|
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
|
||||||
// Turn the fn into a Go func (by taking its address) and call
|
// Turn the fn into a Go func (by taking its address) and call
|
||||||
// cgocallback_gofunc.
|
// cgocallback_gofunc.
|
||||||
TEXT runtime·cgocallback(SB),NOSPLIT,$24-24
|
TEXT runtime·cgocallback(SB),NOSPLIT,$40-32
|
||||||
MOVD $fn+0(FP), R0
|
MOVD $fn+0(FP), R0
|
||||||
MOVD R0, 8(RSP)
|
MOVD R0, 8(RSP)
|
||||||
MOVD frame+8(FP), R0
|
MOVD frame+8(FP), R0
|
||||||
MOVD R0, 16(RSP)
|
MOVD R0, 16(RSP)
|
||||||
MOVD framesize+16(FP), R0
|
MOVD framesize+16(FP), R0
|
||||||
MOVD R0, 24(RSP)
|
MOVD R0, 24(RSP)
|
||||||
|
MOVD ctxt+24(FP), R0
|
||||||
|
MOVD R0, 32(RSP)
|
||||||
MOVD $runtime·cgocallback_gofunc(SB), R0
|
MOVD $runtime·cgocallback_gofunc(SB), R0
|
||||||
BL (R0)
|
BL (R0)
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
|
// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
|
||||||
// See cgocall.go for more details.
|
// See cgocall.go for more details.
|
||||||
TEXT ·cgocallback_gofunc(SB),NOSPLIT,$24-24
|
TEXT ·cgocallback_gofunc(SB),NOSPLIT,$24-32
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
||||||
// Load g from thread-local storage.
|
// Load g from thread-local storage.
|
||||||
|
|
@ -640,12 +642,15 @@ havem:
|
||||||
// so that the traceback will seamlessly trace back into
|
// so that the traceback will seamlessly trace back into
|
||||||
// the earlier calls.
|
// the earlier calls.
|
||||||
//
|
//
|
||||||
// In the new goroutine, -16(SP) and -8(SP) are unused.
|
// In the new goroutine, -8(SP) is unused (where SP refers to
|
||||||
|
// m->curg's SP while we're setting it up, before we've adjusted it).
|
||||||
MOVD m_curg(R8), g
|
MOVD m_curg(R8), g
|
||||||
BL runtime·save_g(SB)
|
BL runtime·save_g(SB)
|
||||||
MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4
|
MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4
|
||||||
MOVD (g_sched+gobuf_pc)(g), R5
|
MOVD (g_sched+gobuf_pc)(g), R5
|
||||||
MOVD R5, -(24+8)(R4) // maintain 16-byte SP alignment
|
MOVD R5, -(16+8)(R4)
|
||||||
|
MOVD ctxt+24(FP), R0
|
||||||
|
MOVD R0, -(24+8)(R4) // maintain 16-byte SP alignment
|
||||||
MOVD $-(24+8)(R4), R0
|
MOVD $-(24+8)(R4), R0
|
||||||
MOVD R0, RSP
|
MOVD R0, RSP
|
||||||
BL runtime·cgocallbackg(SB)
|
BL runtime·cgocallbackg(SB)
|
||||||
|
|
|
||||||
|
|
@ -569,22 +569,24 @@ g0:
|
||||||
MOVW R3, ret+16(FP)
|
MOVW R3, ret+16(FP)
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
|
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
|
||||||
// Turn the fn into a Go func (by taking its address) and call
|
// Turn the fn into a Go func (by taking its address) and call
|
||||||
// cgocallback_gofunc.
|
// cgocallback_gofunc.
|
||||||
TEXT runtime·cgocallback(SB),NOSPLIT,$24-24
|
TEXT runtime·cgocallback(SB),NOSPLIT,$32-32
|
||||||
MOVD $fn+0(FP), R3
|
MOVD $fn+0(FP), R3
|
||||||
MOVD R3, FIXED_FRAME+0(R1)
|
MOVD R3, FIXED_FRAME+0(R1)
|
||||||
MOVD frame+8(FP), R3
|
MOVD frame+8(FP), R3
|
||||||
MOVD R3, FIXED_FRAME+8(R1)
|
MOVD R3, FIXED_FRAME+8(R1)
|
||||||
MOVD framesize+16(FP), R3
|
MOVD framesize+16(FP), R3
|
||||||
MOVD R3, FIXED_FRAME+16(R1)
|
MOVD R3, FIXED_FRAME+16(R1)
|
||||||
|
MOVD ctxt+24(FP), R3
|
||||||
|
MOVD R3, FIXED_FRAME+24(R1)
|
||||||
MOVD $runtime·cgocallback_gofunc(SB), R12
|
MOVD $runtime·cgocallback_gofunc(SB), R12
|
||||||
MOVD R12, CTR
|
MOVD R12, CTR
|
||||||
BL (CTR)
|
BL (CTR)
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
|
// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
|
||||||
// See cgocall.go for more details.
|
// See cgocall.go for more details.
|
||||||
TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-24
|
TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-24
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
@ -654,12 +656,15 @@ havem:
|
||||||
// so that the traceback will seamlessly trace back into
|
// so that the traceback will seamlessly trace back into
|
||||||
// the earlier calls.
|
// the earlier calls.
|
||||||
//
|
//
|
||||||
// In the new goroutine, -16(SP) and -8(SP) are unused.
|
// In the new goroutine, -8(SP) is unused (where SP refers to
|
||||||
|
// m->curg's SP while we're setting it up, before we've adjusted it).
|
||||||
MOVD m_curg(R8), g
|
MOVD m_curg(R8), g
|
||||||
BL runtime·save_g(SB)
|
BL runtime·save_g(SB)
|
||||||
MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4
|
MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4
|
||||||
MOVD (g_sched+gobuf_pc)(g), R5
|
MOVD (g_sched+gobuf_pc)(g), R5
|
||||||
MOVD R5, -(FIXED_FRAME+16)(R4)
|
MOVD R5, -(FIXED_FRAME+8)(R4)
|
||||||
|
MOVD ctxt+24(FP), R1
|
||||||
|
MOVD R1, -(FIXED_FRAME+16)(R4)
|
||||||
MOVD $-(FIXED_FRAME+16)(R4), R1
|
MOVD $-(FIXED_FRAME+16)(R4), R1
|
||||||
BL runtime·cgocallbackg(SB)
|
BL runtime·cgocallbackg(SB)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -541,23 +541,25 @@ g0:
|
||||||
MOVW R2, ret+16(FP)
|
MOVW R2, ret+16(FP)
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
|
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
|
||||||
// Turn the fn into a Go func (by taking its address) and call
|
// Turn the fn into a Go func (by taking its address) and call
|
||||||
// cgocallback_gofunc.
|
// cgocallback_gofunc.
|
||||||
TEXT runtime·cgocallback(SB),NOSPLIT,$24-24
|
TEXT runtime·cgocallback(SB),NOSPLIT,$32-32
|
||||||
MOVD $fn+0(FP), R3
|
MOVD $fn+0(FP), R3
|
||||||
MOVD R3, 8(R15)
|
MOVD R3, 8(R15)
|
||||||
MOVD frame+8(FP), R3
|
MOVD frame+8(FP), R3
|
||||||
MOVD R3, 16(R15)
|
MOVD R3, 16(R15)
|
||||||
MOVD framesize+16(FP), R3
|
MOVD framesize+16(FP), R3
|
||||||
MOVD R3, 24(R15)
|
MOVD R3, 24(R15)
|
||||||
|
MOVD ctxt+24(FP), R3
|
||||||
|
MOVD R3, 32(R15)
|
||||||
MOVD $runtime·cgocallback_gofunc(SB), R3
|
MOVD $runtime·cgocallback_gofunc(SB), R3
|
||||||
BL (R3)
|
BL (R3)
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
|
// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
|
||||||
// See cgocall.go for more details.
|
// See cgocall.go for more details.
|
||||||
TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-24
|
TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-32
|
||||||
NO_LOCAL_POINTERS
|
NO_LOCAL_POINTERS
|
||||||
|
|
||||||
// Load m and g from thread-local storage.
|
// Load m and g from thread-local storage.
|
||||||
|
|
@ -622,12 +624,15 @@ havem:
|
||||||
// so that the traceback will seamlessly trace back into
|
// so that the traceback will seamlessly trace back into
|
||||||
// the earlier calls.
|
// the earlier calls.
|
||||||
//
|
//
|
||||||
// In the new goroutine, -16(SP) and -8(SP) are unused.
|
// In the new goroutine, -8(SP) is unused (where SP refers to
|
||||||
|
// m->curg's SP while we're setting it up, before we've adjusted it).
|
||||||
MOVD m_curg(R8), g
|
MOVD m_curg(R8), g
|
||||||
BL runtime·save_g(SB)
|
BL runtime·save_g(SB)
|
||||||
MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4
|
MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4
|
||||||
MOVD (g_sched+gobuf_pc)(g), R5
|
MOVD (g_sched+gobuf_pc)(g), R5
|
||||||
MOVD R5, -24(R4)
|
MOVD R5, -24(R4)
|
||||||
|
MOVD ctxt+24(FP), R5
|
||||||
|
MOVD R5, -16(R4)
|
||||||
MOVD $-24(R4), R15
|
MOVD $-24(R4), R15
|
||||||
BL runtime·cgocallbackg(SB)
|
BL runtime·cgocallbackg(SB)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import "unsafe"
|
||||||
//go:linkname _cgo_sys_thread_create _cgo_sys_thread_create
|
//go:linkname _cgo_sys_thread_create _cgo_sys_thread_create
|
||||||
//go:linkname _cgo_notify_runtime_init_done _cgo_notify_runtime_init_done
|
//go:linkname _cgo_notify_runtime_init_done _cgo_notify_runtime_init_done
|
||||||
//go:linkname _cgo_callers _cgo_callers
|
//go:linkname _cgo_callers _cgo_callers
|
||||||
|
//go:linkname _cgo_set_context_function _cgo_set_context_function
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_cgo_init unsafe.Pointer
|
_cgo_init unsafe.Pointer
|
||||||
|
|
@ -26,6 +27,7 @@ var (
|
||||||
_cgo_sys_thread_create unsafe.Pointer
|
_cgo_sys_thread_create unsafe.Pointer
|
||||||
_cgo_notify_runtime_init_done unsafe.Pointer
|
_cgo_notify_runtime_init_done unsafe.Pointer
|
||||||
_cgo_callers unsafe.Pointer
|
_cgo_callers unsafe.Pointer
|
||||||
|
_cgo_set_context_function unsafe.Pointer
|
||||||
)
|
)
|
||||||
|
|
||||||
// iscgo is set to true by the runtime/cgo package
|
// iscgo is set to true by the runtime/cgo package
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,9 @@
|
||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
/*
|
// Called by C code generated by cmd/cgo.
|
||||||
* void crosscall2(void (*fn)(void*, int32), void*, int32)
|
// func crosscall2(fn func(a unsafe.Pointer, n int32, ctxt uintptr), a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
* Save registers and call fn with two arguments.
|
// Saves C callee-saved registers and calls fn with three arguments.
|
||||||
*/
|
|
||||||
TEXT crosscall2(SB),NOSPLIT,$0
|
TEXT crosscall2(SB),NOSPLIT,$0
|
||||||
PUSHL BP
|
PUSHL BP
|
||||||
MOVL SP, BP
|
MOVL SP, BP
|
||||||
|
|
@ -15,14 +14,16 @@ TEXT crosscall2(SB),NOSPLIT,$0
|
||||||
PUSHL SI
|
PUSHL SI
|
||||||
PUSHL DI
|
PUSHL DI
|
||||||
|
|
||||||
SUBL $8, SP
|
SUBL $12, SP
|
||||||
|
MOVL 20(BP), AX
|
||||||
|
MOVL AX, 8(SP)
|
||||||
MOVL 16(BP), AX
|
MOVL 16(BP), AX
|
||||||
MOVL AX, 4(SP)
|
MOVL AX, 4(SP)
|
||||||
MOVL 12(BP), AX
|
MOVL 12(BP), AX
|
||||||
MOVL AX, 0(SP)
|
MOVL AX, 0(SP)
|
||||||
MOVL 8(BP), AX
|
MOVL 8(BP), AX
|
||||||
CALL AX
|
CALL AX
|
||||||
ADDL $8, SP
|
ADDL $12, SP
|
||||||
|
|
||||||
POPL DI
|
POPL DI
|
||||||
POPL SI
|
POPL SI
|
||||||
|
|
|
||||||
|
|
@ -4,72 +4,73 @@
|
||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
/*
|
// Called by C code generated by cmd/cgo.
|
||||||
* void crosscall2(void (*fn)(void*, int32), void*, int32)
|
// func crosscall2(fn func(a unsafe.Pointer, n int32, ctxt uintptr), a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
* Save registers and call fn with two arguments.
|
// Saves C callee-saved registers and calls fn with three arguments.
|
||||||
*/
|
|
||||||
TEXT crosscall2(SB),NOSPLIT,$0
|
TEXT crosscall2(SB),NOSPLIT,$0
|
||||||
#ifndef GOOS_windows
|
#ifndef GOOS_windows
|
||||||
SUBQ $0x58, SP /* keeps stack pointer 32-byte aligned */
|
SUBQ $0x58, SP /* keeps stack pointer 32-byte aligned */
|
||||||
#else
|
#else
|
||||||
SUBQ $0xf8, SP /* also need to save xmm6 - xmm15 */
|
SUBQ $0x118, SP /* also need to save xmm6 - xmm15 */
|
||||||
#endif
|
#endif
|
||||||
MOVQ BX, 0x10(SP)
|
MOVQ BX, 0x18(SP)
|
||||||
MOVQ BP, 0x18(SP)
|
MOVQ BP, 0x20(SP)
|
||||||
MOVQ R12, 0x20(SP)
|
MOVQ R12, 0x28(SP)
|
||||||
MOVQ R13, 0x28(SP)
|
MOVQ R13, 0x30(SP)
|
||||||
MOVQ R14, 0x30(SP)
|
MOVQ R14, 0x38(SP)
|
||||||
MOVQ R15, 0x38(SP)
|
MOVQ R15, 0x40(SP)
|
||||||
|
|
||||||
#ifdef GOOS_windows
|
#ifdef GOOS_windows
|
||||||
// Win64 save RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15 and XMM6 -- XMM15.
|
// Win64 save RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15 and XMM6 -- XMM15.
|
||||||
MOVQ DI, 0x40(SP)
|
MOVQ DI, 0x48(SP)
|
||||||
MOVQ SI, 0x48(SP)
|
MOVQ SI, 0x50(SP)
|
||||||
MOVUPS X6, 0x50(SP)
|
MOVUPS X6, 0x60(SP)
|
||||||
MOVUPS X7, 0x60(SP)
|
MOVUPS X7, 0x70(SP)
|
||||||
MOVUPS X8, 0x70(SP)
|
MOVUPS X8, 0x80(SP)
|
||||||
MOVUPS X9, 0x80(SP)
|
MOVUPS X9, 0x90(SP)
|
||||||
MOVUPS X10, 0x90(SP)
|
MOVUPS X10, 0xa0(SP)
|
||||||
MOVUPS X11, 0xa0(SP)
|
MOVUPS X11, 0xb0(SP)
|
||||||
MOVUPS X12, 0xb0(SP)
|
MOVUPS X12, 0xc0(SP)
|
||||||
MOVUPS X13, 0xc0(SP)
|
MOVUPS X13, 0xd0(SP)
|
||||||
MOVUPS X14, 0xd0(SP)
|
MOVUPS X14, 0xe0(SP)
|
||||||
MOVUPS X15, 0xe0(SP)
|
MOVUPS X15, 0xf0(SP)
|
||||||
|
|
||||||
MOVQ DX, 0(SP) /* arg */
|
MOVQ DX, 0x0(SP) /* arg */
|
||||||
MOVQ R8, 8(SP) /* argsize (includes padding) */
|
MOVQ R8, 0x8(SP) /* argsize (includes padding) */
|
||||||
|
MOVQ R9, 0x10(SP) /* ctxt */
|
||||||
|
|
||||||
CALL CX /* fn */
|
CALL CX /* fn */
|
||||||
|
|
||||||
MOVQ 0x40(SP), DI
|
MOVQ 0x48(SP), DI
|
||||||
MOVQ 0x48(SP), SI
|
MOVQ 0x50(SP), SI
|
||||||
MOVUPS 0x50(SP), X6
|
MOVUPS 0x60(SP), X6
|
||||||
MOVUPS 0x60(SP), X7
|
MOVUPS 0x70(SP), X7
|
||||||
MOVUPS 0x70(SP), X8
|
MOVUPS 0x80(SP), X8
|
||||||
MOVUPS 0x80(SP), X9
|
MOVUPS 0x90(SP), X9
|
||||||
MOVUPS 0x90(SP), X10
|
MOVUPS 0xa0(SP), X10
|
||||||
MOVUPS 0xa0(SP), X11
|
MOVUPS 0xb0(SP), X11
|
||||||
MOVUPS 0xb0(SP), X12
|
MOVUPS 0xc0(SP), X12
|
||||||
MOVUPS 0xc0(SP), X13
|
MOVUPS 0xd0(SP), X13
|
||||||
MOVUPS 0xd0(SP), X14
|
MOVUPS 0xe0(SP), X14
|
||||||
MOVUPS 0xe0(SP), X15
|
MOVUPS 0xf0(SP), X15
|
||||||
#else
|
#else
|
||||||
MOVQ SI, 0(SP) /* arg */
|
MOVQ SI, 0x0(SP) /* arg */
|
||||||
MOVQ DX, 8(SP) /* argsize (includes padding) */
|
MOVQ DX, 0x8(SP) /* argsize (includes padding) */
|
||||||
|
MOVQ CX, 0x10(SP) /* ctxt */
|
||||||
|
|
||||||
CALL DI /* fn */
|
CALL DI /* fn */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MOVQ 0x10(SP), BX
|
MOVQ 0x18(SP), BX
|
||||||
MOVQ 0x18(SP), BP
|
MOVQ 0x20(SP), BP
|
||||||
MOVQ 0x20(SP), R12
|
MOVQ 0x28(SP), R12
|
||||||
MOVQ 0x28(SP), R13
|
MOVQ 0x30(SP), R13
|
||||||
MOVQ 0x30(SP), R14
|
MOVQ 0x38(SP), R14
|
||||||
MOVQ 0x38(SP), R15
|
MOVQ 0x40(SP), R15
|
||||||
|
|
||||||
#ifndef GOOS_windows
|
#ifndef GOOS_windows
|
||||||
ADDQ $0x58, SP
|
ADDQ $0x58, SP
|
||||||
#else
|
#else
|
||||||
ADDQ $0xf8, SP
|
ADDQ $0x118, SP
|
||||||
#endif
|
#endif
|
||||||
RET
|
RET
|
||||||
|
|
|
||||||
|
|
@ -4,21 +4,20 @@
|
||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
/*
|
// Called by C code generated by cmd/cgo.
|
||||||
* void crosscall2(void (*fn)(void*, int32), void*, int32)
|
// func crosscall2(fn func(a unsafe.Pointer, n int32, ctxt uintptr), a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
* Save registers and call fn with two arguments.
|
// Saves C callee-saved registers and calls fn with three arguments.
|
||||||
*/
|
|
||||||
TEXT crosscall2(SB),NOSPLIT,$-4
|
TEXT crosscall2(SB),NOSPLIT,$-4
|
||||||
/*
|
/*
|
||||||
* We still need to save all callee save register as before, and then
|
* We still need to save all callee save register as before, and then
|
||||||
* push 2 args for fn (R1 and R2).
|
* push 3 args for fn (R1, R2, R3).
|
||||||
* Also note that at procedure entry in gc world, 4(R13) will be the
|
* Also note that at procedure entry in gc world, 4(R13) will be the
|
||||||
* first arg, so we must push another dummy reg (R0) for 0(R13).
|
* first arg, so we must push another dummy reg (R0) for 0(R13).
|
||||||
* Additionally, runtime·load_g will clobber R0, so we need to save R0
|
* Additionally, runtime·load_g will clobber R0, so we need to save R0
|
||||||
* nevertheless.
|
* nevertheless.
|
||||||
*/
|
*/
|
||||||
MOVM.WP [R0, R1, R2, R4, R5, R6, R7, R8, R9, g, R11, R12, R14], (R13)
|
MOVM.WP [R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, g, R11, R12, R14], (R13)
|
||||||
BL runtime·load_g(SB)
|
BL runtime·load_g(SB)
|
||||||
MOVW R15, R14 // R15 is PC.
|
MOVW R15, R14 // R15 is PC.
|
||||||
MOVW 0(R13), R15
|
MOVW 0(R13), R15
|
||||||
MOVM.IAW (R13), [R0, R1, R2, R4, R5, R6, R7, R8, R9, g, R11, R12, R15]
|
MOVM.IAW (R13), [R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, g, R11, R12, R15]
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,13 @@
|
||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
/*
|
// Called by C code generated by cmd/cgo.
|
||||||
* void crosscall2(void (*fn)(void*, int32), void*, int32)
|
// func crosscall2(fn func(a unsafe.Pointer, n int32, ctxt uintptr), a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
* Save registers and call fn with two arguments.
|
// Saves C callee-saved registers and calls fn with three arguments.
|
||||||
*/
|
|
||||||
TEXT crosscall2(SB),NOSPLIT,$-8
|
TEXT crosscall2(SB),NOSPLIT,$-8
|
||||||
/*
|
/*
|
||||||
* We still need to save all callee save register as before, and then
|
* We still need to save all callee save register as before, and then
|
||||||
* push 2 args for fn (R1 and R2).
|
* push 3 args for fn (R1, R2, R3).
|
||||||
* Also note that at procedure entry in gc world, 8(RSP) will be the
|
* Also note that at procedure entry in gc world, 8(RSP) will be the
|
||||||
* first arg.
|
* first arg.
|
||||||
* TODO(minux): use LDP/STP here if it matters.
|
* TODO(minux): use LDP/STP here if it matters.
|
||||||
|
|
@ -19,26 +18,27 @@ TEXT crosscall2(SB),NOSPLIT,$-8
|
||||||
SUB $(8*24), RSP
|
SUB $(8*24), RSP
|
||||||
MOVD R1, (8*1)(RSP)
|
MOVD R1, (8*1)(RSP)
|
||||||
MOVD R2, (8*2)(RSP)
|
MOVD R2, (8*2)(RSP)
|
||||||
MOVD R19, (8*3)(RSP)
|
MOVD R3, (8*3)(RSP)
|
||||||
MOVD R20, (8*4)(RSP)
|
MOVD R19, (8*4)(RSP)
|
||||||
MOVD R21, (8*5)(RSP)
|
MOVD R20, (8*5)(RSP)
|
||||||
MOVD R22, (8*6)(RSP)
|
MOVD R21, (8*6)(RSP)
|
||||||
MOVD R23, (8*7)(RSP)
|
MOVD R22, (8*7)(RSP)
|
||||||
MOVD R24, (8*8)(RSP)
|
MOVD R23, (8*8)(RSP)
|
||||||
MOVD R25, (8*9)(RSP)
|
MOVD R24, (8*9)(RSP)
|
||||||
MOVD R26, (8*10)(RSP)
|
MOVD R25, (8*10)(RSP)
|
||||||
MOVD R27, (8*11)(RSP)
|
MOVD R26, (8*11)(RSP)
|
||||||
MOVD g, (8*12)(RSP)
|
MOVD R27, (8*12)(RSP)
|
||||||
MOVD R29, (8*13)(RSP)
|
MOVD g, (8*13)(RSP)
|
||||||
MOVD R30, (8*14)(RSP)
|
MOVD R29, (8*14)(RSP)
|
||||||
FMOVD F8, (8*15)(RSP)
|
MOVD R30, (8*15)(RSP)
|
||||||
FMOVD F9, (8*16)(RSP)
|
FMOVD F8, (8*16)(RSP)
|
||||||
FMOVD F10, (8*17)(RSP)
|
FMOVD F9, (8*17)(RSP)
|
||||||
FMOVD F11, (8*18)(RSP)
|
FMOVD F10, (8*18)(RSP)
|
||||||
FMOVD F12, (8*19)(RSP)
|
FMOVD F11, (8*19)(RSP)
|
||||||
FMOVD F13, (8*20)(RSP)
|
FMOVD F12, (8*20)(RSP)
|
||||||
FMOVD F14, (8*21)(RSP)
|
FMOVD F13, (8*21)(RSP)
|
||||||
FMOVD F15, (8*22)(RSP)
|
FMOVD F14, (8*22)(RSP)
|
||||||
|
FMOVD F15, (8*23)(RSP)
|
||||||
|
|
||||||
MOVD R0, R19
|
MOVD R0, R19
|
||||||
|
|
||||||
|
|
@ -49,25 +49,26 @@ TEXT crosscall2(SB),NOSPLIT,$-8
|
||||||
|
|
||||||
MOVD (8*1)(RSP), R1
|
MOVD (8*1)(RSP), R1
|
||||||
MOVD (8*2)(RSP), R2
|
MOVD (8*2)(RSP), R2
|
||||||
MOVD (8*3)(RSP), R19
|
MOVD (8*3)(RSP), R3
|
||||||
MOVD (8*4)(RSP), R20
|
MOVD (8*4)(RSP), R19
|
||||||
MOVD (8*5)(RSP), R21
|
MOVD (8*5)(RSP), R20
|
||||||
MOVD (8*6)(RSP), R22
|
MOVD (8*6)(RSP), R21
|
||||||
MOVD (8*7)(RSP), R23
|
MOVD (8*7)(RSP), R22
|
||||||
MOVD (8*8)(RSP), R24
|
MOVD (8*8)(RSP), R23
|
||||||
MOVD (8*9)(RSP), R25
|
MOVD (8*9)(RSP), R24
|
||||||
MOVD (8*10)(RSP), R26
|
MOVD (8*10)(RSP), R25
|
||||||
MOVD (8*11)(RSP), R27
|
MOVD (8*11)(RSP), R26
|
||||||
MOVD (8*12)(RSP), g
|
MOVD (8*12)(RSP), R27
|
||||||
MOVD (8*13)(RSP), R29
|
MOVD (8*13)(RSP), g
|
||||||
MOVD (8*14)(RSP), R30
|
MOVD (8*14)(RSP), R29
|
||||||
FMOVD (8*15)(RSP), F8
|
MOVD (8*15)(RSP), R30
|
||||||
FMOVD (8*16)(RSP), F9
|
FMOVD (8*16)(RSP), F8
|
||||||
FMOVD (8*17)(RSP), F10
|
FMOVD (8*17)(RSP), F9
|
||||||
FMOVD (8*18)(RSP), F11
|
FMOVD (8*18)(RSP), F10
|
||||||
FMOVD (8*19)(RSP), F12
|
FMOVD (8*19)(RSP), F11
|
||||||
FMOVD (8*20)(RSP), F13
|
FMOVD (8*20)(RSP), F12
|
||||||
FMOVD (8*21)(RSP), F14
|
FMOVD (8*21)(RSP), F13
|
||||||
FMOVD (8*22)(RSP), F15
|
FMOVD (8*22)(RSP), F14
|
||||||
|
FMOVD (8*23)(RSP), F15
|
||||||
ADD $(8*24), RSP
|
ADD $(8*24), RSP
|
||||||
RET
|
RET
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,9 @@
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
#include "asm_ppc64x.h"
|
#include "asm_ppc64x.h"
|
||||||
|
|
||||||
/*
|
// Called by C code generated by cmd/cgo.
|
||||||
* void crosscall2(void (*fn)(void*, int32), void*, int32)
|
// func crosscall2(fn func(a unsafe.Pointer, n int32, ctxt uintptr), a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
* Save registers and call fn with two arguments.
|
// Saves C callee-saved registers and calls fn with three arguments.
|
||||||
* crosscall2 obeys the C ABI; fn obeys the Go ABI.
|
|
||||||
*/
|
|
||||||
TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
|
TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
|
||||||
// TODO(austin): ABI v1 (fn is probably a function descriptor)
|
// TODO(austin): ABI v1 (fn is probably a function descriptor)
|
||||||
|
|
||||||
|
|
@ -22,7 +20,7 @@ TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
|
||||||
|
|
||||||
BL saveregs2<>(SB)
|
BL saveregs2<>(SB)
|
||||||
|
|
||||||
MOVDU R1, (-288-2*8-FIXED_FRAME)(R1)
|
MOVDU R1, (-288-3*8-FIXED_FRAME)(R1)
|
||||||
|
|
||||||
// Initialize Go ABI environment
|
// Initialize Go ABI environment
|
||||||
BL runtime·reginit(SB)
|
BL runtime·reginit(SB)
|
||||||
|
|
@ -32,6 +30,7 @@ TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
|
||||||
MOVD R3, CTR
|
MOVD R3, CTR
|
||||||
MOVD R4, FIXED_FRAME+0(R1)
|
MOVD R4, FIXED_FRAME+0(R1)
|
||||||
MOVD R5, FIXED_FRAME+8(R1)
|
MOVD R5, FIXED_FRAME+8(R1)
|
||||||
|
MOVD R6, FIXED_FRAME+16(R1)
|
||||||
BL (CTR)
|
BL (CTR)
|
||||||
|
|
||||||
ADD $(288+2*8+FIXED_FRAME), R1
|
ADD $(288+2*8+FIXED_FRAME), R1
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,9 @@
|
||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
/*
|
// Called by C code generated by cmd/cgo.
|
||||||
* void crosscall2(void (*fn)(void*, int32), void*, int32)
|
// func crosscall2(fn func(a unsafe.Pointer, n int32, ctxt uintptr), a unsafe.Pointer, n int32, ctxt uintptr)
|
||||||
* Save registers and call fn with two arguments.
|
// Saves C callee-saved registers and calls fn with three arguments.
|
||||||
* crosscall2 obeys the C ABI; fn obeys the Go ABI.
|
|
||||||
*/
|
|
||||||
TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
|
TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
|
||||||
// Start with standard C stack frame layout and linkage
|
// Start with standard C stack frame layout and linkage
|
||||||
|
|
||||||
|
|
@ -24,14 +22,15 @@ TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
|
||||||
XOR R0, R0
|
XOR R0, R0
|
||||||
BL runtime·load_g(SB)
|
BL runtime·load_g(SB)
|
||||||
|
|
||||||
// Allocate 24 bytes on the stack
|
// Allocate 32 bytes on the stack
|
||||||
SUB $24, R15
|
SUB $32, R15
|
||||||
|
|
||||||
MOVD R3, 8(R15) // arg1
|
MOVD R3, 8(R15) // arg1
|
||||||
MOVW R4, 16(R15) // arg2
|
MOVW R4, 16(R15) // arg2
|
||||||
BL (R2) // fn(arg1, arg2)
|
MOVD R5, 24(R15) // arg3
|
||||||
|
BL (R2) // fn(arg1, arg2, arg3)
|
||||||
|
|
||||||
ADD $24, R15
|
ADD $32, R15
|
||||||
|
|
||||||
// Restore R6-R15, F0, F2, F4 and F6
|
// Restore R6-R15, F0, F2, F4 and F6
|
||||||
LMG 48(R15), R6, R15
|
LMG 48(R15), R6, R15
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import "unsafe"
|
||||||
|
|
||||||
// cgocallback is defined in runtime
|
// cgocallback is defined in runtime
|
||||||
//go:linkname _runtime_cgocallback runtime.cgocallback
|
//go:linkname _runtime_cgocallback runtime.cgocallback
|
||||||
func _runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
|
func _runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
|
||||||
|
|
||||||
// The declaration of crosscall2 is:
|
// The declaration of crosscall2 is:
|
||||||
// void crosscall2(void (*fn)(void *, int), void *, int);
|
// void crosscall2(void (*fn)(void *, int), void *, int);
|
||||||
|
|
@ -19,6 +19,10 @@ func _runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
|
||||||
// We need to export the symbol crosscall2 in order to support
|
// We need to export the symbol crosscall2 in order to support
|
||||||
// callbacks from shared libraries. This applies regardless of
|
// callbacks from shared libraries. This applies regardless of
|
||||||
// linking mode.
|
// linking mode.
|
||||||
|
//
|
||||||
|
// Compatibility note: crosscall2 actually takes four arguments, but
|
||||||
|
// it works to call it with three arguments when calling _cgo_panic.
|
||||||
|
// That is supported for backward compatibility.
|
||||||
//go:cgo_export_static crosscall2
|
//go:cgo_export_static crosscall2
|
||||||
//go:cgo_export_dynamic crosscall2
|
//go:cgo_export_dynamic crosscall2
|
||||||
|
|
||||||
|
|
@ -39,7 +43,7 @@ var _runtime_cgo_panic_internal byte
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
//go:norace
|
//go:norace
|
||||||
func _cgo_panic(a unsafe.Pointer, n int32) {
|
func _cgo_panic(a unsafe.Pointer, n int32) {
|
||||||
_runtime_cgocallback(unsafe.Pointer(&_runtime_cgo_panic_internal), a, uintptr(n))
|
_runtime_cgocallback(unsafe.Pointer(&_runtime_cgo_panic_internal), a, uintptr(n), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:cgo_import_static x_cgo_init
|
//go:cgo_import_static x_cgo_init
|
||||||
|
|
@ -92,5 +96,13 @@ var _cgo_sys_thread_create = &x_cgo_sys_thread_create
|
||||||
var x_cgo_notify_runtime_init_done byte
|
var x_cgo_notify_runtime_init_done byte
|
||||||
var _cgo_notify_runtime_init_done = &x_cgo_notify_runtime_init_done
|
var _cgo_notify_runtime_init_done = &x_cgo_notify_runtime_init_done
|
||||||
|
|
||||||
|
// Sets the traceback context function. See runtime.SetCgoTraceback.
|
||||||
|
|
||||||
|
//go:cgo_import_static x_cgo_set_context_function
|
||||||
|
//go:linkname x_cgo_set_context_function x_cgo_set_context_function
|
||||||
|
//go:linkname _cgo_set_context_function _cgo_set_context_function
|
||||||
|
var x_cgo_set_context_function byte
|
||||||
|
var _cgo_set_context_function = &x_cgo_set_context_function
|
||||||
|
|
||||||
//go:cgo_export_static _cgo_topofstack
|
//go:cgo_export_static _cgo_topofstack
|
||||||
//go:cgo_export_dynamic _cgo_topofstack
|
//go:cgo_export_dynamic _cgo_topofstack
|
||||||
|
|
|
||||||
27
src/runtime/cgo/gcc_context.c
Normal file
27
src/runtime/cgo/gcc_context.c
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// +build cgo
|
||||||
|
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
|
||||||
|
|
||||||
|
#include "libcgo.h"
|
||||||
|
|
||||||
|
// The context function, used when tracing back C calls into Go.
|
||||||
|
void (*x_cgo_context_function)(struct context_arg*);
|
||||||
|
|
||||||
|
// Sets the context function to call to record the traceback context
|
||||||
|
// when calling a Go function from C code. Called from runtime.SetCgoTraceback.
|
||||||
|
void x_cgo_set_context_function(void (*context)(struct context_arg*)) {
|
||||||
|
x_cgo_context_function = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Releases the cgo traceback context.
|
||||||
|
void _cgo_release_context(uintptr_t ctxt) {
|
||||||
|
if (ctxt != 0 && x_cgo_context_function != nil) {
|
||||||
|
struct context_arg arg;
|
||||||
|
|
||||||
|
arg.Context = ctxt;
|
||||||
|
(*x_cgo_context_function)(&arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h> // strerror
|
#include <string.h> // strerror
|
||||||
|
#include "libcgo.h"
|
||||||
|
|
||||||
static pthread_cond_t runtime_init_cond = PTHREAD_COND_INITIALIZER;
|
static pthread_cond_t runtime_init_cond = PTHREAD_COND_INITIALIZER;
|
||||||
static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
@ -24,13 +25,21 @@ x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
uintptr_t
|
||||||
_cgo_wait_runtime_init_done() {
|
_cgo_wait_runtime_init_done() {
|
||||||
pthread_mutex_lock(&runtime_init_mu);
|
pthread_mutex_lock(&runtime_init_mu);
|
||||||
while (runtime_init_done == 0) {
|
while (runtime_init_done == 0) {
|
||||||
pthread_cond_wait(&runtime_init_cond, &runtime_init_mu);
|
pthread_cond_wait(&runtime_init_cond, &runtime_init_mu);
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&runtime_init_mu);
|
pthread_mutex_unlock(&runtime_init_mu);
|
||||||
|
if (x_cgo_context_function != nil) {
|
||||||
|
struct context_arg arg;
|
||||||
|
|
||||||
|
arg.Context = 0;
|
||||||
|
(*x_cgo_context_function)(&arg);
|
||||||
|
return arg.Context;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "libcgo.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
|
x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
|
||||||
|
|
@ -11,12 +12,20 @@ x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
uintptr_t
|
||||||
_cgo_wait_runtime_init_done() {
|
_cgo_wait_runtime_init_done() {
|
||||||
// TODO(spetrovic): implement this method.
|
// TODO(spetrovic): implement this method.
|
||||||
|
if (x_cgo_context_function != nil) {
|
||||||
|
struct context_arg arg;
|
||||||
|
|
||||||
|
arg.Context = 0;
|
||||||
|
(*x_cgo_context_function)(&arg);
|
||||||
|
return arg.Context;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
x_cgo_notify_runtime_init_done(void* dummy) {
|
x_cgo_notify_runtime_init_done(void* dummy) {
|
||||||
// TODO(spetrovic): implement this method.
|
// TODO(spetrovic): implement this method.
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "libcgo.h"
|
||||||
|
|
||||||
static volatile long runtime_init_once_gate = 0;
|
static volatile long runtime_init_once_gate = 0;
|
||||||
static volatile long runtime_init_once_done = 0;
|
static volatile long runtime_init_once_done = 0;
|
||||||
|
|
||||||
|
|
@ -66,12 +68,20 @@ _cgo_is_runtime_initialized() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
uintptr_t
|
||||||
_cgo_wait_runtime_init_done() {
|
_cgo_wait_runtime_init_done() {
|
||||||
_cgo_maybe_run_preinit();
|
_cgo_maybe_run_preinit();
|
||||||
while (!_cgo_is_runtime_initialized()) {
|
while (!_cgo_is_runtime_initialized()) {
|
||||||
WaitForSingleObject(runtime_init_wait, INFINITE);
|
WaitForSingleObject(runtime_init_wait, INFINITE);
|
||||||
}
|
}
|
||||||
|
if (x_cgo_context_function != nil) {
|
||||||
|
struct context_arg arg;
|
||||||
|
|
||||||
|
arg.Context = 0;
|
||||||
|
(*x_cgo_context_function)(&arg);
|
||||||
|
return arg.Context;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,10 @@ void _cgo_sys_thread_start(ThreadStart *ts);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Waits for the Go runtime to be initialized (OS dependent).
|
* Waits for the Go runtime to be initialized (OS dependent).
|
||||||
|
* If runtime.SetCgoTraceback is used to set a context function,
|
||||||
|
* calls the context function and returns the context value.
|
||||||
*/
|
*/
|
||||||
void _cgo_wait_runtime_init_done();
|
uintptr_t _cgo_wait_runtime_init_done();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call fn in the 6c world.
|
* Call fn in the 6c world.
|
||||||
|
|
@ -84,3 +86,11 @@ void darwin_arm_init_thread_exception_port(void);
|
||||||
* Starts a mach message server processing EXC_BAD_ACCESS.
|
* Starts a mach message server processing EXC_BAD_ACCESS.
|
||||||
*/
|
*/
|
||||||
void darwin_arm_init_mach_exception_handler(void);
|
void darwin_arm_init_mach_exception_handler(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The cgo context function. See runtime.SetCgoTraceback.
|
||||||
|
*/
|
||||||
|
struct context_arg {
|
||||||
|
uintptr_t Context;
|
||||||
|
};
|
||||||
|
extern void (*x_cgo_context_function)(struct context_arg*);
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ func cfree(p unsafe.Pointer) {
|
||||||
|
|
||||||
// Call from C back to Go.
|
// Call from C back to Go.
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func cgocallbackg() {
|
func cgocallbackg(ctxt uintptr) {
|
||||||
gp := getg()
|
gp := getg()
|
||||||
if gp != gp.m.curg {
|
if gp != gp.m.curg {
|
||||||
println("runtime: bad g in cgocallback")
|
println("runtime: bad g in cgocallback")
|
||||||
|
|
@ -184,20 +184,43 @@ func cgocallbackg() {
|
||||||
savedsp := unsafe.Pointer(gp.syscallsp)
|
savedsp := unsafe.Pointer(gp.syscallsp)
|
||||||
savedpc := gp.syscallpc
|
savedpc := gp.syscallpc
|
||||||
exitsyscall(0) // coming out of cgo call
|
exitsyscall(0) // coming out of cgo call
|
||||||
cgocallbackg1()
|
|
||||||
|
cgocallbackg1(ctxt)
|
||||||
|
|
||||||
// going back to cgo call
|
// going back to cgo call
|
||||||
reentersyscall(savedpc, uintptr(savedsp))
|
reentersyscall(savedpc, uintptr(savedsp))
|
||||||
|
|
||||||
gp.m.syscall = syscall
|
gp.m.syscall = syscall
|
||||||
}
|
}
|
||||||
|
|
||||||
func cgocallbackg1() {
|
func cgocallbackg1(ctxt uintptr) {
|
||||||
gp := getg()
|
gp := getg()
|
||||||
if gp.m.needextram {
|
if gp.m.needextram {
|
||||||
gp.m.needextram = false
|
gp.m.needextram = false
|
||||||
systemstack(newextram)
|
systemstack(newextram)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ctxt != 0 {
|
||||||
|
s := append(gp.cgoCtxt, ctxt)
|
||||||
|
|
||||||
|
// Now we need to set gp.cgoCtxt = s, but we could get
|
||||||
|
// a SIGPROF signal while manipulating the slice, and
|
||||||
|
// the SIGPROF handler could pick up gp.cgoCtxt while
|
||||||
|
// tracing up the stack. We need to ensure that the
|
||||||
|
// handler always sees a valid slice, so set the
|
||||||
|
// values in an order such that it always does.
|
||||||
|
p := (*slice)(unsafe.Pointer(&gp.cgoCtxt))
|
||||||
|
atomicstorep(unsafe.Pointer(&p.array), unsafe.Pointer(&s[0]))
|
||||||
|
p.cap = cap(s)
|
||||||
|
p.len = len(s)
|
||||||
|
|
||||||
|
defer func(gp *g) {
|
||||||
|
// Decrease the length of the slice by one, safely.
|
||||||
|
p := (*slice)(unsafe.Pointer(&gp.cgoCtxt))
|
||||||
|
p.len--
|
||||||
|
}(gp)
|
||||||
|
}
|
||||||
|
|
||||||
if gp.m.ncgo == 0 {
|
if gp.m.ncgo == 0 {
|
||||||
// The C call to Go came from a thread not currently running
|
// The C call to Go came from a thread not currently running
|
||||||
// any Go. In the case of -buildmode=c-archive or c-shared,
|
// any Go. In the case of -buildmode=c-archive or c-shared,
|
||||||
|
|
@ -236,13 +259,13 @@ func cgocallbackg1() {
|
||||||
// SP and the stack frame and between the stack frame and the arguments.
|
// SP and the stack frame and between the stack frame and the arguments.
|
||||||
cb = (*args)(unsafe.Pointer(sp + 5*sys.PtrSize))
|
cb = (*args)(unsafe.Pointer(sp + 5*sys.PtrSize))
|
||||||
case "amd64":
|
case "amd64":
|
||||||
// On amd64, stack frame is one word, plus caller PC.
|
// On amd64, stack frame is two words, plus caller PC.
|
||||||
if framepointer_enabled {
|
if framepointer_enabled {
|
||||||
// In this case, there's also saved BP.
|
// In this case, there's also saved BP.
|
||||||
cb = (*args)(unsafe.Pointer(sp + 3*sys.PtrSize))
|
cb = (*args)(unsafe.Pointer(sp + 4*sys.PtrSize))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
cb = (*args)(unsafe.Pointer(sp + 2*sys.PtrSize))
|
cb = (*args)(unsafe.Pointer(sp + 3*sys.PtrSize))
|
||||||
case "386":
|
case "386":
|
||||||
// On 386, stack frame is three words, plus caller PC.
|
// On 386, stack frame is three words, plus caller PC.
|
||||||
cb = (*args)(unsafe.Pointer(sp + 4*sys.PtrSize))
|
cb = (*args)(unsafe.Pointer(sp + 4*sys.PtrSize))
|
||||||
|
|
|
||||||
|
|
@ -221,3 +221,14 @@ func TestCgoCrashTraceback(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCgoTracebackContext(t *testing.T) {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
t.Skipf("test does not work on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||||
|
}
|
||||||
|
got := runTestProg(t, "testprogcgo", "TracebackContext")
|
||||||
|
want := "OK\n"
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("expected %q got %v", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -352,7 +352,8 @@ type g struct {
|
||||||
gopc uintptr // pc of go statement that created this goroutine
|
gopc uintptr // pc of go statement that created this goroutine
|
||||||
startpc uintptr // pc of goroutine function
|
startpc uintptr // pc of goroutine function
|
||||||
racectx uintptr
|
racectx uintptr
|
||||||
waiting *sudog // sudog structures this g is waiting on (that have a valid elem ptr); in lock order
|
waiting *sudog // sudog structures this g is waiting on (that have a valid elem ptr); in lock order
|
||||||
|
cgoCtxt []uintptr // cgo traceback context
|
||||||
|
|
||||||
// Per-G GC state
|
// Per-G GC state
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,10 @@ type Frames struct {
|
||||||
// ci.callers[0] is the address of the faulting instruction
|
// ci.callers[0] is the address of the faulting instruction
|
||||||
// instead of the return address of the call.
|
// instead of the return address of the call.
|
||||||
wasPanic bool
|
wasPanic bool
|
||||||
|
|
||||||
|
// Frames to return for subsequent calls to the Next method.
|
||||||
|
// Used for non-Go frames.
|
||||||
|
frames *[]Frame
|
||||||
}
|
}
|
||||||
|
|
||||||
// Frame is the information returned by Frames for each call frame.
|
// Frame is the information returned by Frames for each call frame.
|
||||||
|
|
@ -46,12 +50,23 @@ type Frame struct {
|
||||||
// prepares to return function/file/line information.
|
// prepares to return function/file/line information.
|
||||||
// Do not change the slice until you are done with the Frames.
|
// Do not change the slice until you are done with the Frames.
|
||||||
func CallersFrames(callers []uintptr) *Frames {
|
func CallersFrames(callers []uintptr) *Frames {
|
||||||
return &Frames{callers, false}
|
return &Frames{callers: callers}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next returns frame information for the next caller.
|
// Next returns frame information for the next caller.
|
||||||
// If more is false, there are no more callers (the Frame value is valid).
|
// If more is false, there are no more callers (the Frame value is valid).
|
||||||
func (ci *Frames) Next() (frame Frame, more bool) {
|
func (ci *Frames) Next() (frame Frame, more bool) {
|
||||||
|
if ci.frames != nil {
|
||||||
|
// We have saved up frames to return.
|
||||||
|
f := (*ci.frames)[0]
|
||||||
|
if len(*ci.frames) == 1 {
|
||||||
|
ci.frames = nil
|
||||||
|
} else {
|
||||||
|
*ci.frames = (*ci.frames)[1:]
|
||||||
|
}
|
||||||
|
return f, ci.frames != nil || len(ci.callers) > 0
|
||||||
|
}
|
||||||
|
|
||||||
if len(ci.callers) == 0 {
|
if len(ci.callers) == 0 {
|
||||||
ci.wasPanic = false
|
ci.wasPanic = false
|
||||||
return Frame{}, false
|
return Frame{}, false
|
||||||
|
|
@ -62,6 +77,9 @@ func (ci *Frames) Next() (frame Frame, more bool) {
|
||||||
f := FuncForPC(pc)
|
f := FuncForPC(pc)
|
||||||
if f == nil {
|
if f == nil {
|
||||||
ci.wasPanic = false
|
ci.wasPanic = false
|
||||||
|
if cgoSymbolizer != nil {
|
||||||
|
return ci.cgoNext(pc, more)
|
||||||
|
}
|
||||||
return Frame{}, more
|
return Frame{}, more
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,6 +105,54 @@ func (ci *Frames) Next() (frame Frame, more bool) {
|
||||||
return frame, more
|
return frame, more
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cgoNext returns frame information for pc, known to be a non-Go function,
|
||||||
|
// using the cgoSymbolizer hook.
|
||||||
|
func (ci *Frames) cgoNext(pc uintptr, more bool) (Frame, bool) {
|
||||||
|
arg := cgoSymbolizerArg{pc: pc}
|
||||||
|
callCgoSymbolizer(&arg)
|
||||||
|
|
||||||
|
if arg.file == nil && arg.funcName == nil {
|
||||||
|
// No useful information from symbolizer.
|
||||||
|
return Frame{}, more
|
||||||
|
}
|
||||||
|
|
||||||
|
var frames []Frame
|
||||||
|
for {
|
||||||
|
frames = append(frames, Frame{
|
||||||
|
PC: pc,
|
||||||
|
Func: nil,
|
||||||
|
Function: gostring(arg.funcName),
|
||||||
|
File: gostring(arg.file),
|
||||||
|
Line: int(arg.lineno),
|
||||||
|
Entry: arg.entry,
|
||||||
|
})
|
||||||
|
if arg.more == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
callCgoSymbolizer(&arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// No more frames for this PC. Tell the symbolizer we are done.
|
||||||
|
// We don't try to maintain a single cgoSymbolizerArg for the
|
||||||
|
// whole use of Frames, because there would be no good way to tell
|
||||||
|
// the symbolizer when we are done.
|
||||||
|
arg.pc = 0
|
||||||
|
callCgoSymbolizer(&arg)
|
||||||
|
|
||||||
|
if len(frames) == 1 {
|
||||||
|
// Return a single frame.
|
||||||
|
return frames[0], more
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the first frame we saw and store the rest to be
|
||||||
|
// returned by later calls to Next.
|
||||||
|
rf := frames[0]
|
||||||
|
frames = frames[1:]
|
||||||
|
ci.frames = new([]Frame)
|
||||||
|
*ci.frames = frames
|
||||||
|
return rf, true
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: Func does not expose the actual unexported fields, because we return *Func
|
// NOTE: Func does not expose the actual unexported fields, because we return *Func
|
||||||
// values to users, and we want to keep them from being able to overwrite the data
|
// values to users, and we want to keep them from being able to overwrite the data
|
||||||
// with (say) *f = Func{}.
|
// with (say) *f = Func{}.
|
||||||
|
|
|
||||||
191
src/runtime/testdata/testprogcgo/tracebackctxt.go
vendored
Normal file
191
src/runtime/testdata/testprogcgo/tracebackctxt.go
vendored
Normal file
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -172,6 +172,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||||
frame.lr = lr0
|
frame.lr = lr0
|
||||||
}
|
}
|
||||||
waspanic := false
|
waspanic := false
|
||||||
|
cgoCtxt := gp.cgoCtxt
|
||||||
printing := pcbuf == nil && callback == nil
|
printing := pcbuf == nil && callback == nil
|
||||||
_defer := gp._defer
|
_defer := gp._defer
|
||||||
|
|
||||||
|
|
@ -252,6 +253,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||||
sp = gp.m.curg.sched.sp
|
sp = gp.m.curg.sched.sp
|
||||||
stkbarG = gp.m.curg
|
stkbarG = gp.m.curg
|
||||||
stkbar = stkbarG.stkbar[stkbarG.stkbarPos:]
|
stkbar = stkbarG.stkbar[stkbarG.stkbarPos:]
|
||||||
|
cgoCtxt = gp.m.curg.cgoCtxt
|
||||||
}
|
}
|
||||||
frame.fp = sp + uintptr(funcspdelta(f, frame.pc, &cache))
|
frame.fp = sp + uintptr(funcspdelta(f, frame.pc, &cache))
|
||||||
if !usesLR {
|
if !usesLR {
|
||||||
|
|
@ -413,6 +415,18 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
|
||||||
n++
|
n++
|
||||||
|
|
||||||
skipped:
|
skipped:
|
||||||
|
if f.entry == cgocallback_gofuncPC && len(cgoCtxt) > 0 {
|
||||||
|
ctxt := cgoCtxt[len(cgoCtxt)-1]
|
||||||
|
cgoCtxt = cgoCtxt[:len(cgoCtxt)-1]
|
||||||
|
|
||||||
|
// skip only applies to Go frames.
|
||||||
|
// callback != nil only used when we only care
|
||||||
|
// about Go frames.
|
||||||
|
if skip == 0 && callback == nil {
|
||||||
|
n = tracebackCgoContext(pcbuf, printing, ctxt, n, max)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
waspanic = f.entry == sigpanicPC
|
waspanic = f.entry == sigpanicPC
|
||||||
|
|
||||||
// Do not unwind past the bottom of the stack.
|
// Do not unwind past the bottom of the stack.
|
||||||
|
|
@ -546,6 +560,39 @@ func getArgInfo(frame *stkframe, f *_func, needArgMap bool) (arglen uintptr, arg
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tracebackCgoContext handles tracing back a cgo context value, from
|
||||||
|
// the context argument to setCgoTraceback, for the gentraceback
|
||||||
|
// function. It returns the new value of n.
|
||||||
|
func tracebackCgoContext(pcbuf *uintptr, printing bool, ctxt uintptr, n, max int) int {
|
||||||
|
var cgoPCs [32]uintptr
|
||||||
|
cgoContextPCs(ctxt, cgoPCs[:])
|
||||||
|
var arg cgoSymbolizerArg
|
||||||
|
anySymbolized := false
|
||||||
|
for _, pc := range cgoPCs {
|
||||||
|
if pc == 0 || n >= max {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if pcbuf != nil {
|
||||||
|
(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = pc
|
||||||
|
}
|
||||||
|
if printing {
|
||||||
|
if cgoSymbolizer == nil {
|
||||||
|
print("non-Go function at pc=", hex(pc), "\n")
|
||||||
|
} else {
|
||||||
|
c := printOneCgoTraceback(pc, max-n, &arg)
|
||||||
|
n += c - 1 // +1 a few lines down
|
||||||
|
anySymbolized = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
if anySymbolized {
|
||||||
|
arg.pc = 0
|
||||||
|
callCgoSymbolizer(&arg)
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
func printcreatedby(gp *g) {
|
func printcreatedby(gp *g) {
|
||||||
// Show what created goroutine, except main goroutine (goid 1).
|
// Show what created goroutine, except main goroutine (goid 1).
|
||||||
pc := gp.gopc
|
pc := gp.gopc
|
||||||
|
|
@ -782,10 +829,11 @@ func isSystemGoroutine(gp *g) bool {
|
||||||
// };
|
// };
|
||||||
//
|
//
|
||||||
// If the Context field is 0, the context function is being called to
|
// If the Context field is 0, the context function is being called to
|
||||||
// record the current traceback context. It should record whatever
|
// record the current traceback context. It should record in the
|
||||||
// information is needed about the current point of execution to later
|
// Context field whatever information is needed about the current
|
||||||
// produce a stack trace, probably the stack pointer and PC. In this
|
// point of execution to later produce a stack trace, probably the
|
||||||
// case the context function will be called from C code.
|
// stack pointer and PC. In this case the context function will be
|
||||||
|
// called from C code.
|
||||||
//
|
//
|
||||||
// If the Context field is not 0, then it is a value returned by a
|
// If the Context field is not 0, then it is a value returned by a
|
||||||
// previous call to the context function. This case is called when the
|
// previous call to the context function. This case is called when the
|
||||||
|
|
@ -903,16 +951,18 @@ func SetCgoTraceback(version int, traceback, context, symbolizer unsafe.Pointer)
|
||||||
if version != 0 {
|
if version != 0 {
|
||||||
panic("unsupported version")
|
panic("unsupported version")
|
||||||
}
|
}
|
||||||
if context != nil {
|
|
||||||
panic("SetCgoTraceback: context function not yet implemented")
|
|
||||||
}
|
|
||||||
cgoTraceback = traceback
|
cgoTraceback = traceback
|
||||||
cgoContext = context
|
|
||||||
cgoSymbolizer = symbolizer
|
cgoSymbolizer = symbolizer
|
||||||
|
|
||||||
|
// The context function is called when a C function calls a Go
|
||||||
|
// function. As such it is only called by C code in runtime/cgo.
|
||||||
|
if _cgo_set_context_function != nil {
|
||||||
|
cgocall(_cgo_set_context_function, context)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var cgoTraceback unsafe.Pointer
|
var cgoTraceback unsafe.Pointer
|
||||||
var cgoContext unsafe.Pointer
|
|
||||||
var cgoSymbolizer unsafe.Pointer
|
var cgoSymbolizer unsafe.Pointer
|
||||||
|
|
||||||
// cgoTracebackArg is the type passed to cgoTraceback.
|
// cgoTracebackArg is the type passed to cgoTraceback.
|
||||||
|
|
@ -922,7 +972,7 @@ type cgoTracebackArg struct {
|
||||||
max uintptr
|
max uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
// cgoContextArg is the type passed to cgoContext.
|
// cgoContextArg is the type passed to the context function.
|
||||||
type cgoContextArg struct {
|
type cgoContextArg struct {
|
||||||
context uintptr
|
context uintptr
|
||||||
}
|
}
|
||||||
|
|
@ -950,39 +1000,75 @@ func printCgoTraceback(callers *cgoCallers) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
call := cgocall
|
|
||||||
if panicking > 0 {
|
|
||||||
// We do not want to call into the scheduler when panicking.
|
|
||||||
call = asmcgocall
|
|
||||||
}
|
|
||||||
|
|
||||||
var arg cgoSymbolizerArg
|
var arg cgoSymbolizerArg
|
||||||
for _, c := range callers {
|
for _, c := range callers {
|
||||||
if c == 0 {
|
if c == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
arg.pc = c
|
printOneCgoTraceback(c, 0x7fffffff, &arg)
|
||||||
for {
|
|
||||||
call(cgoSymbolizer, noescape(unsafe.Pointer(&arg)))
|
|
||||||
if arg.funcName != nil {
|
|
||||||
// Note that we don't print any argument
|
|
||||||
// information here, not even parentheses.
|
|
||||||
// The symbolizer must add that if
|
|
||||||
// appropriate.
|
|
||||||
println(gostringnocopy(arg.funcName))
|
|
||||||
} else {
|
|
||||||
println("non-Go function")
|
|
||||||
}
|
|
||||||
print("\t")
|
|
||||||
if arg.file != nil {
|
|
||||||
print(gostringnocopy(arg.file), ":", arg.lineno, " ")
|
|
||||||
}
|
|
||||||
print("pc=", hex(c), "\n")
|
|
||||||
if arg.more == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
arg.pc = 0
|
arg.pc = 0
|
||||||
call(cgoSymbolizer, noescape(unsafe.Pointer(&arg)))
|
callCgoSymbolizer(&arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// printOneCgoTraceback prints the traceback of a single cgo caller.
|
||||||
|
// This can print more than one line because of inlining.
|
||||||
|
// Returns the number of frames printed.
|
||||||
|
func printOneCgoTraceback(pc uintptr, max int, arg *cgoSymbolizerArg) int {
|
||||||
|
c := 0
|
||||||
|
arg.pc = pc
|
||||||
|
for {
|
||||||
|
if c > max {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
callCgoSymbolizer(arg)
|
||||||
|
if arg.funcName != nil {
|
||||||
|
// Note that we don't print any argument
|
||||||
|
// information here, not even parentheses.
|
||||||
|
// The symbolizer must add that if appropriate.
|
||||||
|
println(gostringnocopy(arg.funcName))
|
||||||
|
} else {
|
||||||
|
println("non-Go function")
|
||||||
|
}
|
||||||
|
print("\t")
|
||||||
|
if arg.file != nil {
|
||||||
|
print(gostringnocopy(arg.file), ":", arg.lineno, " ")
|
||||||
|
}
|
||||||
|
print("pc=", hex(c), "\n")
|
||||||
|
c++
|
||||||
|
if arg.more == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// callCgoSymbolizer calls the cgoSymbolizer function.
|
||||||
|
func callCgoSymbolizer(arg *cgoSymbolizerArg) {
|
||||||
|
call := cgocall
|
||||||
|
if panicking > 0 || getg().m.curg != getg() {
|
||||||
|
// We do not want to call into the scheduler when panicking
|
||||||
|
// or when on the system stack.
|
||||||
|
call = asmcgocall
|
||||||
|
}
|
||||||
|
call(cgoSymbolizer, noescape(unsafe.Pointer(arg)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// cgoContextPCs gets the PC values from a cgo traceback.
|
||||||
|
func cgoContextPCs(ctxt uintptr, buf []uintptr) {
|
||||||
|
if cgoTraceback == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
call := cgocall
|
||||||
|
if panicking > 0 || getg().m.curg != getg() {
|
||||||
|
// We do not want to call into the scheduler when panicking
|
||||||
|
// or when on the system stack.
|
||||||
|
call = asmcgocall
|
||||||
|
}
|
||||||
|
arg := cgoTracebackArg{
|
||||||
|
context: ctxt,
|
||||||
|
buf: (*uintptr)(noescape(unsafe.Pointer(&buf[0]))),
|
||||||
|
max: uintptr(len(buf)),
|
||||||
|
}
|
||||||
|
call(cgoTraceback, noescape(unsafe.Pointer(&arg)))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue