mirror of https://github.com/EasyDarwin/EasyDarwin
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
261 lines
6.9 KiB
261 lines
6.9 KiB
// Copyright 2011 The Go Authors. All rights reserved. |
|
// Use of this source code is governed by a BSD-style |
|
// license that can be found in the LICENSE file. |
|
|
|
package unix |
|
|
|
import ( |
|
"sync" |
|
"sync/atomic" |
|
"syscall" |
|
"unsafe" |
|
) |
|
|
|
// soError describes reasons for shared library load failures. |
|
type soError struct { |
|
Err error |
|
ObjName string |
|
Msg string |
|
} |
|
|
|
func (e *soError) Error() string { return e.Msg } |
|
|
|
// Implemented in runtime/syscall_solaris.goc. |
|
func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) |
|
func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) |
|
func dlclose(handle uintptr) (err syscall.Errno) |
|
func dlopen(name *uint8, mode uintptr) (handle uintptr, err syscall.Errno) |
|
func dlsym(handle uintptr, name *uint8) (proc uintptr, err syscall.Errno) |
|
|
|
// A so implements access to a single shared library object. |
|
type so struct { |
|
Name string |
|
Handle uintptr |
|
} |
|
|
|
// loadSO loads shared library file into memory. |
|
func loadSO(name string) (*so, error) { |
|
namep, err := BytePtrFromString(name) |
|
if err != nil { |
|
return nil, err |
|
} |
|
h, e := dlopen(namep, 1) // RTLD_LAZY |
|
if e != 0 { |
|
return nil, &soError{ |
|
Err: e, |
|
ObjName: name, |
|
Msg: "Failed to load " + name + ": " + e.Error(), |
|
} |
|
} |
|
d := &so{ |
|
Name: name, |
|
Handle: uintptr(h), |
|
} |
|
return d, nil |
|
} |
|
|
|
// mustLoadSO is like loadSO but panics if load operation fails. |
|
func mustLoadSO(name string) *so { |
|
d, e := loadSO(name) |
|
if e != nil { |
|
panic(e) |
|
} |
|
return d |
|
} |
|
|
|
// FindProc searches shared library d for procedure named name and returns |
|
// *proc if found. It returns an error if the search fails. |
|
func (d *so) FindProc(name string) (*proc, error) { |
|
namep, err := BytePtrFromString(name) |
|
if err != nil { |
|
return nil, err |
|
} |
|
a, _ := dlsym(uintptr(d.Handle), namep) |
|
if a == 0 { |
|
return nil, &soError{ |
|
Err: ENOSYS, |
|
ObjName: name, |
|
Msg: "Failed to find " + name + " procedure in " + d.Name, |
|
} |
|
} |
|
p := &proc{ |
|
SO: d, |
|
Name: name, |
|
addr: a, |
|
} |
|
return p, nil |
|
} |
|
|
|
// MustFindProc is like FindProc but panics if search fails. |
|
func (d *so) MustFindProc(name string) *proc { |
|
p, e := d.FindProc(name) |
|
if e != nil { |
|
panic(e) |
|
} |
|
return p |
|
} |
|
|
|
// Release unloads shared library d from memory. |
|
func (d *so) Release() (err error) { |
|
return dlclose(d.Handle) |
|
} |
|
|
|
// A proc implements access to a procedure inside a shared library. |
|
type proc struct { |
|
SO *so |
|
Name string |
|
addr uintptr |
|
} |
|
|
|
// Addr returns the address of the procedure represented by p. |
|
// The return value can be passed to Syscall to run the procedure. |
|
func (p *proc) Addr() uintptr { |
|
return p.addr |
|
} |
|
|
|
// Call executes procedure p with arguments a. It will panic, if more then |
|
// 6 arguments are supplied. |
|
// |
|
// The returned error is always non-nil, constructed from the result of |
|
// GetLastError. Callers must inspect the primary return value to decide |
|
// whether an error occurred (according to the semantics of the specific |
|
// function being called) before consulting the error. The error will be |
|
// guaranteed to contain syscall.Errno. |
|
func (p *proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { |
|
switch len(a) { |
|
case 0: |
|
return sysvicall6(p.Addr(), uintptr(len(a)), 0, 0, 0, 0, 0, 0) |
|
case 1: |
|
return sysvicall6(p.Addr(), uintptr(len(a)), a[0], 0, 0, 0, 0, 0) |
|
case 2: |
|
return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], 0, 0, 0, 0) |
|
case 3: |
|
return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], 0, 0, 0) |
|
case 4: |
|
return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0) |
|
case 5: |
|
return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0) |
|
case 6: |
|
return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5]) |
|
default: |
|
panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".") |
|
} |
|
return |
|
} |
|
|
|
// A lazySO implements access to a single shared library. It will delay |
|
// the load of the shared library until the first call to its Handle method |
|
// or to one of its lazyProc's Addr method. |
|
type lazySO struct { |
|
mu sync.Mutex |
|
so *so // non nil once SO is loaded |
|
Name string |
|
} |
|
|
|
// Load loads single shared file d.Name into memory. It returns an error if |
|
// fails. Load will not try to load SO, if it is already loaded into memory. |
|
func (d *lazySO) Load() error { |
|
// Non-racy version of: |
|
// if d.so == nil { |
|
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.so))) == nil { |
|
d.mu.Lock() |
|
defer d.mu.Unlock() |
|
if d.so == nil { |
|
so, e := loadSO(d.Name) |
|
if e != nil { |
|
return e |
|
} |
|
// Non-racy version of: |
|
// d.so = so |
|
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.so)), unsafe.Pointer(so)) |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
// mustLoad is like Load but panics if search fails. |
|
func (d *lazySO) mustLoad() { |
|
e := d.Load() |
|
if e != nil { |
|
panic(e) |
|
} |
|
} |
|
|
|
// Handle returns d's module handle. |
|
func (d *lazySO) Handle() uintptr { |
|
d.mustLoad() |
|
return uintptr(d.so.Handle) |
|
} |
|
|
|
// NewProc returns a lazyProc for accessing the named procedure in the SO d. |
|
func (d *lazySO) NewProc(name string) *lazyProc { |
|
return &lazyProc{l: d, Name: name} |
|
} |
|
|
|
// newLazySO creates new lazySO associated with SO file. |
|
func newLazySO(name string) *lazySO { |
|
return &lazySO{Name: name} |
|
} |
|
|
|
// A lazyProc implements access to a procedure inside a lazySO. |
|
// It delays the lookup until the Addr method is called. |
|
type lazyProc struct { |
|
mu sync.Mutex |
|
Name string |
|
l *lazySO |
|
proc *proc |
|
} |
|
|
|
// Find searches the shared library for procedure named p.Name. It returns an |
|
// error if search fails. Find will not search procedure, if it is already |
|
// found and loaded into memory. |
|
func (p *lazyProc) Find() error { |
|
// Non-racy version of: |
|
// if p.proc == nil { |
|
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil { |
|
p.mu.Lock() |
|
defer p.mu.Unlock() |
|
if p.proc == nil { |
|
e := p.l.Load() |
|
if e != nil { |
|
return e |
|
} |
|
proc, e := p.l.so.FindProc(p.Name) |
|
if e != nil { |
|
return e |
|
} |
|
// Non-racy version of: |
|
// p.proc = proc |
|
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc)) |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
// mustFind is like Find but panics if search fails. |
|
func (p *lazyProc) mustFind() { |
|
e := p.Find() |
|
if e != nil { |
|
panic(e) |
|
} |
|
} |
|
|
|
// Addr returns the address of the procedure represented by p. |
|
// The return value can be passed to Syscall to run the procedure. |
|
func (p *lazyProc) Addr() uintptr { |
|
p.mustFind() |
|
return p.proc.Addr() |
|
} |
|
|
|
// Call executes procedure p with arguments a. It will panic, if more then |
|
// 6 arguments are supplied. |
|
// |
|
// The returned error is always non-nil, constructed from the result of |
|
// GetLastError. Callers must inspect the primary return value to decide |
|
// whether an error occurred (according to the semantics of the specific |
|
// function being called) before consulting the error. The error will be |
|
// guaranteed to contain syscall.Errno. |
|
func (p *lazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { |
|
p.mustFind() |
|
return p.proc.Call(a...) |
|
}
|
|
|