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