1// Copyright 2018 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//go:build darwin || (openbsd && !mips64)
6
7package runtime
8
9import "unsafe"
10
11// Call fn with arg as its argument. Return what fn returns.
12// fn is the raw pc value of the entry point of the desired function.
13// Switches to the system stack, if not already there.
14// Preserves the calling point as the location where a profiler traceback will begin.
15//
16//go:nosplit
17func libcCall(fn, arg unsafe.Pointer) int32 {
18	// Leave caller's PC/SP/G around for traceback.
19	gp := getg()
20	var mp *m
21	if gp != nil {
22		mp = gp.m
23	}
24	if mp != nil && mp.libcallsp == 0 {
25		mp.libcallg.set(gp)
26		mp.libcallpc = getcallerpc()
27		// sp must be the last, because once async cpu profiler finds
28		// all three values to be non-zero, it will use them
29		mp.libcallsp = getcallersp()
30	} else {
31		// Make sure we don't reset libcallsp. This makes
32		// libcCall reentrant; We remember the g/pc/sp for the
33		// first call on an M, until that libcCall instance
34		// returns.  Reentrance only matters for signals, as
35		// libc never calls back into Go.  The tricky case is
36		// where we call libcX from an M and record g/pc/sp.
37		// Before that call returns, a signal arrives on the
38		// same M and the signal handling code calls another
39		// libc function.  We don't want that second libcCall
40		// from within the handler to be recorded, and we
41		// don't want that call's completion to zero
42		// libcallsp.
43		// We don't need to set libcall* while we're in a sighandler
44		// (even if we're not currently in libc) because we block all
45		// signals while we're handling a signal. That includes the
46		// profile signal, which is the one that uses the libcall* info.
47		mp = nil
48	}
49	res := asmcgocall(fn, arg)
50	if mp != nil {
51		mp.libcallsp = 0
52	}
53	return res
54}
55