github.com/bytedance/mockey@v1.2.10/internal/monkey/inst/disasm_arm64.go (about)

     1  /*
     2   * Copyright 2022 ByteDance Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package inst
    18  
    19  import (
    20  	"reflect"
    21  	"unsafe"
    22  
    23  	"github.com/bytedance/mockey/internal/monkey/common"
    24  	"github.com/bytedance/mockey/internal/tool"
    25  	"golang.org/x/arch/arm64/arm64asm"
    26  )
    27  
    28  func calcFnAddrRange(name string, fn func()) (uintptr, uintptr) {
    29  	v := reflect.ValueOf(fn)
    30  	var start, end uintptr
    31  	start = v.Pointer()
    32  	maxScan := 2000
    33  	code := common.BytesOf(start, 2000)
    34  	pos := 0
    35  	for pos < maxScan {
    36  		inst, err := arm64asm.Decode(code[pos:])
    37  		tool.Assert(err == nil, err)
    38  
    39  		args := []interface{}{name, inst.Op}
    40  		for i := range inst.Args {
    41  			args = append(args, inst.Args[i])
    42  		}
    43  		tool.DebugPrintf("init: <%v>\t%v\t%v\t%v\t%v\t%v\t%v\n", args...)
    44  
    45  		if inst.Op == arm64asm.RET {
    46  			end = start + uintptr(pos)
    47  			tool.DebugPrintf("init: %v(%v,%v)\n", name, start, end)
    48  			return start, end
    49  		}
    50  
    51  		pos += int(unsafe.Sizeof(inst.Enc))
    52  	}
    53  	tool.Assert(false, "%v end not found", name)
    54  	return 0, 0
    55  }
    56  
    57  func Disassemble(code []byte, required int, checkLen bool) int {
    58  	tool.Assert(len(code) > required, "function is too short to patch")
    59  	return required
    60  }
    61  
    62  func GetGenericJumpAddr(addr uintptr, maxScan uint64) uintptr {
    63  	code := common.BytesOf(addr, int(maxScan))
    64  	var pos uint64
    65  	var err error
    66  	var inst arm64asm.Inst
    67  
    68  	allAddrs := []uintptr{}
    69  	for pos < maxScan {
    70  		inst, err = arm64asm.Decode(code[pos:])
    71  		tool.Assert(err == nil, err)
    72  		args := []interface{}{inst.Op}
    73  		for i := range inst.Args {
    74  			args = append(args, inst.Args[i])
    75  		}
    76  		tool.DebugPrintf("%v\t%v\t%v\t%v\t%v\t%v\n", args...)
    77  
    78  		if inst.Op == arm64asm.RET {
    79  			break
    80  		}
    81  
    82  		if inst.Op == arm64asm.BL {
    83  			fnAddr := calcAddr(uintptr(unsafe.Pointer(&code[0]))+uintptr(pos), inst.Enc)
    84  			isExtraCall, extraName := isGenericProxyCallExtra(fnAddr)
    85  			tool.DebugPrintf("found BL, raw is: %x,  fnAddr: %v, isExtraCall: %v, extraName: %v\n", inst.String(), fnAddr, isExtraCall, extraName)
    86  			if !isExtraCall {
    87  				allAddrs = append(allAddrs, fnAddr)
    88  			}
    89  		}
    90  		pos += uint64(unsafe.Sizeof(inst.Enc))
    91  	}
    92  	tool.Assert(len(allAddrs) == 1, "invalid callAddr: %v", allAddrs)
    93  	return allAddrs[0]
    94  }
    95  
    96  func calcAddr(from uintptr, bl uint32) uintptr {
    97  	tool.DebugPrintf("calc BL addr, from: %x(%v) bl: %x\n", from, from, bl)
    98  	offset := bl << 8 >> 8
    99  	flag := (offset << 9 >> 9) == offset // 是否小于0
   100  
   101  	var dest uintptr
   102  	if flag {
   103  		// L -> H
   104  		// (dest - cur) / 4 = offset
   105  		// dest = cur + offset * 4
   106  		dest = from + uintptr(offset*4)
   107  	} else {
   108  		// H -> L
   109  		// (cur - dest) / 4 = (0x00ffffff - offset + 1)
   110  		// dest = cur -  (0x00ffffff - offset + 1) * 4
   111  		dest = from - uintptr((0x00ffffff-offset+1)*4)
   112  	}
   113  	tool.DebugPrintf("2th complement, L->H:%v offset: %x from: %x(%v) dest: %x(%v), distance: %v\n", flag, offset, from, from, dest, dest, from-dest)
   114  	return dest
   115  }