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