Source file src/runtime/debugcall.go

Documentation: runtime

     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