...
Run Format

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{}, 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	}
   131	

View as plain text