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.
5 // +build linux,cgo darwin,cgo
10 #cgo linux LDFLAGS: -ldl
18 static uintptr_t pluginOpen(const char* path, char** err) {
19 void* h = dlopen(path, RTLD_NOW|RTLD_GLOBAL);
21 *err = (char*)dlerror();
26 static void* pluginLookup(uintptr_t h, const char* name, char** err) {
27 void* r = dlsym((void*)h, name);
29 *err = (char*)dlerror();
42 func open(name
string) (*Plugin
, error
) {
43 cPath
:= (*C
.char
)(C
.malloc(C
.PATH_MAX
+ 1))
44 defer C
.free(unsafe
.Pointer(cPath
))
46 cRelName
:= C
.CString(name
)
47 defer C
.free(unsafe
.Pointer(cRelName
))
48 if C
.realpath(cRelName
, cPath
) == nil {
49 return nil, errors
.New("plugin.Open(" + name
+ "): realpath failed")
52 filepath
:= C
.GoString(cPath
)
55 if p
:= plugins
[filepath
]; p
!= nil {
61 h
:= C
.pluginOpen(cPath
, &cErr
)
64 return nil, errors
.New("plugin.Open: " + C
.GoString(cErr
))
66 // TODO(crawshaw): look for plugin note, confirm it is a Go plugin
67 // and it was built with the correct toolchain.
68 if len(name
) > 3 && name
[len(name
)-3:] == ".so" {
69 name
= name
[:len(name
)-3]
72 pluginpath
, syms
, mismatchpkg
:= lastmoduleinit()
73 if mismatchpkg
!= "" {
75 return nil, errors
.New("plugin.Open: plugin was built with a different version of package " + mismatchpkg
)
78 plugins
= make(map[string]*Plugin
)
80 // This function can be called from the init function of a plugin.
81 // Drop a placeholder in the map so subsequent opens can wait on it.
83 pluginpath
: pluginpath
,
84 loaded
: make(chan struct{}),
90 initStr
:= C
.CString(pluginpath
+ ".init")
91 initFuncPC
:= C
.pluginLookup(h
, initStr
, &cErr
)
92 C
.free(unsafe
.Pointer(initStr
))
93 if initFuncPC
!= nil {
94 initFuncP
:= &initFuncPC
95 initFunc
:= *(*func())(unsafe
.Pointer(&initFuncP
))
99 // Fill out the value of each plugin symbol.
100 for symName
, sym
:= range syms
{
101 isFunc
:= symName
[0] == '.'
103 delete(syms
, symName
)
104 symName
= symName
[1:]
107 cname
:= C
.CString(pluginpath
+ "." + symName
)
108 p
:= C
.pluginLookup(h
, cname
, &cErr
)
109 C
.free(unsafe
.Pointer(cname
))
111 return nil, errors
.New("plugin.Open: could not find symbol " + symName
+ ": " + C
.GoString(cErr
))
113 valp
:= (*[2]unsafe
.Pointer
)(unsafe
.Pointer(&sym
))
115 (*valp
)[1] = unsafe
.Pointer(&p
)
125 func lookup(p
*Plugin
, symName
string) (Symbol
, error
) {
126 if s
:= p
.syms
[symName
]; s
!= nil {
129 return nil, errors
.New("plugin: symbol " + symName
+ " not found in plugin " + p
.pluginpath
)
134 plugins
map[string]*Plugin
137 // lastmoduleinit is defined in package runtime
138 func lastmoduleinit() (pluginpath
string, syms
map[string]interface{}, mismatchpkg
string)