github.com/mangodowner/go-gm@v0.0.0-20180818020936-8baa2bd4408c/src/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{}, 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 { 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 := funcInfo{(*_func)(unsafe.Pointer(&md.pclntable[md.ftab[i].funcoff])), md} 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.valid() { 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 }