github.com/dearplain/goloader@v0.0.0-20190107071432-2b1e47d74273/examples/loader/loader.go (about)

     1  package main
     2  
     3  import (
     4  	"cmd/objfile/goobj"
     5  	"flag"
     6  	"fmt"
     7  	"net/http"
     8  	"os"
     9  	"runtime"
    10  	"strings"
    11  	"sync"
    12  	"time"
    13  	"unsafe"
    14  
    15  	"github.com/dearplain/goloader"
    16  	"github.com/kr/pretty"
    17  )
    18  
    19  func mustOK(err error) {
    20  	if err != nil {
    21  		panic(err)
    22  	}
    23  }
    24  
    25  type arrayFlags struct {
    26  	File    []string
    27  	PkgPath []string
    28  }
    29  
    30  func (i *arrayFlags) String() string {
    31  	return "my string representation"
    32  }
    33  
    34  func (i *arrayFlags) Set(value string) error {
    35  	s := strings.Split(value, ":")
    36  	i.File = append(i.File, s[0])
    37  	var path string
    38  	if len(s) > 1 {
    39  		path = s[1]
    40  	}
    41  	i.PkgPath = append(i.PkgPath, path)
    42  	return nil
    43  }
    44  
    45  func main() {
    46  
    47  	var files arrayFlags
    48  	flag.Var(&files, "o", "load go object file")
    49  	var pkgpath = flag.String("p", "", "package path")
    50  	var parseFile = flag.String("parse", "", "parse go object file")
    51  	var run = flag.String("run", "main.main", "run function")
    52  	var times = flag.Int("times", 1, "run count")
    53  
    54  	flag.Parse()
    55  
    56  	if *parseFile != "" {
    57  		parse(parseFile, pkgpath)
    58  		return
    59  	}
    60  
    61  	if len(files.File) == 0 {
    62  		flag.PrintDefaults()
    63  		return
    64  	}
    65  
    66  	symPtr := make(map[string]uintptr)
    67  	goloader.RegSymbol(symPtr)
    68  
    69  	goloader.RegTypes(symPtr, time.Duration(0), time.Unix(0, 0))
    70  	goloader.RegTypes(symPtr, runtime.LockOSThread)
    71  	// most of time you don't need to register function, but if loader complain about it, you have to.
    72  	goloader.RegTypes(symPtr, http.ListenAndServe, http.Dir("/"),
    73  		http.Handler(http.FileServer(http.Dir("/"))), http.FileServer, http.HandleFunc,
    74  		&http.Request{})
    75  	w := sync.WaitGroup{}
    76  	rw := sync.RWMutex{}
    77  	goloader.RegTypes(symPtr, &w, w.Wait, &rw)
    78  
    79  	reloc, err := goloader.ReadObjs(files.File, files.PkgPath)
    80  	if err != nil {
    81  		fmt.Println(err)
    82  	}
    83  
    84  	var mmapByte []byte
    85  	for i := 0; i < *times; i++ {
    86  		codeModule, err := goloader.Load(reloc, symPtr)
    87  		if err != nil {
    88  			fmt.Println("Load error:", err)
    89  		}
    90  		runFuncPtr := codeModule.Syms[*run]
    91  		funcPtrContainer := (uintptr)(unsafe.Pointer(&runFuncPtr))
    92  		runFunc := *(*func())(unsafe.Pointer(&funcPtrContainer))
    93  		runFunc()
    94  		codeModule.Unload()
    95  
    96  		// a strict test, try to make mmap random
    97  		if mmapByte == nil {
    98  			mmapByte, err = goloader.Mmap(1024)
    99  			if err != nil {
   100  				fmt.Println(err)
   101  			}
   102  			b := make([]byte, 1024)
   103  			copy(mmapByte, b) // reset all bytes
   104  		} else {
   105  			goloader.Munmap(mmapByte)
   106  			mmapByte = nil
   107  		}
   108  	}
   109  
   110  }
   111  
   112  func parse(file, pkgpath *string) {
   113  
   114  	if *file == "" {
   115  		flag.PrintDefaults()
   116  		return
   117  	}
   118  
   119  	f, err := os.Open(*file)
   120  	if err != nil {
   121  		fmt.Printf("%# v\n", err)
   122  		return
   123  	}
   124  	obj, err := goobj.Parse(f, *pkgpath)
   125  	pretty.Printf("%# v\n", obj)
   126  	f.Close()
   127  	if err != nil {
   128  		fmt.Printf("error reading %s: %v\n", *file, err)
   129  		return
   130  	}
   131  }