gosh/interceptor/dl.go

106 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package interceptor
import (
"fmt"
"path/filepath"
"reflect"
"strings"
"github.com/ebitengine/purego"
)
type funcType struct {
ParamTypes []string
ReturnTypes []string
}
var typeMap = map[string]reflect.Type{
"int": reflect.TypeOf(int(0)),
"int32": reflect.TypeOf(int32(0)),
"int64": reflect.TypeOf(int64(0)),
"uint": reflect.TypeOf(uint(0)),
"float32": reflect.TypeOf(float32(0)),
"float64": reflect.TypeOf(float64(0)),
"string": reflect.TypeOf(""),
"bool": reflect.TypeOf(false),
"void": nil, // 用于表示无返回值
}
func makeFuncType(paramTypes, returnTypes []string) (reflect.Type, error) {
var in, out []reflect.Type
// 参数类型
for _, t := range paramTypes {
rt, ok := typeMap[t]
if !ok {
return nil, fmt.Errorf("unknown parameter type: %s", t)
}
in = append(in, rt)
}
// 返回值类型
for _, t := range returnTypes {
if t == "void" {
continue // 无返回值
}
rt, ok := typeMap[t]
if !ok {
return nil, fmt.Errorf("unknown return type: %s", t)
}
out = append(out, rt)
}
return reflect.FuncOf(in, out, false), nil
}
func (a *Ankointerceptor) loadLibrary(libPath string, libFuncMap map[string]funcType) interface{} {
libName := filepath.Base(libPath)
libName = strings.TrimSuffix(libName, filepath.Ext(".dll"))
// 是不是so文件libName里边是否包含.so
if strings.Contains(libName, ".so") {
soIndex := strings.Index(libName, ".so")
libName = libName[0:soIndex]
}
libName = strings.TrimPrefix(libName, "lib")
if _, ok := a.libMap[libName]; ok {
return a.libMap[libName] // 如果已经加载过,直接返回
}
lib, err := purego.Dlopen(libPath, purego.RTLD_LAZY)
if err != nil {
panic("Load library error")
}
a.libhabdles = append(a.libhabdles, lib)
fnmap := make(map[string]interface{})
fileds := make([]reflect.StructField, 0, len(fnmap))
for name, types := range libFuncMap {
ft, err := makeFuncType(types.ParamTypes, types.ReturnTypes)
if err != nil {
panic(err)
}
fn := reflect.New(ft).Elem().Addr().Interface()
purego.RegisterLibFunc(fn, lib, name)
//Get ft 指针类型
// ftp := reflect.PtrTo(ft)
fileds = append(fileds, reflect.StructField{
Name: name,
Type: ft,
})
fnmap[name] = fn
}
// 根据fnmap构建一个匿名结构体结构体的字段名为函数名字段值为函数指针
libstruct := reflect.StructOf(fileds)
// 创建一个匿名结构体的实例
libinstance := reflect.New(libstruct).Elem()
for name, fn := range fnmap {
// 将函数指针指向的函数设置到结构体实例的对应字段中
libinstance.FieldByName(name).Set(reflect.ValueOf(fn).Elem())
// libinstance.FieldByName(name).Set()
}
a.libMap[libName] = libinstance.Interface()
return a.libMap[libName]
}