...

Source file src/runtime/plugin.go

Documentation: 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", hex(entry), "/", hex(entry2), ": ",
	 119  			name, "/", name2, "outside pc range:[", hex(md.minpc), ",", hex(md.maxpc), "], modulename=", md.modulename, ", pluginpath=", md.pluginpath)
	 120  	}
	 121  	if badtable {
	 122  		throw("runtime: plugin has bad symbol table")
	 123  	}
	 124  }
	 125  
	 126  // inRange reports whether v0 or v1 are in the range [r0, r1].
	 127  func inRange(r0, r1, v0, v1 uintptr) bool {
	 128  	return (v0 >= r0 && v0 <= r1) || (v1 >= r0 && v1 <= r1)
	 129  }
	 130  
	 131  // A ptabEntry is generated by the compiler for each exported function
	 132  // and global variable in the main package of a plugin. It is used to
	 133  // initialize the plugin module's symbol map.
	 134  type ptabEntry struct {
	 135  	name nameOff
	 136  	typ	typeOff
	 137  }
	 138  

View as plain text