github.com/lsg2020/gort@v0.0.0-20220515072951-7a7794baa036/gort_functions.go (about)

     1  package gort
     2  
     3  import (
     4  	"debug/dwarf"
     5  	"fmt"
     6  	"reflect"
     7  	"unsafe"
     8  
     9  	"github.com/go-delve/delve/pkg/proc"
    10  )
    11  
    12  func (d *DwarfRT) ForeachFunc(f func(name string, pc uint64)) error {
    13  	if err := d.check(); err != nil {
    14  		return err
    15  	}
    16  
    17  	for _, function := range d.bi.Functions {
    18  		if function.Entry != 0 {
    19  			f(function.Name, function.Entry)
    20  		}
    21  	}
    22  	return nil
    23  }
    24  
    25  func (d *DwarfRT) FindFuncEntry(name string) (*proc.Function, error) {
    26  	if err := d.check(); err != nil {
    27  		return nil, err
    28  	}
    29  
    30  	f, err := d.findFunc(name)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  	return f, nil
    35  }
    36  
    37  func (d *DwarfRT) FindFuncPc(name string) (uint64, error) {
    38  	if err := d.check(); err != nil {
    39  		return 0, err
    40  	}
    41  
    42  	f, err := d.findFunc(name)
    43  	if err != nil {
    44  		return 0, err
    45  	}
    46  	return f.Entry, nil
    47  }
    48  
    49  func (d *DwarfRT) FindFuncType(name string, variadic bool) (reflect.Type, error) {
    50  	if err := d.check(); err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	f, err := d.findFunc(name)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	inTyps, outTyps, _, _, err := d.getFunctionArgTypes(f)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  
    63  	ftyp := reflect.FuncOf(inTyps, outTyps, variadic)
    64  	return ftyp, nil
    65  }
    66  
    67  func (d *DwarfRT) FindFunc(name string, variadic bool) (reflect.Value, error) {
    68  	pc, err := d.FindFuncPc(name)
    69  	if err != nil {
    70  		return reflect.Value{}, err
    71  	}
    72  	ftyp, err := d.FindFuncType(name, variadic)
    73  	if err != nil {
    74  		return reflect.Value{}, err
    75  	}
    76  
    77  	newFunc := CreateFuncForCodePtr(ftyp, pc)
    78  	return newFunc, nil
    79  }
    80  
    81  func (d *DwarfRT) CallFunc(name string, variadic bool, args []reflect.Value) ([]reflect.Value, error) {
    82  	if err := d.check(); err != nil {
    83  		return nil, err
    84  	}
    85  	f, err := d.findFunc(name)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	inTyps, outTyps, inNames, _, err := d.getFunctionArgTypes(f)
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  
    95  	ftyp := reflect.FuncOf(inTyps, outTyps, variadic)
    96  	newFunc := CreateFuncForCodePtr(ftyp, f.Entry)
    97  
    98  	getInTyp := func(i int) (reflect.Type, string) {
    99  		if len(inTyps) <= 0 {
   100  			return nil, ""
   101  		}
   102  		if i < len(inTyps)-1 {
   103  			return inTyps[i], inNames[i]
   104  		}
   105  		if variadic {
   106  			return inTyps[len(inTyps)-1].Elem(), inNames[len(inNames)-1]
   107  		}
   108  		if i < len(inTyps) {
   109  			return inTyps[i], inNames[i]
   110  		}
   111  		return nil, ""
   112  	}
   113  
   114  	for i, arg := range args {
   115  		inTyp, inName := getInTyp(i)
   116  		if inTyp == nil {
   117  			return nil, fmt.Errorf("len mismatch %d", i)
   118  		}
   119  
   120  		if !arg.Type().AssignableTo(inTyp) {
   121  			return nil, fmt.Errorf("type mismatch %d:%s", i, inName)
   122  		}
   123  	}
   124  
   125  	out := newFunc.Call(args)
   126  	return out, nil
   127  }
   128  
   129  func (d *DwarfRT) findFunc(name string) (*proc.Function, error) {
   130  	for i := len(d.bi.Functions) - 1; i >= 0; i-- {
   131  		if d.bi.Functions[i].Name == name {
   132  			if d.bi.Functions[i].Entry != 0 {
   133  				return &(d.bi.Functions[i]), nil
   134  			}
   135  			return nil, ErrNotFound
   136  		}
   137  	}
   138  	return nil, ErrNotFound
   139  }
   140  
   141  func (d *DwarfRT) getFunctionArgTypes(f *proc.Function) ([]reflect.Type, []reflect.Type, []string, []string, error) {
   142  	rOffset := reflect.ValueOf(f).Elem().FieldByName("offset")
   143  	rCU := reflect.ValueOf(f).Elem().FieldByName("cu")
   144  	if !rOffset.IsValid() || !rCU.IsValid() {
   145  		return nil, nil, nil, nil, ErrNotSupport
   146  	}
   147  	rImage := rCU.Elem().FieldByName("image")
   148  	if !rImage.IsValid() {
   149  		return nil, nil, nil, nil, ErrNotSupport
   150  	}
   151  	rDwarf := rImage.Elem().FieldByName("dwarf")
   152  	if !rDwarf.IsValid() {
   153  		return nil, nil, nil, nil, ErrNotSupport
   154  	}
   155  	image := (*proc.Image)(unsafe.Pointer(rImage.Pointer()))
   156  	dwarfData := (*dwarf.Data)(unsafe.Pointer(rDwarf.Pointer()))
   157  
   158  	reader := image.DwarfReader()
   159  	reader.Seek(dwarf.Offset(rOffset.Uint()))
   160  	entry, err := reader.Next()
   161  	if err != nil || entry == nil || entry.Tag != dwarf.TagSubprogram {
   162  		return nil, nil, nil, nil, fmt.Errorf("get function arg types not found %s", f.Name)
   163  	}
   164  	name, ok := entry.Val(dwarf.AttrName).(string)
   165  	if !ok || f.Name != name {
   166  		return nil, nil, nil, nil, fmt.Errorf("get function arg types name err %s:%s", f.Name, name)
   167  	}
   168  
   169  	var inTyps []reflect.Type
   170  	var outTyps []reflect.Type
   171  	var inNames []string
   172  	var outNames []string
   173  
   174  	for {
   175  		child, err := reader.Next()
   176  		if err != nil {
   177  			return nil, nil, nil, nil, fmt.Errorf("get function arg types reader err %s:%s", f.Name, err.Error())
   178  		}
   179  		if child == nil || child.Tag == 0 {
   180  			break
   181  		}
   182  		if child.Tag != dwarf.TagFormalParameter {
   183  			continue
   184  		}
   185  
   186  		dtyp, err := entryType(dwarfData, child)
   187  		if err != nil {
   188  			return nil, nil, nil, nil, fmt.Errorf("get function arg types type err %s:%s", f.Name, err.Error())
   189  		}
   190  		dname := dwarfTypeName(dtyp)
   191  		rtyp, err := d.FindType(dname)
   192  		if err != nil {
   193  			return nil, nil, nil, nil, fmt.Errorf("get function arg types type err %s:%s", f.Name, err.Error())
   194  		}
   195  
   196  		isret, _ := child.Val(dwarf.AttrVarParam).(bool)
   197  		if isret {
   198  			outTyps = append(outTyps, rtyp)
   199  			outNames = append(outNames, dname)
   200  		} else {
   201  			inTyps = append(inTyps, rtyp)
   202  			inNames = append(inNames, dname)
   203  		}
   204  	}
   205  	return inTyps, outTyps, inNames, outNames, nil
   206  }