github.com/fenixara/go@v0.0.0-20170127160404-96ea0918e670/src/runtime/plugin.go (about)

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package runtime
     6  
     7  import "unsafe"
     8  
     9  //go:linkname plugin_lastmoduleinit plugin.lastmoduleinit
    10  func plugin_lastmoduleinit() (path string, syms map[string]interface{}, mismatchpkg string) {
    11  	md := firstmoduledata.next
    12  	if md == nil {
    13  		throw("runtime: no plugin module data")
    14  	}
    15  	for md.next != nil {
    16  		md = md.next
    17  	}
    18  	if md.typemap != nil {
    19  		throw("runtime: plugin already initialized")
    20  	}
    21  
    22  	for _, pmd := range activeModules() {
    23  		if pmd.pluginpath == md.pluginpath {
    24  			println("plugin: plugin", md.pluginpath, "already loaded")
    25  			throw("plugin: plugin already loaded")
    26  		}
    27  
    28  		if inRange(pmd.text, pmd.etext, md.text, md.etext) ||
    29  			inRange(pmd.bss, pmd.ebss, md.bss, md.ebss) ||
    30  			inRange(pmd.data, pmd.edata, md.data, md.edata) ||
    31  			inRange(pmd.types, pmd.etypes, md.types, md.etypes) {
    32  			println("plugin: new module data overlaps with previous moduledata")
    33  			println("\tpmd.text-etext=", hex(pmd.text), "-", hex(pmd.etext))
    34  			println("\tpmd.bss-ebss=", hex(pmd.bss), "-", hex(pmd.ebss))
    35  			println("\tpmd.data-edata=", hex(pmd.data), "-", hex(pmd.edata))
    36  			println("\tpmd.types-etypes=", hex(pmd.types), "-", hex(pmd.etypes))
    37  			println("\tmd.text-etext=", hex(md.text), "-", hex(md.etext))
    38  			println("\tmd.bss-ebss=", hex(md.bss), "-", hex(md.ebss))
    39  			println("\tmd.data-edata=", hex(md.data), "-", hex(md.edata))
    40  			println("\tmd.types-etypes=", hex(md.types), "-", hex(md.etypes))
    41  			throw("plugin: new module data overlaps with previous moduledata")
    42  		}
    43  	}
    44  	for _, pkghash := range md.pkghashes {
    45  		if pkghash.linktimehash != *pkghash.runtimehash {
    46  			return "", nil, pkghash.modulename
    47  		}
    48  	}
    49  
    50  	// Initialize the freshly loaded module.
    51  	modulesinit()
    52  	typelinksinit()
    53  
    54  	pluginftabverify(md)
    55  	moduledataverify1(md)
    56  
    57  	lock(&ifaceLock)
    58  	for _, i := range md.itablinks {
    59  		if i.inhash == 0 {
    60  			additab(i, true, false)
    61  		}
    62  	}
    63  	unlock(&ifaceLock)
    64  
    65  	// Build a map of symbol names to symbols. Here in the runtime
    66  	// we fill out the first word of the interface, the type. We
    67  	// pass these zero value interfaces to the plugin package,
    68  	// where the symbol value is filled in (usually via cgo).
    69  	//
    70  	// Because functions are handled specially in the plugin package,
    71  	// function symbol names are prefixed here with '.' to avoid
    72  	// a dependency on the reflect package.
    73  	syms = make(map[string]interface{}, len(md.ptab))
    74  	for _, ptab := range md.ptab {
    75  		symName := resolveNameOff(unsafe.Pointer(md.types), ptab.name)
    76  		t := (*_type)(unsafe.Pointer(md.types)).typeOff(ptab.typ)
    77  		var val interface{}
    78  		valp := (*[2]unsafe.Pointer)(unsafe.Pointer(&val))
    79  		(*valp)[0] = unsafe.Pointer(t)
    80  
    81  		name := symName.name()
    82  		if t.kind&kindMask == kindFunc {
    83  			name = "." + name
    84  		}
    85  		syms[name] = val
    86  	}
    87  	return md.pluginpath, syms, ""
    88  }
    89  
    90  func pluginftabverify(md *moduledata) {
    91  	badtable := false
    92  	for i := 0; i < len(md.ftab); i++ {
    93  		entry := md.ftab[i].entry
    94  		if md.minpc <= entry && entry <= md.maxpc {
    95  			continue
    96  		}
    97  
    98  		f := (*_func)(unsafe.Pointer(&md.pclntable[md.ftab[i].funcoff]))
    99  		name := funcname(f)
   100  
   101  		// A common bug is f.entry has a relocation to a duplicate
   102  		// function symbol, meaning if we search for its PC we get
   103  		// a valid entry with a name that is useful for debugging.
   104  		name2 := "none"
   105  		entry2 := uintptr(0)
   106  		f2 := findfunc(entry)
   107  		if f2 != nil {
   108  			name2 = funcname(f2)
   109  			entry2 = f2.entry
   110  		}
   111  		badtable = true
   112  		println("ftab entry outside pc range: ", hex(entry), "/", hex(entry2), ": ", name, "/", name2)
   113  	}
   114  	if badtable {
   115  		throw("runtime: plugin has bad symbol table")
   116  	}
   117  }
   118  
   119  // inRange reports whether v0 or v1 are in the range [r0, r1].
   120  func inRange(r0, r1, v0, v1 uintptr) bool {
   121  	return (v0 >= r0 && v0 <= r1) || (v1 >= r0 && v1 <= r1)
   122  }
   123  
   124  // A ptabEntry is generated by the compiler for each exported function
   125  // and global variable in the main package of a plugin. It is used to
   126  // initialize the plugin module's symbol map.
   127  type ptabEntry struct {
   128  	name nameOff
   129  	typ  typeOff
   130  }