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 7package runtime 8 9import "unsafe" 10 11const ( 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 18func debugCallV1() 19func 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 26func 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. 100func 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