...

Source file src/runtime/plugin.go

     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	

View as plain text