github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/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{}, 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 }