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  }