...
Run Format

Source file src/runtime/debugcall.go

Documentation: runtime

  // Copyright 2018 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 amd64
  
  package runtime
  
  import "unsafe"
  
  const (
  	debugCallSystemStack = "executing on Go runtime stack"
  	debugCallUnknownFunc = "call from unknown function"
  	debugCallRuntime     = "call from within the Go runtime"
  	debugCallUnsafePoint = "call not at safe point"
  )
  
  func debugCallV1()
  func debugCallPanicked(val interface{})
  
  // debugCallCheck checks whether it is safe to inject a debugger
  // function call with return PC pc. If not, it returns a string
  // explaining why.
  //
  //go:nosplit
  func debugCallCheck(pc uintptr) string {
  	// No user calls from the system stack.
  	if getg() != getg().m.curg {
  		return debugCallSystemStack
  	}
  	if sp := getcallersp(); !(getg().stack.lo < sp && sp <= getg().stack.hi) {
  		// Fast syscalls (nanotime) and racecall switch to the
  		// g0 stack without switching g. We can't safely make
  		// a call in this state. (We can't even safely
  		// systemstack.)
  		return debugCallSystemStack
  	}
  
  	// Switch to the system stack to avoid overflowing the user
  	// stack.
  	var ret string
  	systemstack(func() {
  		f := findfunc(pc)
  		if !f.valid() {
  			ret = debugCallUnknownFunc
  			return
  		}
  
  		// Disallow calls from the runtime. We could
  		// potentially make this condition tighter (e.g., not
  		// when locks are held), but there are enough tightly
  		// coded sequences (e.g., defer handling) that it's
  		// better to play it safe.
  		if name, pfx := funcname(f), "runtime."; len(name) > len(pfx) && name[:len(pfx)] == pfx {
  			ret = debugCallRuntime
  			return
  		}
  
  		// Look up PC's register map.
  		pcdata := int32(-1)
  		if pc != f.entry {
  			pc--
  			pcdata = pcdatavalue(f, _PCDATA_RegMapIndex, pc, nil)
  		}
  		if pcdata == -1 {
  			pcdata = 0 // in prologue
  		}
  		stkmap := (*stackmap)(funcdata(f, _FUNCDATA_RegPointerMaps))
  		if pcdata == -2 || stkmap == nil {
  			// Not at a safe point.
  			ret = debugCallUnsafePoint
  			return
  		}
  	})
  	return ret
  }
  
  // debugCallWrap pushes a defer to recover from panics in debug calls
  // and then calls the dispatching function at PC dispatch.
  func debugCallWrap(dispatch uintptr) {
  	var dispatchF func()
  	dispatchFV := funcval{dispatch}
  	*(*unsafe.Pointer)(unsafe.Pointer(&dispatchF)) = noescape(unsafe.Pointer(&dispatchFV))
  
  	var ok bool
  	defer func() {
  		if !ok {
  			err := recover()
  			debugCallPanicked(err)
  		}
  	}()
  	dispatchF()
  	ok = true
  }
  

View as plain text