go.undefinedlabs.com/scopeagent@v0.4.2/reflection/panic_handler.go (about) 1 package reflection 2 3 import ( 4 "sync" 5 "unsafe" 6 _ "unsafe" 7 8 "github.com/undefinedlabs/go-mpatch" 9 ) 10 11 var ( 12 patchOnPanic *mpatch.Patch 13 mOnPanic sync.Mutex 14 onPanicHandlers []func(e interface{}) 15 16 patchOnExit *mpatch.Patch 17 mOnExit sync.Mutex 18 onExitHandler []func(e interface{}) 19 ) 20 21 // Adds a global panic handler (this handler will be executed before any recover call) 22 func AddPanicHandler(fn func(interface{})) { 23 mOnPanic.Lock() 24 defer mOnPanic.Unlock() 25 if patchOnPanic == nil { 26 np, err := mpatch.PatchMethod(lgopanic, gopanic) 27 if err == nil { 28 patchOnPanic = np 29 } 30 } 31 onPanicHandlers = append(onPanicHandlers, fn) 32 } 33 34 // Adds a global panic handler before process kill (this handler will be executed if not recover is set before the process exits) 35 func AddOnPanicExitHandler(fn func(interface{})) { 36 mOnExit.Lock() 37 defer mOnExit.Unlock() 38 if patchOnExit == nil { 39 np, err := mpatch.PatchMethod(lpreprintpanics, preprintpanics) 40 if err == nil { 41 patchOnExit = np 42 } 43 } 44 onExitHandler = append(onExitHandler, fn) 45 } 46 47 func gopanic(e interface{}) { 48 mOnPanic.Lock() 49 defer mOnPanic.Unlock() 50 for _, fn := range onPanicHandlers { 51 fn(e) 52 } 53 patchOnPanic.Unpatch() 54 defer patchOnPanic.Patch() 55 lgopanic(e) 56 } 57 58 func preprintpanics(p *_panic) { 59 mOnExit.Lock() 60 defer mOnExit.Unlock() 61 for _, fn := range onExitHandler { 62 fn(p.arg) 63 } 64 patchOnExit.Unpatch() 65 defer patchOnExit.Patch() 66 lpreprintpanics(p) 67 } 68 69 //go:linkname lgopanic runtime.gopanic 70 func lgopanic(e interface{}) 71 72 //go:linkname lpreprintpanics runtime.preprintpanics 73 func lpreprintpanics(p *_panic) 74 75 type _panic struct { 76 argp unsafe.Pointer // pointer to arguments of deferred call run during panic; cannot move - known to liblink 77 arg interface{} // argument to panic 78 link *_panic // link to earlier panic 79 recovered bool // whether this panic is over 80 aborted bool // the panic was aborted 81 }