| // 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 | 
 | 		} | 
 |  | 
 | 		name := funcname(f) | 
 |  | 
 | 		switch name { | 
 | 		case "debugCall32", | 
 | 			"debugCall64", | 
 | 			"debugCall128", | 
 | 			"debugCall256", | 
 | 			"debugCall512", | 
 | 			"debugCall1024", | 
 | 			"debugCall2048", | 
 | 			"debugCall4096", | 
 | 			"debugCall8192", | 
 | 			"debugCall16384", | 
 | 			"debugCall32768", | 
 | 			"debugCall65536": | 
 | 			// These functions are whitelisted so that the debugger can initiate multiple function calls. | 
 | 			// See: https://golang.org/cl/161137/ | 
 | 			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 pfx := "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 | 
 | } |