1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
|
// +build gccgo
package hook
import (
"runtime"
"strings"
)
// callerDepth defines the number of stack frames to skip during
// currentServiceMethodName. This value differs for various gccgo
// versions.
var callerDepth int
// namePartsPos defines the position within the raw method name, deliniated by periods.
var namePartsPos = -1 // will panic if we cannot determine the position.
type inner struct{}
func (i *inner) m() {
for callerDepth = 1; ; callerDepth++ {
pc, _, _, ok := runtime.Caller(callerDepth)
if !ok {
panic("current method name cannot be found")
}
if name := runtime.FuncForPC(pc).Name(); name == "hook.setCallerDepth" {
for i, s := range strings.Split(name, ".") {
if s == "setCallerDepth" {
namePartsPos = i
break
}
}
return
}
}
}
type outer struct {
inner
}
func setCallerDepth0() {
var o outer
o.m()
}
func setCallerDepth() {
setCallerDepth0()
}
func init() {
setCallerDepth()
println(callerDepth)
}
// currentServiceMethodName returns the method executing on the service when ProcessControlHook was invoked.
func (s *TestService) currentServiceMethodName() string {
// We have to go deeper into the stack with gccgo because in a situation like:
// type Inner { }
// func (i *Inner) meth {}
// type Outer { Inner }
// o = &Outer{}
// o.meth()
// gccgo generates a method called "meth" on *Outer, and this shows up
// on the stack as seen by runtime.Caller (this might be a gccgo bug).
pc, _, _, ok := runtime.Caller(callerDepth)
if !ok {
panic("current method name cannot be found")
}
return unqualifiedMethodName(pc)
}
func unqualifiedMethodName(pc uintptr) string {
f := runtime.FuncForPC(pc)
fullName := f.Name()
// This is very fragile. fullName will be something like:
// launchpad.net_goose_testservices_novaservice.removeServer.pN49_launchpad.net_goose_testservices_novaservice.Nova
// so if the number of dots in the full package path changes,
// We try to figure sniff this value at the top, but it may not work.
nameParts := strings.Split(fullName, ".")
return nameParts[namePartsPos]
}
|