package inject

/*
#cgo CFLAGS: -I include
#cgo amd64 LDFLAGS: ${SRCDIR}/lib/libhotpatch_amd64.a
#cgo arm64 LDFLAGS: ${SRCDIR}/lib/libhotpatch_arm64.a
#include "hotpatch.h"
#include <stdlib.h>
*/
import "C"

import (
	"bufio"
	"bytes"
	"fmt"
	"github.com/coroot/coroot-node-agent/utils"
	klog "github.com/sirupsen/logrus"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"

	"golang.org/x/arch/arm64/arm64asm"
	"golang.org/x/arch/x86/x86asm"

	//"time"
	"unsafe"
)

var jumpOps = map[arm64asm.Op]bool{
	arm64asm.CBZ:  true,
	arm64asm.CBNZ: true,
	arm64asm.B:    true,
	arm64asm.TBZ:  true,
	arm64asm.TBNZ: true,
	arm64asm.ADRP: true,
	arm64asm.BL:   true,
	arm64asm.BLR:  true,
	arm64asm.RET:  true,
	arm64asm.BR:   true,
}

const NOP_ENC = 0xd503201f

const RET_ENC = 0xd65f03c0

var nopBytes = []byte{0xd5, 0x03, 0x20, 0x1f}

const (
	IO_FD_FDID_SYM_OFFSET = 192
	NET_SEND_SYM_OFFSET   = 776
)
const (
	OFFSET_0      = 0
	OFFSET_16_BIT = 1
	OFFSET_32_BIT = 2
	OFFSET_48_BIT = 3
	PC_START      = 0

	BLR_X18 = 0xd63f0240
)

var SrcAddrOffset uintptr

const ChangeEncLen = 3

type InstInfo struct {
	SymName          string
	SymSize          uint64
	SymAddr          uint64
	PC               uint64
	Inst             arm64asm.Inst
	OriginInst       arm64asm.Inst
	OriginCode       []byte
	TargetAddr       uint64
	OriginTargetAddr uint64
	TargetEnc        uint32
	OriginEnc        uint32
}

type InnerSymbolInfo struct {
	IO_fd_fdID_ADRP InstInfo
	IO_fd_fdID_ADD  InstInfo
	NET_Send        InstInfo
}

//
//type LibNetInfo struct {
//	LibName     string
//	LibPath     string
//	FuncSymbol  InstInfo
//	InnerSymbol InnerSymbolInfo
//}
//
//type UprobeData struct {
//	Offset  int
//	Func    string
//	ELFPath string
//}
//
//type JvmInjector struct {
//	Pid               int
//	ReleaseLibNetInfo LibNetInfo
//	DebugLibNetInfo   LibNetInfo
//	RecodeInfo        LibNetInfo
//	// 原方法首个指令不为jmp | ReleaseLibNetInfo 读取无异常
//	PreCheck struct {
//		NeedInjectionCheck bool // 原指令校验 true表示可以继续执行注入
//		LoadingCheck       bool // true 表示加载成功
//		IoFdCheck          bool // fd地址校验
//		NetSendFuncCheck   bool // netsend校验
//		EbpfCanInjection   bool
//	}
//	AfterCheck struct {
//		IoFdCheck        bool
//		NetSendFuncCheck bool
//	}
//	Uprobe UprobeData
//	Rootfs string
//}

func (j *JvmInjector) checkEnc(code []byte, start, len uint64, enc uint32) error {
	end := start + len
	inst, err := arm64asm.Decode(code[start:end])
	if err != nil {
		return fmt.Errorf("Decode code[%d:%d] %s: err is <%v>", start, end, arm64asm.GNUSyntax(inst), err)
	} else {
		if inst.Enc != enc {
			return fmt.Errorf("Validation inst failed:'%s <+%d>: %s'", fmt.Sprintf("0x%016x", j.ReleaseLibNetInfo.FuncSymbol.SymAddr+start), start, arm64asm.GNUSyntax(inst))
		}
	}
	return nil
}

func (j *JvmInjector) findReleaseAddressInfoFromMem() error {
	funcAbsAddress := j.ReleaseLibNetInfo.FuncSymbol.SymAddr
	releaseFuncSym := InnerSymbolInfo{}
	code, err := j.readMemory(funcAbsAddress, j.ReleaseLibNetInfo.FuncSymbol.SymSize)
	if err != nil {
		return err
	}
	klog.Infof("[inject] SymSize %d", j.ReleaseLibNetInfo.FuncSymbol.SymSize)
	// cwso是否载入,载入则从recode判断指令 ToDo更新位置信息
	baseAddress, _, err := j.findLibBaseFromProcMaps(j.DebugLibNetInfo.LibName)
	if err == nil {
		j.PreCheck.LoadingCheck = true
		klog.Infof("[inject] so already loaded check enc...")
		// 获取recode地址
		klog.Infof("[inject] baseAddress %d", baseAddress)

		recodeFunctionSym, err := GetFunctionOffset(j.DebugLibNetInfo.LibPath, j.RecodeInfo.FuncSymbol.SymName)
		if err != nil {
			klog.WithError(err).Errorf("[inject] get recode function symbol failed.")
			return err
		}
		j.RecodeInfo.FuncSymbol.SymAddr = baseAddress + recodeFunctionSym.Value
		recode, err := j.readMemory(j.RecodeInfo.FuncSymbol.SymAddr, 4)
		if err != nil {
			return err
		}
		if !bytes.Equal(recode, nopBytes) {
			j.PreCheck.EbpfCanInjection = true
			klog.Infof("[inject] successful...")
			return nil
		}
		klog.Infof("[inject] so already loaded. check failed.")
	}
	/*
		0x0000fffbdc0ef24c <+56>:	str	x2, [x6,#120]
		0x0000fffbdc0ef250 <+60>:	str	x3, [x29,#96]
		0x0000fffbdc0ef254 <+64>:	mov	x21, x0
		0x0000fffbdc0ef258 <+68>:	mov	w28, w4
		0x0000fffbdc0ef25c <+72>:	mov	w23, w5
	*/
	// 修改指令效验方式为首地址 w5向上偏移4段
	// TODO Position Independent check
	klog.Infof("[inject] start check...")
	if os.Getenv("jvm_offset") != "" {
		if off, err := strconv.Atoi(os.Getenv("jvm_offset")); err == nil {
			SrcAddrOffset = uintptr(off)
			if SrcAddrOffset == 0 {
				return fmt.Errorf("[attach] jvm_offset have no hook point.")
			} else {
				klog.Infof("[attach] use jvm_offset off:%d", SrcAddrOffset)
				return nil
			}
		}
	}

	pc := uint64(0)

	var findw5 bool
	var findx3 bool

	for pc < uint64(len(code)) {
		//err = j.checkEnc(code, pc, 4, 0x2a0503f3) // mov w19, w5

		inst, err := arm64asm.Decode(code[pc:])

		if err == nil && inst.Op == arm64asm.STR && inst.Args[0] == arm64asm.X3 && !findw5 {
			findx3 = true
			forwardOk := true
			// Step 1: 向后检查
			for i := 0; i <= ChangeEncLen; i++ {
				offset := pc + uint64(i*4)
				if offset+4 > uint64(len(code)) {
					forwardOk = false
					break
				}
				inst, err := arm64asm.Decode(code[offset : offset+4])
				if err != nil || jumpOps[inst.Op] {
					forwardOk = false
					break
				}
			}
			if forwardOk {
				SrcAddrOffset = uintptr(pc)
				klog.Infof("[inject] x3 start check ok [after]...  SrcAddrOffset:%d", SrcAddrOffset)
				return nil
			}

		}

		if err == nil && inst.Op == arm64asm.MOV && inst.Args[1] == arm64asm.W5 && !findx3 {
			findw5 = true

			// Step 1: 向前检查（不包含当前指令）
			if pc >= uint64(ChangeEncLen*4) {
				backwardOk := true
				for i := 1; i <= ChangeEncLen; i++ {
					offset := pc - uint64(i*4)
					inst, err := arm64asm.Decode(code[offset : offset+4])
					if err != nil || jumpOps[inst.Op] {
						backwardOk = false
						break
					}
				}
				if backwardOk {
					SrcAddrOffset = uintptr(pc - uint64(ChangeEncLen*4))
					klog.Infof("[inject] w5 start check ok [before]... SrcAddrOffset:%d", SrcAddrOffset)
					return nil
				}
			}

			// Step 2: 向前失败 → 尝试向后
			forwardOk := true
			for i := 0; i <= ChangeEncLen; i++ {
				offset := pc + uint64(i*4)
				if offset+4 > uint64(len(code)) {
					forwardOk = false
					break
				}
				inst, err := arm64asm.Decode(code[offset : offset+4])
				if err != nil || jumpOps[inst.Op] {
					forwardOk = false
					break
				}
			}
			if forwardOk {
				SrcAddrOffset = uintptr(pc)
				klog.Infof("[inject] w5 start check ok [after]... SrcAddrOffset:%d", SrcAddrOffset)
				return nil
			}

		}

		pc += 4
	}
	klog.Infof("[inject] SrcAddrOffset:", SrcAddrOffset)

	//aaa, _ := strconv.Atoi(os.Getenv("offset"))
	//SrcAddrOffset = uintptr(aaa)
	if SrcAddrOffset == 0 {
		return fmt.Errorf("[attach] have no hook point.")
	}

	//err = j.checkEnc(code, 56, 4, 0xf9003cc2)
	//if err != nil {
	//	return err
	//}
	//err = j.checkEnc(code, 60, 4, 0xf90033a3)
	//if err != nil {
	//	return err
	//}
	//err = j.checkEnc(code, 64, 4, 0xaa0003f5)
	//if err != nil {
	//	return err
	//}
	//err = j.checkEnc(code, 68, 4, 0x2a0403fc)
	//if err != nil {
	//	return err
	//}
	//err = j.checkEnc(code, 72, 4, 0x2a0503f7)
	//if err != nil {
	//	return err
	//}

	j.ReleaseLibNetInfo.InnerSymbol = releaseFuncSym
	j.ReleaseLibNetInfo.FuncSymbol.OriginCode = code[0:4]
	return nil
}

func (j *JvmInjector) findDebugAddressInfoFromMem() (uint64, error) {
	funcAbsAddress := j.DebugLibNetInfo.FuncSymbol.SymAddr
	debugFuncSym := InnerSymbolInfo{}
	//debugFuncSym.FuncSymbol.SymAddr = funcAbsAddress
	//offset := sym.Value
	size := j.DebugLibNetInfo.FuncSymbol.SymSize
	code, err := j.readMemory(funcAbsAddress, size)
	//klog.Infoln(code, err)
	if err != nil {
		return 0, err
	}

	pc := uint64(0)
	preContext := InstInfo{}

	for pc < uint64(len(code)) {
		inst, err := arm64asm.Decode(code[pc:])
		if err != nil {
			klog.Infof("Decode error at offset 0x%x: %v\n", pc, err)
			pc++ // Skip this byte and try to decode again
			continue
		}
		//klog.Infof("Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, Inst)
		//klog.Infof("Decoded x86 instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.IntelSyntax(inst, 0, nil))
		//klog.Infof("Decoded GNU instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.GNUSyntax(Inst, 0, nil))
		currentData := InstInfo{
			PC:      pc,
			SymAddr: funcAbsAddress + pc,
			Inst:    inst,
		}
		if pc == 0 {
			j.DebugLibNetInfo.FuncSymbol.PC = currentData.PC
			j.DebugLibNetInfo.FuncSymbol.Inst = currentData.Inst
			j.DebugLibNetInfo.FuncSymbol.OriginInst = currentData.Inst
		}

		// IO_fd_fdID
		if pc == IO_FD_FDID_SYM_OFFSET {
			if inst.Op == arm64asm.ADD {
				if preContext.Inst.Op == arm64asm.ADRP && inst.Args[0].String() == arm64asm.X0.String() {
					debugFuncSym.IO_fd_fdID_ADD = currentData
					debugFuncSym.IO_fd_fdID_ADD.SymName = "<IO_fd_fdID ADD>(Debug)"
					debugFuncSym.IO_fd_fdID_ADD.OriginEnc = currentData.Inst.Enc
					debugFuncSym.IO_fd_fdID_ADD.TargetEnc = j.ReleaseLibNetInfo.InnerSymbol.IO_fd_fdID_ADD.Inst.Enc & uint32(0xFFFFF000)

					/*
						|31 immlo | 27-24 |23       immhi        5|4  Rd 0|
						 1  00   1  0000   0001 1000 0000 1110 011 0  0000
						 9          0      1    8    0    e    6      0
						( target- pc >> zero(12) )/4k
					*/
					debugFuncSym.IO_fd_fdID_ADRP = preContext
					debugFuncSym.IO_fd_fdID_ADRP.SymName = "<IO_fd_fdID ADRP>(Debug)"
					debugFuncSym.IO_fd_fdID_ADRP.OriginEnc = preContext.Inst.Enc

					releaseTarget := j.ReleaseLibNetInfo.InnerSymbol.IO_fd_fdID_ADRP.TargetAddr
					offset := (releaseTarget - preContext.SymAddr&0xFFFFFFFFFFFFF000) / (1 << 12)
					immhi := offset >> 2
					immlo := offset & 0x03
					decimal31_24 := (1 << 7) + (immlo << 5) + (1 << 4)
					targetEnc := (decimal31_24 << 24) | (immhi << 5)
					debugFuncSym.IO_fd_fdID_ADRP.TargetEnc = uint32(targetEnc)

					j.PreCheck.IoFdCheck = true
				} else {
					return 0, fmt.Errorf("The decoded instruction is not a ADRP or X0. inst:<%s>, arg:<%s>", inst.String(), inst.Args)
				}
			} else {
				return 0, fmt.Errorf("The decoded instruction is not a ADD. inst:<%s>, arg:<%s>", inst.String(), inst.Args)
			}
		}
		if pc == NET_SEND_SYM_OFFSET {
			debugFuncSym.NET_Send = currentData
			//klog.Infof("4 call Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, inst)
			//relOffset, ok := (inst.Args[0].(x86asm.Rel))
			klog.Infoln(inst)
			klog.Infoln(inst.Args)
			//if !ok {
			//	return 0, fmt.Errorf("The decoded instruction is not a Rel.")
			//}
			//targetAddress := currentData.SymAddr + uint64(inst.Len) + uint64(relOffset)
			//debugFuncSym.NET_Send.TargetAddr = targetAddress
			debugFuncSym.NET_Send.SymName = "<NET_Send>(Debug)"
			//klog.Infof("Find %s Target address: 0x%x\n", debugFuncSym.NET_Send.SymName, targetAddress)
			//
			//// 保存原始数据
			//debugFuncSym.NET_Send.OriginTargetAddr = targetAddress
			//debugFuncSym.NET_Send.OriginInst = currentData.Inst

			j.PreCheck.NetSendFuncCheck = true
		}

		preContext = InstInfo{
			PC:      pc,
			SymAddr: funcAbsAddress + pc,
			Inst:    inst,
		}
		pc += 4
	}
	j.DebugLibNetInfo.InnerSymbol = debugFuncSym
	return 0, nil
}

//func (j *JvmInjector) checkDebugFuncSymAfterChange() (uint64, error) {
//	funcAbsAddress := j.DebugLibNetInfo.FuncSymbol.SymAddr
//	debugFuncSym := InnerSymbolInfo{}
//	code, err := j.readMemory(funcAbsAddress, j.DebugLibNetInfo.FuncSymbol.SymSize)
//	if err != nil {
//		return 0, err
//	}
//
//	pc := uint64(0)
//	preContext := InstInfo{}
//
//	for pc < uint64(len(code)) {
//		inst, err := x86asm.Decode(code[pc:], 64)
//		if err != nil {
//			klog.Infof("Decode error at offset 0x%x: %v\n", pc, err)
//			pc++ // Skip this byte and try to decode again
//			continue
//		}
//		//klog.Infof("Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, Inst)
//		//klog.Infof("Decoded x86 instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.IntelSyntax(inst, 0, nil))
//		//klog.Infof("Decoded GNU instuction at 0x%x: %v\n", funcAbsAddress+pc, x86asm.GNUSyntax(Inst, 0, nil))
//		currentData := InstInfo{
//			PC:      pc,
//			SymAddr: funcAbsAddress + pc,
//			Inst:    inst,
//		}
//		if pc == NET_SEND_SYM_OFFSET {
//			klog.Infof("Instuction at 0x%x: %v\n", preContext.PC, preContext.Inst)
//			debugFuncSym.IO_fd_fdID = currentData
//			debugFuncSym.IO_fd_fdID.SymName = "<IO_fd_fdID>(Debug)"
//			// 计算目标地址
//			if currentData.Inst.Op == x86asm.MOV &&
//				len(currentData.Inst.Args) == 4 &&
//				currentData.Inst.Args[0] != nil &&
//				currentData.Inst.Args[0] == x86asm.RDX &&
//				currentData.Inst.Args[1] != nil {
//				if mem, ok := currentData.Inst.Args[1].(x86asm.Mem); ok && mem.Base == x86asm.RIP {
//					// 直接从Mem结构体中读取偏移
//					relOffset := mem.Disp
//					targetAddress := currentData.SymAddr + uint64(currentData.Inst.Len) + uint64(relOffset)
//					klog.Infof("Find %s Target address: 0x%x\n", debugFuncSym.IO_fd_fdID.SymName, targetAddress)
//					debugFuncSym.IO_fd_fdID.TargetAddr = targetAddress
//					//j.PreCheck.IoFdCheck = true
//
//					if targetAddress == j.ReleaseLibNetInfo.InnerSymbol.IO_fd_fdID.TargetAddr {
//						j.DebugLibNetInfo.InnerSymbol.IO_fd_fdID.TargetAddr = targetAddress
//						j.DebugLibNetInfo.InnerSymbol.IO_fd_fdID.Inst = currentData.Inst
//						j.AfterCheck.IoFdCheck = true
//						klog.Infoln("ok")
//					}
//				} else {
//					return 0, fmt.Errorf("The instruction does not use RIP-relative addressing.")
//				}
//			} else {
//				return 0, fmt.Errorf("The decoded instruction is not a MOV to RDX.")
//			}
//		}
//		if pc == NET_SEND_SYM_OFFSET {
//			debugFuncSym.NET_Send = currentData
//			//klog.Infoln(currentData.IntelInst)
//			//klog.Infof("4 call Decoded instuction at 0x%x: %v\n", funcAbsAddress+pc, inst)
//			relOffset, ok := (inst.Args[0].(x86asm.Rel))
//			if !ok {
//				return 0, fmt.Errorf("The decoded instruction is not a Rel.")
//			}
//			targetAddress := currentData.SymAddr + uint64(inst.Len) + uint64(relOffset)
//			debugFuncSym.NET_Send.TargetAddr = targetAddress
//			debugFuncSym.NET_Send.SymName = "<NET_Send>(Debug)"
//			klog.Infof("Find %s Target address: 0x%x\n", debugFuncSym.NET_Send.SymName, targetAddress)
//
//			if targetAddress == j.ReleaseLibNetInfo.InnerSymbol.NET_Send.TargetAddr {
//				j.DebugLibNetInfo.InnerSymbol.NET_Send.TargetAddr = targetAddress
//				j.DebugLibNetInfo.InnerSymbol.NET_Send.Inst = currentData.Inst
//				j.AfterCheck.NetSendFuncCheck = true
//			}
//		}
//
//		preContext = InstInfo{
//			PC:      pc,
//			SymAddr: funcAbsAddress + pc,
//			Inst:    inst,
//		}
//		pc += uint64(inst.Len)
//	}
//	return 0, nil
//}

func (j *JvmInjector) checkReleaseFuncSymAfterChange() error {
	funcAbsAddress := j.ReleaseLibNetInfo.FuncSymbol.SymAddr
	code, err := j.readMemory(funcAbsAddress, j.ReleaseLibNetInfo.FuncSymbol.SymSize)
	if err != nil {
		return fmt.Errorf("readMemory error in checkReleaseFuncSymAfterChange <%v>", err)
	}
	inst, err := x86asm.Decode(code[0:], 64)
	if err != nil {
		return fmt.Errorf("Decode error in checkReleaseFuncSymAfterChange <%v>", err)
	}
	if inst.Op != x86asm.JMP {
		return fmt.Errorf("The instruction does not JMP.")
	}
	relOffset, ok := inst.Args[0].(x86asm.Rel)
	if !ok {
		return fmt.Errorf("The instruction does not use RIP-relative addressing.")
	}
	// 验证target与Debug入口是否一致
	targetAddress := funcAbsAddress + uint64(inst.Len) + uint64(relOffset)
	if targetAddress != j.DebugLibNetInfo.FuncSymbol.SymAddr {
		return fmt.Errorf("Function entry jmp address does not match expectations.")
	}
	return nil
}

// readMemory 用于读取指定地址的内存数据
func (j *JvmInjector) readMemory(address uint64, size uint64) ([]byte, error) {
	memFile := fmt.Sprintf("/proc/%d/mem", j.Pid)
	file, err := os.Open(memFile)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	data := make([]byte, size)
	_, err = file.ReadAt(data, int64(address))
	if err != nil {
		return nil, err
	}

	return data, nil
}

// findLibraryBases 用于在 /proc/[pid]/maps 文件中查找库的所有基地址

func findLibraryBasesList(pid int, libraryName string, libPath string) ([]uint64, error) {
	mapsFile := fmt.Sprintf("/proc/%d/maps", pid)
	file, err := os.Open(mapsFile)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var bases []uint64
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.Contains(line, libraryName) && strings.Contains(line, libPath) {
			var start, end uint64
			fmt.Sscanf(line, "%x-%x", &start, &end)
			bases = append(bases, start)
		}
	}

	if len(bases) == 0 {
		return nil, fmt.Errorf("library %s not found", libraryName)
	}

	return bases, nil
}

func (j *JvmInjector) findLibBaseFromProcMaps(libName string) (uint64, string, error) {
	mapsFile := fmt.Sprintf("/proc/%d/maps", j.Pid)
	file, err := os.Open(mapsFile)
	if err != nil {
		return 0, "", err
	}
	defer file.Close()
	var start, end uint64
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.Contains(line, "/"+libName) {
			fmt.Sscanf(line, "%x-%x", &start, &end)
			fields := strings.Fields(line)
			if len(fields) > 5 {
				path := fields[5]
				if strings.HasSuffix(path, ".so") {
					klog.Infof("Found library %s\n", path)
					return start, path, nil
				}
			}
		}
	}

	return 1, "", fmt.Errorf("[findLibBaseFromProcMaps] library %s not found", libName)
}

//func (j *JvmInjector) getFunctionOffset(libPath, functionName string) (elf.Symbol, error) {
//	elfFile, err := elf.Open(libPath)
//	if err != nil {
//		return elf.Symbol{}, fmt.Errorf("failed to open ELF file: %v", err)
//	}
//	defer elfFile.Close()
//
//	symbols, err := elfFile.DynamicSymbols()
//	if err != nil {
//		return elf.Symbol{}, fmt.Errorf("failed to read dynamic symbols: %v", err)
//	}
//
//	for _, sym := range symbols {
//		if sym.Name == functionName {
//			return sym, nil
//		}
//	}
//
//	//textSection := elfFile.Section(".text")
//	//if textSection == nil {
//	//	klog.Infoln("textSection is null")
//	//	//return nil
//	//}
//	//textSectionData, err := textSection.Data()
//	//if err != nil {
//	//	klog.Infoln("textSectionData error is", err)
//	//	//return nil
//	//}
//	//textSectionLen := uint64(len(textSectionData) - 1)
//
//	return elf.Symbol{}, fmt.Errorf("function %s not found", functionName)
//}

//var PID string

//func (j *JvmInjector) findReleaseFuncContextFromLibPath() error {
//	// 获取release库的基地址
//	baseAddress, libPath, err := j.findLibBaseFromProcMaps(j.ReleaseLibNetInfo.LibName)
//	functionName := j.ReleaseLibNetInfo.FuncSymbol.SymName
//	j.ReleaseLibNetInfo.LibPath = libPath
//	libName := j.ReleaseLibNetInfo.LibName
//	if err != nil {
//		return fmt.Errorf("Error finding base addresses: %v", err)
//	}
//	klog.Infof("Base address of (%s)%s: %x\n", "", libName, baseAddress)
//
//	// 获取函数的偏移量
//	functionSym, err := j.getFunctionOffset(libPath, functionName)
//
//	// 计算函数的实际内存地址
//	j.ReleaseLibNetInfo.FuncSymbol.SymAddr = baseAddress + functionSym.Value
//	j.ReleaseLibNetInfo.FuncSymbol.SymSize = functionSym.Size
//	if err != nil {
//		return fmt.Errorf("Error getting function offset: %v", err)
//	}
//	klog.Infof("Actual memory address of %s at base 0x%x: 0x%x\n", functionName, baseAddress, j.ReleaseLibNetInfo.FuncSymbol.SymAddr)
//	err = j.findReleaseAddressInfoFromMem()
//
//	if err != nil {
//		return err
//	} else {
//		j.PreCheck.NeedInjectionCheck = true
//	}
//
//	return nil
//}

func (j *JvmInjector) InitProg() error {
	// 获取release库的基地址
	klog.Infof("[InitProg] find lib base from proc maps: %d|%s", j.Pid, j.ReleaseLibNetInfo.LibName)
	baseAddress, releaseSoFilePathInProc, mapFilesPath, deleted, err := FindLibBaseFromProcMaps(j.Pid, j.ReleaseLibNetInfo.LibName)
	//j.ReleaseLibNetInfo.LibPath = releaseSoFilePathInProc
	j.ReleaseLibNetInfo.FileDeleted = deleted
	j.ReleaseLibNetInfo.MapFile = mapFilesPath
	pJvmlibnetPhysicalPath := j.Rootfs + releaseSoFilePathInProc
	j.ReleaseLibNetInfo.LibPath = pJvmlibnetPhysicalPath

	if err != nil {
		klog.Errorf("[InitProg] Error finding base addresses: %v", err)
		return fmt.Errorf("[InitProg] Error finding base addresses: %v", err)
	}

	// jvm prog base
	//pJvmLibBaseDir := filepath.Dir(pJvmlibnetPhysicalPath)
	jvmLibBaseDir := filepath.Dir(releaseSoFilePathInProc)
	// proc maps load path

	debugSoFilePathInProc := filepath.Join(jvmLibBaseDir, j.DebugLibNetInfo.LibName)
	// Physical path
	debugSoFilePhysicalPath := filepath.Join(j.Rootfs, debugSoFilePathInProc)
	_, noFileErr := os.Stat(debugSoFilePhysicalPath)

	// find cwlibnet.so in proc maps
	var readDebugSoPathInMaps string
	_, readDebugSoPathInMaps, j.DebugLibNetInfo.MapFile, j.DebugLibNetInfo.FileDeleted, _ = FindLibBaseFromProcMaps(j.Pid, j.DebugLibNetInfo.LibName)
	j.DebugLibNetInfo.LibPath = debugSoFilePhysicalPath
	j.DebugLibNetInfo.ProcLoadPath = filepath.Join(jvmLibBaseDir, j.DebugLibNetInfo.LibName)
	// condition create
	pathFromProg := utils.GetDefaultLibsPath("jvm", j.DebugLibNetInfo.LibName)
	if noFileErr != nil && readDebugSoPathInMaps == "" && !j.DebugLibNetInfo.FileDeleted {
		err = CopyFileAndMatchPermissions(pathFromProg, debugSoFilePhysicalPath, pJvmlibnetPhysicalPath)
		klog.Infof("[src:%s],[target:%s],[perm:%s]", pathFromProg, debugSoFilePhysicalPath, pJvmlibnetPhysicalPath)
		if err != nil {
			klog.WithError(err).Errorf("[InitProg] Error copy.")
			return err
		}
	}

	functionName := j.ReleaseLibNetInfo.FuncSymbol.SymName
	//j.ReleaseLibNetInfo.LibPath = pJvmlibnetPhysicalPath

	klog.Infof("[inject] Base address of [%s]:[%x]", j.ReleaseLibNetInfo.LibName, baseAddress)

	// 获取函数的偏移量
	functionSym, err := GetFunctionOffset(pJvmlibnetPhysicalPath, functionName)

	// 计算函数的实际内存地址
	j.ReleaseLibNetInfo.FuncSymbol.SymAddr = baseAddress + functionSym.Value
	j.ReleaseLibNetInfo.FuncSymbol.SymSize = functionSym.Size
	if err != nil {
		klog.WithError(err).Errorf("Error getting function offset")
		return err
	}
	klog.Infof("[inject] Actual memory address of %s at base 0x%x: 0x%x", functionName, baseAddress, j.ReleaseLibNetInfo.FuncSymbol.SymAddr)
	if j.Uprobe.ELFPath == "" {
		if j.DebugLibNetInfo.FileDeleted {
			j.Uprobe.ELFPath = j.DebugLibNetInfo.MapFile
		} else {
			j.Uprobe.ELFPath = debugSoFilePhysicalPath
		}
	}
	err = j.findReleaseAddressInfoFromMem()
	if err != nil {
		klog.WithError(err).Errorf("[InitProg] Error copy.")
		return err
	} else {
		j.PreCheck.NeedInjectionCheck = true
	}

	// copy /NativeAgent
	nativePath := filepath.Join(j.Rootfs, "/tmp/NativeAgent")
	klog.Infof("[InitProg] init /tmp/NativeAgent.")
	if _, err := os.Stat(nativePath); err == nil {
		// 目标已存在，直接跳过
		klog.Infof("[InitProg] found /tmp/NativeAgent.")
		return nil
	}
	err = CopyFileAndMatchPermissions(utils.GetDefaultAgentsPath("NativeAgent"), nativePath, pJvmlibnetPhysicalPath)
	if err != nil {
		klog.WithError(err).Errorf("[InitProg] NativeAgent Error copy.")
	}

	return nil
}

func (j *JvmInjector) findDebugFuncContextFromLibPath() error {
	//libName := j.DebugLibNetInfo.LibName

	// 获取release库的基地址
	baseAddress, libPath, err := FindLibBaseByPathFromProcMaps(j.Pid, j.DebugLibNetInfo.ProcLoadPath)
	klog.Infof("[inject] debug base address of [%s] : %x", libPath, baseAddress)
	functionName := j.DebugLibNetInfo.FuncSymbol.SymName
	//j.DebugLibNetInfo.LibPath = libPath
	if err != nil {
		klog.WithError(err).Errorf("[inject] error.")
		return err
	}

	// 获取函数的偏移量
	functionSym, err := GetFunctionOffset(j.DebugLibNetInfo.LibPath, functionName)
	// 计算函数的实际内存地址
	j.DebugLibNetInfo.FuncSymbol.SymAddr = baseAddress + functionSym.Value
	j.DebugLibNetInfo.FuncSymbol.SymSize = functionSym.Size

	if err != nil {
		return fmt.Errorf("Error getting debug function:[%s] error: %v", functionName, err)
	}

	// 计算recode内存地址
	recodeFunctionSym, err := GetFunctionOffset(j.DebugLibNetInfo.LibPath, j.RecodeInfo.FuncSymbol.SymName)
	j.RecodeInfo.FuncSymbol.SymAddr = baseAddress + recodeFunctionSym.Value
	if err != nil {
		return fmt.Errorf("Error getting recode function:[%s] error: %v", j.RecodeInfo.FuncSymbol.SymName, err)
	}
	//klog.Infof("DEBUG Actual memory address of %s at base 0x%x: 0x%x\n", functionName, baseAddress, j.DebugLibNetInfo.FuncSymbol.SymAddr)
	//klog.Infof("DEBUG Actual memory address of %s at base 0x%x: 0x%x\n", j.RecodeInfo.FuncSymbol.SymName, baseAddress, j.RecodeInfo.FuncSymbol.SymAddr)

	//_, err = j.findDebugAddressInfoFromMem()
	//if err != nil {
	//	return err
	//}
	return nil
}

func printCodeData(data LibNetInfo) {
	klog.Infof("========FuncEnter <0x%x> \n", data.FuncSymbol.SymAddr)
	//klog.Infof("%s | CurrentAddr:<0x%x>\nOrigin-TargetAddr:<0x%x> | TargetAddr:<0x%x> \nOrigin-Enc:<0x%x> | TargetEnc:<0x%x> \n",
	//	data.InnerSymbol.IO_fd_fdID_ADRP.SymName,
	//	data.InnerSymbol.IO_fd_fdID_ADRP.SymAddr,
	//	data.InnerSymbol.IO_fd_fdID_ADRP.OriginTargetAddr,
	//	data.InnerSymbol.IO_fd_fdID_ADRP.TargetAddr,
	//	data.InnerSymbol.IO_fd_fdID_ADRP.OriginEnc,
	//	data.InnerSymbol.IO_fd_fdID_ADRP.TargetEnc)
	//klog.Infof("\n%s | CurrentAddr:<0x%x>\nOrigin-TargetAddr:<0x%x> | TargetAddr:<0x%x> \nOrigin-Enc:<0x%x> | TargetEnc:<0x%x> \n",
	//	data.InnerSymbol.IO_fd_fdID_ADD.SymName,
	//	data.InnerSymbol.IO_fd_fdID_ADD.SymAddr,
	//	data.InnerSymbol.IO_fd_fdID_ADD.OriginTargetAddr,
	//	data.InnerSymbol.IO_fd_fdID_ADD.TargetAddr,
	//	data.InnerSymbol.IO_fd_fdID_ADD.OriginEnc,
	//	data.InnerSymbol.IO_fd_fdID_ADD.TargetEnc)
	//klog.Infof("\n%s | CurrentAddr:<0x%x>\nOrigin-TargetAddr:<0x%x> | TargetAddr:<0x%x>\nOrigin-Inst:<%s> | Inst:<%s> \n",
	//	data.InnerSymbol.NET_Send.SymName,
	//	data.InnerSymbol.NET_Send.SymAddr,
	//	data.InnerSymbol.NET_Send.OriginTargetAddr,
	//	data.InnerSymbol.NET_Send.TargetAddr,
	//	arm64asm.GNUSyntax(data.InnerSymbol.NET_Send.OriginInst),
	//	arm64asm.GNUSyntax(data.InnerSymbol.NET_Send.Inst))
	klog.Infoln("========")
}

func (j *JvmInjector) jvmInjectLib() int {
	dll := C.CString(j.DebugLibNetInfo.ProcLoadPath) // 替换为实际的DLL路径
	rootfs := C.CString(j.Rootfs)                    // 替换为实际的DLL路径
	defer C.free(unsafe.Pointer(dll))                // 确保在使用完字符串后释放内存
	result := C.cw_inject_library(C.int(j.Pid), C.int(1), dll, rootfs)
	klog.Infof("[inject] [pid:%d][rootfs:%s][dll:%s][result:%d]\n", j.Pid, j.Rootfs, j.DebugLibNetInfo.ProcLoadPath, int(result))
	return int(result)
}

func (j *JvmInjector) validateAllPreCheck() bool {
	return j.PreCheck.NeedInjectionCheck && j.PreCheck.LoadingCheck
}

func (j *JvmInjector) validateAllModifyCheck() bool {
	return j.AfterCheck.IoFdCheck && j.AfterCheck.NetSendFuncCheck
}

/*修改部分*/
func readData(pid int, addr uintptr) (uint64, error) {
	var data uint64
	if _, err := syscall.PtracePeekData(pid, addr, (*[4]byte)(unsafe.Pointer(&data))[:]); err != nil {
		return 0, fmt.Errorf("ptrace PEEKDATA: %v", err)
	}
	return data, nil
}

func writeData(pid int, addr uintptr, data uint64) error {
	if _, err := syscall.PtracePokeData(pid, addr, (*[4]byte)(unsafe.Pointer(&data))[:]); err != nil {
		return fmt.Errorf("ptrace POKEDATA: %v", err)
	}
	return nil
}

func modifyIoFdTargetAddr(pid int, insertAddr, distAddr uintptr) error {
	newOffset := distAddr - (insertAddr + 7)
	targetAddr := insertAddr + 3
	// 获取目标地址处的数据
	originalData, err := readData(pid, targetAddr)
	if err != nil {
		return err
	}

	// 更新数据中的目标偏移
	updatedData := (originalData & 0xFFFFFFFF00000000) | uint64(newOffset&0xFFFFFFFF)
	err = writeData(pid, targetAddr, updatedData)
	if err != nil {
		return err
	}
	return nil
}

/*
set *(unsigned int*)($debug)  =  *(unsigned int*)($origin+56)
set *(unsigned int*)($debug+4)  =  *(unsigned int*)($origin+60)
set *(unsigned int*)($debug+8) = *(unsigned int*)($origin+64)
set  *(unsigned int*)($debug+12) = *(unsigned int*)($origin+68)

#   SUB     SP, SP, #0x080       // 将栈指针下移 8 字节，创建栈帧空间
set  *(unsigned int*)($debug+16) = 0xd10203ff
#   STR     W5, [SP]            // 将 W5 的值存储到栈顶
set  *(unsigned int*)($debug+20) = 0xb90003e5
#   LDR     W5, [SP]            // 从栈顶加载数据回 W5
set  *(unsigned int*)($debug+24) = 0xb94003e5
#   ADD     SP, SP, #0x080       // 恢复栈指针
set  *(unsigned int*)($debug+28) = 0x910203ff
#mov    w23, w5
set  *(unsigned int*)($debug+32) = *(unsigned int*)($origin+72)
# ret
set  *(unsigned int*)($debug+36) = 0xd65f03c0
*/
func buildCwNopEnc(pid int, nopAddr, originAddr uintptr) error {
	// 指令不为空则返回
	originalData, err := readData(pid, nopAddr)
	if err != nil {
		return err
	}
	klog.Infof("0x%016x\n", originalData) // 16个字符宽度，左边补0

	if originalData != 0xd503201f {
		return fmt.Errorf("The cw enc not nop <0x%016x>\n", originAddr)
	}
	/*
		sub sp, sp, #0x80      ; 分配栈空间
		str w5, [sp]           ; 保存 w5
		// nop
		ldr w5, [sp]           ; 恢复 w5
		add sp, sp, #0x80      ; 回收栈空间
	*/

	encodings := []uint64{
		0xd10203ff, // sub sp, sp, #0x80
		0xb90003e5, // str w5, [sp]
		NOP_ENC,    // nop
		0xb94003e5, // ldr w5, [sp]
		0x910203ff, // add sp, sp, #0x80
	}

	for i, enc := range encodings {
		if enc == NOP_ENC {
			continue
		}
		addr := nopAddr + uintptr(i*4)
		if err = setEnc(pid, addr, enc); err != nil {
			return err
		}
	}

	//err = setEnc(pid, nopAddr+0, 0xd10203ff)
	//if err != nil {
	//	return err
	//}
	//err = setEnc(pid, nopAddr+4, 0xb90003e5)
	//if err != nil {
	//	return err
	//}
	////nop
	//err = setEnc(pid, nopAddr+4+4, 0xd503201f)
	//if err != nil {
	//	return err
	//}
	//err = setEnc(pid, nopAddr+4+8, 0xb94003e5)
	//if err != nil {
	//	return err
	//}
	//
	//err = setEnc(pid, nopAddr+4+12, 0x910203ff)
	//if err != nil {
	//	return err
	//}

	var encLine = ChangeEncLen

	for i := 0; i < encLine; i++ {
		src := originAddr + SrcAddrOffset + 4*uintptr(i)
		dst := nopAddr + (4 + 16) + 4*uintptr(i)

		err = setEncByAddr(pid, dst, src)
		if err != nil {
			return err
		}
	}

	//err = setEncByAddr(pid, nopAddr+4+16, originAddr+56)
	//if err != nil {
	//	return err
	//}
	//err = setEncByAddr(pid, nopAddr+4+20, originAddr+60)
	//if err != nil {
	//	return err
	//}
	//err = setEncByAddr(pid, nopAddr+4+24, originAddr+64)
	//if err != nil {
	//	return err
	//}
	//err = setEncByAddr(pid, nopAddr+4+28, originAddr+68)
	//if err != nil {
	//	return err
	//}
	//
	//err = setEncByAddr(pid, nopAddr+4+32, originAddr+72)
	//if err != nil {
	//	return err
	//}
	//err = setEnc(pid, nopAddr+8 * 4, 0xd65f03c0)
	//if err != nil {
	//	return err
	//}

	return nil
}

func setEncByAddr(pid int, currentAddr, targetAddr uintptr) error {
	// 获取目标地址处的数据
	originalData, err := readData(pid, targetAddr)
	if err != nil {
		return err
	}
	// 更新数据中的目标偏移
	err = writeData(pid, currentAddr, originalData)
	if err != nil {
		return err
	}
	return nil
}

func setEnc(pid int, soAddr uintptr, enc uint64) error {
	// 更新数据中的目标偏移
	err := writeData(pid, soAddr, enc)
	if err != nil {
		return err
	}
	return nil
}

func encodeADRP(rd int, targetAddr, originAddr uint64) uint32 {
	targetPage := targetAddr >> 12
	originPage := originAddr >> 12
	imm := int64(targetPage) - int64(originPage) // offset in 4KB pages

	if imm < -(1<<20) || imm >= (1<<20) {
		panic("adrp offset out of range")
	}

	immlo := uint32(imm & 0x3)            // bits 30:29
	immhi := uint32((imm >> 2) & 0x7FFFF) // bits 23:5

	return (0x90000000 | (immlo << 29) | (immhi << 5) | uint32(rd))
}

func encodeADDLO12(rd int, targetAddr uint64) uint32 {
	imm12 := targetAddr & 0xFFF
	return (0x91000000 | uint32(imm12<<10) | uint32(rd<<5) | uint32(rd))
}

/*
set *(unsigned int*)($origin+56) = 0xf2889692
set *(unsigned int*)($origin+60) = 0xf2a363b2
set *(unsigned int*)($origin+64) = 0xf2dfff92
set *(unsigned int*)($origin+68) = 0xf2e00012
# blr x18
set *(unsigned int*)($origin+72) = 0xd63f0240
*/
func modifyOriginEnc(pid int, trampolineAddr uint64, origin uintptr, recode uintptr) error {
	var err error

	// Original 64-bit address
	//blrAddr := trampolineAddr
	// 拆分四段16位地址
	// Extract the 16-bit chunks
	//part1 := blrAddr & 0xFFFF         // Lower 16 bits
	//part2 := (blrAddr >> 16) & 0xFFFF // Next 16 bits
	//part3 := (blrAddr >> 32) & 0xFFFF // Upper 16 bits
	//part4 := (blrAddr >> 48) & 0xFFFF // MAXUpper 16 bits

	//changeParts := []struct {
	//	part   uint64
	//	offset uint64
	//	enc    uint64
	//}{
	//	{blrAddr & 0xFFFF, OFFSET_0, 0},              // Lower 16 bits
	//	{(blrAddr >> 16) & 0xFFFF, OFFSET_16_BIT, 0}, // Next 16 bits
	//	{(blrAddr >> 32) & 0xFFFF, OFFSET_32_BIT, 0}, // Upper 16 bits
	//	{(blrAddr >> 48) & 0xFFFF, OFFSET_48_BIT, 0}, // MAXUpper 16 bits
	//	{0, 0, BLR_X18},
	//}

	StepCount := ChangeEncLen

	originAddr := make([]uintptr, StepCount)
	for i := 0; i < StepCount; i++ {
		originAddr[i] = origin + SrcAddrOffset + uintptr(i*4)
	}

	changeParts := []struct {
		enc uint32
	}{
		{encodeADRP(18, trampolineAddr, uint64(originAddr[0]))}, // adrp x18, trampolineAddr
		{encodeADDLO12(18, trampolineAddr)},                     // add  x18, x18, :lo12:trampolineAddr
		{BLR_X18},                                               // blr  x18
	}

	//for i, p := range changeParts {
	//	if err := setEnc(pid, originInst[i], uint64(p.enc)); err != nil {
	//		return err
	//	}
	//}

	//callAddrOffset = 44
	//var addrSteps = []uintptr{
	//	origin + callAddrOffset,
	//	origin + callAddrOffset + 4,
	//	origin + callAddrOffset + 8,
	//	origin + callAddrOffset + 12,
	//	origin + callAddrOffset + 16,
	//}

	// Save Change
	for i := 0; i < StepCount; i++ {
		if err = setEncByAddr(pid, recode+uintptr(i*4), originAddr[i]); err != nil {
			return err
		}
	}

	// 修改原函数入口
	for i, p := range changeParts {
		if err = setEnc(pid, originAddr[i], uint64(p.enc)); err != nil {
			return err
		}
	}

	//for i, p := range changeParts {
	//	if p.enc == 0 {
	//		p.enc = buildArm64Enc(p.part, p.offset)
	//	}
	//	if err = setEnc(pid, originInst[i], p.enc); err != nil {
	//		return err
	//	}
	//}
	//  blr x18
	//if err = setEnc(pid, addrSteps[stepCount-1], BLR_X18); err != nil {
	//	return err
	//}

	//err = setEnc(pid, addrSteps[0], buildArm64Enc(part1, OFFSET_0))
	//if err != nil {
	//	return err
	//}
	//err = setEnc(pid, addrSteps[1], buildArm64Enc(part2, OFFSET_16_BIT))
	//if err != nil {
	//	return err
	//}
	//err = setEnc(pid, addrSteps[2], buildArm64Enc(part3, OFFSET_32_BIT))
	//if err != nil {
	//	return err
	//}
	//err = setEnc(pid, addrSteps[3], buildArm64Enc(part4, OFFSET_48_BIT))
	//if err != nil {
	//	return err
	//}

	klog.Infof("# blr x18 \nset *(unsigned int*)($origin+%d) = 0x%08x\n", PC_START+4*4, 0xD63F0240)
	return nil
}

func buildArm64Enc(imm16, hw uint64) uint64 {
	rd := 0x12 // x18
	fixed := 0x1e5
	// Combine all parts into a single 32-bit value
	result := uint64(rd<<0) | (imm16 << 5) | (hw << 21) | uint64(fixed<<23)
	klog.Infof("set *(unsigned int*)($origin+%d) = 0x%08x\n", PC_START+hw*4, result)
	return result
}

func modifyNetSetTargetAddr(pid int, sendDebugAddr, sendReleaseAddr uintptr) error {
	sendOffset := sendReleaseAddr - sendDebugAddr - 5

	// 读取原始数据
	alignedAddr := sendDebugAddr & ^(uintptr(unsafe.Sizeof(uintptr(0))) - 1)
	originalData, err := readData(pid, alignedAddr)
	if err != nil {
		return err
	}

	bytes := (*[8]byte)(unsafe.Pointer(&originalData))
	offsetLocation := (sendDebugAddr % uintptr(unsafe.Sizeof(uintptr(0)))) + 1
	*(*uint32)(unsafe.Pointer(&bytes[offsetLocation])) = uint32(sendOffset)

	err = writeData(pid, alignedAddr, originalData)
	if err != nil {
		return err
	}
	return nil
}

func modifyReleaseFuncEnter(pid int, originEnterAddr, debugEnterAddr uintptr) error {
	offset := debugEnterAddr - (originEnterAddr + 5)

	// 读取原始数据
	alignedAddr := originEnterAddr & ^(uintptr(unsafe.Sizeof(uintptr(0))) - 1)
	originalData, err := readData(pid, alignedAddr)
	if err != nil {
		return err
	}

	bytes := (*[8]byte)(unsafe.Pointer(&originalData))
	bytes[originEnterAddr%uintptr(unsafe.Sizeof(uintptr(0)))] = 0xe9
	*(*uint32)(unsafe.Pointer(&bytes[(originEnterAddr%uintptr(unsafe.Sizeof(uintptr(0))))+1])) = uint32(offset)
	err = writeData(pid, alignedAddr, originalData)
	if err != nil {
		return err
	}
	return nil
}

func restoreOriginalInstructions(pid int, addr uintptr, instructions []byte) error {
	alignedAddr := addr & ^(uintptr(unsafe.Sizeof(uintptr(0))) - 1)
	originalData, err := readData(pid, alignedAddr)
	if err != nil {
		return err
	}

	bytes := (*[8]byte)(unsafe.Pointer(&originalData))
	for i := 0; i < len(instructions); i++ {
		bytes[addr%uintptr(unsafe.Sizeof(uintptr(0)))+uintptr(i)] = instructions[i]
	}

	err = writeData(pid, alignedAddr, originalData)
	if err != nil {
		return err
	}
	return nil
}

//func main() {
//	flag.StringVar(&PID, "p", "", "PID")
//	flag.Parse()
//	pidStr := PID // 替换为目标进程的 PID
//	pid, err := strconv.Atoi(pidStr)
//	if err != nil {
//		log.Fatalf("Invalid PID: %v", err)
//	}
//	functionName := "Java_java_net_SocketOutputStream_socketWrite0"
//	libraryName := "libnet.so"
//
//	cwLibraryName := "cwlibnet.so"
//	cwLibraryPath := "/root/cwlibnet.so"
//
//	jvmInjector := &JvmInjector{
//		pid: pid,
//		ReleaseLibNetInfo: LibNetInfo{
//			libName: libraryName,
//			FuncSymbol: instInfo{
//				SymName: functionName,
//			},
//		},
//		DebugLibNetInfo: LibNetInfo{
//			// TODO 根据版本设置
//			libName: cwLibraryName,
//			// TODO 根据版本设置
//			libPath: cwLibraryPath,
//			FuncSymbol: instInfo{
//				SymName: functionName,
//			},
//		},
//	}
//
//	err = jvmInject(jvmInjector)
//	klog.Infoln(err)
//}

func JvmInject(jvmInjector *JvmInjector) error {
	jvmInjector.DebugLibNetInfo.FuncSymbol.SymName = "CW_Java_java_net_SocketOutputStream_socketWrite0"
	pid := jvmInjector.Pid

	var err error
	err = jvmInjector.InitProg()

	//err = jvmInjector.findReleaseFuncContextFromLibPath()

	//klog.Infoln(err)
	// Debug版本无需修改寄存器  TODO 直接使用原函数 需要在ebpf层适配
	// 已经加载so并指令修改正确的
	if jvmInjector.PreCheck.EbpfCanInjection {
		klog.Infoln("[inject] eBPF can injection.")
		return nil
	}

	if err != nil {
		klog.WithError(err).Errorf("[inject] Error message during release phase.")
		return err
	}

	// 原指令校验通过
	if !jvmInjector.PreCheck.NeedInjectionCheck {
		return err
	}

	printCodeData(jvmInjector.ReleaseLibNetInfo)
	klog.Info("[inject] Pre check suc.")
	_type, _, err := jvmInjector.findLibBaseFromProcMaps(jvmInjector.DebugLibNetInfo.LibName)
	if err != nil {
		// load so
		if _type == 1 {
			klog.Infoln("[inject] start load so.")
			resCode := jvmInjector.jvmInjectLib()
			if resCode == 0 {
				klog.Infof("[inject] load so successful. proc load path is [%s], file path in node is [%s]", jvmInjector.DebugLibNetInfo.ProcLoadPath, jvmInjector.DebugLibNetInfo.LibPath)
				jvmInjector.PreCheck.LoadingCheck = true
			} else {
				klog.Errorf("[inject] Failed load so. so path is [%s]", jvmInjector.DebugLibNetInfo.LibPath)
				return fmt.Errorf("[inject] Failed load so. code is %d so path is [%s]", resCode, jvmInjector.DebugLibNetInfo.LibPath)
			}
		}
	} else {
		klog.Infoln("[inject] so already loaded.")
		jvmInjector.PreCheck.LoadingCheck = true
	}

	if !jvmInjector.PreCheck.LoadingCheck {
		klog.Infof("Failed load so")
		return err
	}

	err = jvmInjector.findDebugFuncContextFromLibPath()
	if err != nil {
		klog.WithError(err).Errorf("[inject] Failed to find debug Func Context from libPath")
		return err
	}

	if !jvmInjector.validateAllPreCheck() {

		klog.Errorf("[inject] validateAllPreCheck failed : "+
			"NeedInjectionCheck=%v, LoadingCheck=%v",
			jvmInjector.PreCheck.NeedInjectionCheck,
			jvmInjector.PreCheck.LoadingCheck,
		)
		return err
	}

	//printCodeData(jvmInjector.DebugLibNetInfo)

	//// 修改
	debugFuncEnterAddr := uintptr(jvmInjector.DebugLibNetInfo.FuncSymbol.SymAddr)
	originFuncEnterAddr := uintptr(jvmInjector.ReleaseLibNetInfo.FuncSymbol.SymAddr)
	recodeFuncEnterAddr := uintptr(jvmInjector.RecodeInfo.FuncSymbol.SymAddr)
	//klog.Infof("<0x%x> -> <0x%x>\n", originFuncEnterAddr, debugFuncEnterAddr)
	//klog.Infof("<0x%x> -> <0x%x>\n", debugIoFdAddr, ioFdReleaseTargetAddr)
	//klog.Infof("<0x%x> -> <0x%x>\n", debugNetSendAddr, netSendReleaseTargetAddr)
	//
	// 附加到目标进程
	klog.Infof("[inject] %d attach", pid)

	err = syscall.PtraceAttach(pid)
	if err != nil {
		klog.Infof("ptrace ATTACH: %v", err)
	}
	//
	// 等待目标进程停止
	klog.Infof("[inject] %d attach wait.", pid)
	if _, err := syscall.Wait4(pid, nil, 0, nil); err != nil {
		klog.WithError(err).Errorf("[inject] Wait4 error")
		return err
	}
	// 保存原始指令并扩充新指令
	klog.Infof("[inject] %d build cw enc", pid)
	err = buildCwNopEnc(pid, debugFuncEnterAddr, originFuncEnterAddr)
	if err != nil {
		klog.Errorln(err)
		return err
	}

	//
	//err = modifyNetSetTargetAddr(pid, debugNetSendAddr, netSendReleaseTargetAddr)
	//klog.Infoln(err)
	//if err != nil {
	//	klog.Infoln(err)
	//	return err
	//}
	// todo 二次效验 读取并验证地址
	//_, err = jvmInjector.checkDebugFuncSymAfterChange()
	//printCodeData(jvmInjector.ReleaseLibNetInfo)
	//printCodeData(jvmInjector.DebugLibNetInfo)
	//
	//// todo 效验目标函数内地址是否与预期一致
	//if !jvmInjector.validateAllModifyCheck() && err == nil {
	//	return err
	//}

	//变更原指令 长跳转到新地址 保存到recode
	klog.Infof("[inject] %d modifyNetSetTargetAddr", pid)
	err = modifyOriginEnc(pid, uint64(debugFuncEnterAddr), originFuncEnterAddr, recodeFuncEnterAddr)

	//// 更新函数入口
	//err = modifyReleaseFuncEnter(pid, originFuncEnterAddr, debugFuncEnterAddr)
	//if err != nil {
	//	klog.Infoln(err)
	//	return err
	//}
	//// 校验jmp地址修改正确
	//err = jvmInjector.checkReleaseFuncSymAfterChange()
	//if err != nil {
	//	klog.Infoln(err)
	//	if len(jvmInjector.ReleaseLibNetInfo.FuncSymbol.OriginCode) == 5 {
	//		err = restoreOriginalInstructions(pid, originFuncEnterAddr, jvmInjector.ReleaseLibNetInfo.FuncSymbol.OriginCode)
	//		if err != nil {
	//			klog.Infoln(err)
	//			return err
	//		}
	//	}
	//}
	//
	// 恢复执行
	klog.Infof("[inject] %d Detach", pid)
	if err = syscall.PtraceDetach(pid); err != nil {
		klog.Errorf("ptrace DETACH: %v", err)
		return err
	}
	return nil
}
