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 6 // +build darwin openbsd 7 8 package runtime 9 10 import "unsafe" 11 12 // Call fn with arg as its argument. Return what fn returns. 13 // fn is the raw pc value of the entry point of the desired function. 14 // Switches to the system stack, if not already there. 15 // Preserves the calling point as the location where a profiler traceback will begin. 16 //go:nosplit 17 func 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