github.com/x04/go/src@v0.0.0-20200202162449-3d481ceb3525/runtime/debugcall.go (about) 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 "github.com/x04/go/src/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 }