github.com/tencent/goom@v1.0.1/internal/patch/fix_origin_amd64.go (about) 1 package patch 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/tencent/goom/internal/bytecode" 8 "github.com/tencent/goom/internal/bytecode/memory" 9 "github.com/tencent/goom/internal/logger" 10 ) 11 12 // fixOriginFuncToTrampoline 将原始函数 from 的指令到 trampoline 指向的地址(在 PlaceHolder 区内存区段内) 13 // 对于 trampoline 模式的使用场景,本方法实现了指令移动后的修复 14 // 此方式不需要修正 pcvalue, 因此相对较安全 15 // 因 trampoline 函数需要指定签名,因此只能用于静态代理 16 // from 原始函数位置 17 // trampoline 自定义占位函数位置(注意, 自定义占位函数一定要和原函数相同的函数签名,否则栈帧不一致会导致计算调用堆栈时候抛异常) 18 // jumpInstSize 跳转指令长度, 用于判断需要修复的最小指令长度 19 // return 跳板函数(即原函数调用入口指针) 20 func fixOriginFuncToTrampoline(origin uintptr, trampoline uintptr, jumpInstSize int) (uintptr, error) { 21 // get origin func size 22 originFuncSize, err := bytecode.GetFuncSize(defaultArchMod, origin, false) 23 if err != nil { 24 logger.Error("GetFuncSize error", err) 25 originFuncSize = defaultFuncSize 26 } 27 28 // get trampoline func size 29 trampFuncSize, err := bytecode.GetFuncSize(defaultArchMod, trampoline, false) 30 if err != nil { 31 logger.Error("GetFuncSize error", err) 32 trampFuncSize = 20 33 } 34 logger.Debug("origin func size is", originFuncSize) 35 36 // 如果需要修复的指令长度大于 trampoline 函数指令长度,则任务是无法修复 37 if jumpInstSize >= trampFuncSize { 38 bytecode.PrintInst("origin inst > ", origin, bytecode.PrintShort, logger.InfoLevel) 39 return 0, fmt.Errorf( 40 "jumpInstSize[%d] is bigger than trampoline FuncSize[%d], "+ 41 "please fill your trampoline func code", jumpInstSize, originFuncSize) 42 } 43 44 // copy origin function 45 fixOriginData := memory.RawRead(origin, originFuncSize) 46 bytecode.PrintInstf("origin inst >>>>> ", origin, 47 fixOriginData[:bytecode.MinSize(bytecode.PrintMiddle, fixOriginData)], logger.DebugLevel) 48 49 // fix relative address to placeholder 50 fixedData, fixedDataSize, err := fixRelativeAddr(origin, fixOriginData, trampoline, originFuncSize, jumpInstSize) 51 if err != nil { 52 return 0, err 53 } 54 55 if len(fixedData) < len(fixOriginData) { 56 // 追加跳转到原函数指令到修复后指令的末尾 57 // append jump back to origin func position where next to the broken instructions 58 jumpBackData := jmpToOriginFunctionValue( 59 trampoline+uintptr(len(fixedData)), 60 origin+(uintptr(fixedDataSize))) 61 fixOriginData = append(fixedData, jumpBackData...) 62 } 63 64 // get trampoline func size 65 trampolineFuncSize, err := bytecode.GetFuncSize(defaultArchMod, trampoline, false) 66 if err != nil { 67 logger.Error("Get trampoline FuncSize error", err) 68 return 0, errors.New("Get trampoline FuncSize error:" + err.Error()) 69 } 70 logger.Debug("trampoline func size is", trampolineFuncSize) 71 72 if len(fixOriginData) > trampolineFuncSize { 73 logger.Errorf("fixOriginSize[%d] is bigger than trampoline FuncSize[%d], please add your "+ 74 "trampoline func code", len(fixOriginData), trampolineFuncSize) 75 bytecode.PrintInst("trampoline inst > ", trampoline, bytecode.PrintLong, logger.InfoLevel) 76 77 return 0, fmt.Errorf("fixOriginSize[%d] is bigger than trampoline FuncSize[%d], "+ 78 "please add your trampoline func code", len(fixOriginData), trampolineFuncSize) 79 } 80 bytecode.PrintInst("trampoline inst > ", trampoline, bytecode.PrintLong, logger.DebugLevel) 81 bytecode.PrintInstf("fixed inst >>>>> ", trampoline, fixOriginData, logger.DebugLevel) 82 83 if err := memory.WriteTo(trampoline, fixOriginData); err != nil { 84 return 0, err 85 } 86 87 bytecode.PrintInst(fmt.Sprintf("trampline copy to 0x%x", trampoline), 88 trampoline, bytecode.PrintMiddle, logger.DebugLevel) 89 logger.Debugf("copy to trampoline %x ", trampoline) 90 return trampoline, nil 91 }