...

Source file src/runtime/debugcall.go

     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	// +build amd64
     6	
     7	package runtime
     8	
     9	import "unsafe"
    10	
    11	const (
    12		debugCallSystemStack = "executing on Go runtime stack"
    13		debugCallUnknownFunc = "call from unknown function"
    14		debugCallRuntime     = "call from within the Go runtime"
    15		debugCallUnsafePoint = "call not at safe point"
    16	)
    17	
    18	func debugCallV1()
    19	func debugCallPanicked(val interface{})
    20	
    21	// debugCallCheck checks whether it is safe to inject a debugger
    22	// function call with return PC pc. If not, it returns a string
    23	// explaining why.
    24	//
    25	//go:nosplit
    26	func debugCallCheck(pc uintptr) string {
    27		// No user calls from the system stack.
    28		if getg() != getg().m.curg {
    29			return debugCallSystemStack
    30		}
    31		if sp := getcallersp(); !(getg().stack.lo < sp && sp <= getg().stack.hi) {
    32			// Fast syscalls (nanotime) and racecall switch to the
    33			// g0 stack without switching g. We can't safely make
    34			// a call in this state. (We can't even safely
    35			// systemstack.)
    36			return debugCallSystemStack
    37		}
    38	
    39		// Switch to the system stack to avoid overflowing the user
    40		// stack.
    41		var ret string
    42		systemstack(func() {
    43			f := findfunc(pc)
    44			if !f.valid() {
    45				ret = debugCallUnknownFunc
    46				return
    47			}
    48	
    49			name := funcname(f)
    50	
    51			switch name {
    52			case "debugCall32",
    53				"debugCall64",
    54				"debugCall128",
    55				"debugCall256",
    56				"debugCall512",
    57				"debugCall1024",
    58				"debugCall2048",
    59				"debugCall4096",
    60				"debugCall8192",
    61				"debugCall16384",
    62				"debugCall32768",
    63				"debugCall65536":
    64				// These functions are whitelisted so that the debugger can initiate multiple function calls.
    65				// See: https://golang.org/cl/161137/
    66				return
    67			}
    68	
    69			// Disallow calls from the runtime. We could
    70			// potentially make this condition tighter (e.g., not
    71			// when locks are held), but there are enough tightly
    72			// coded sequences (e.g., defer handling) that it's
    73			// better to play it safe.
    74			if pfx := "runtime."; len(name) > len(pfx) && name[:len(pfx)] == pfx {
    75				ret = debugCallRuntime
    76				return
    77			}
    78	
    79			// Look up PC's register map.
    80			pcdata := int32(-1)
    81			if pc != f.entry {
    82				pc--
    83				pcdata = pcdatavalue(f, _PCDATA_RegMapIndex, pc, nil)
    84			}
    85			if pcdata == -1 {
    86				pcdata = 0 // in prologue
    87			}
    88			stkmap := (*stackmap)(funcdata(f, _FUNCDATA_RegPointerMaps))
    89			if pcdata == -2 || stkmap == nil {
    90				// Not at a safe point.
    91				ret = debugCallUnsafePoint
    92				return
    93			}
    94		})
    95		return ret
    96	}
    97	
    98	// debugCallWrap pushes a defer to recover from panics in debug calls
    99	// and then calls the dispatching function at PC dispatch.
   100	func debugCallWrap(dispatch uintptr) {
   101		var dispatchF func()
   102		dispatchFV := funcval{dispatch}
   103		*(*unsafe.Pointer)(unsafe.Pointer(&dispatchF)) = noescape(unsafe.Pointer(&dispatchFV))
   104	
   105		var ok bool
   106		defer func() {
   107			if !ok {
   108				err := recover()
   109				debugCallPanicked(err)
   110			}
   111		}()
   112		dispatchF()
   113		ok = true
   114	}
   115	

View as plain text