dynamic_library.js
3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/**
* Module dependencies.
*/
var ForeignFunction = require('./foreign_function')
, assert = require('assert')
, debug = require('debug')('ffi:DynamicLibrary')
, bindings = require('./bindings')
, funcs = bindings.StaticFunctions
, ref = require('ref')
, read = require('fs').readFileSync
// typedefs
var int = ref.types.int
, voidPtr = ref.refType(ref.types.void)
var dlopen = ForeignFunction(funcs.dlopen, voidPtr, [ 'string', int ])
, dlclose = ForeignFunction(funcs.dlclose, int, [ voidPtr ])
, dlsym = ForeignFunction(funcs.dlsym, voidPtr, [ voidPtr, 'string' ])
, dlerror = ForeignFunction(funcs.dlerror, 'string', [ ])
/**
* `DynamicLibrary` loads and fetches function pointers for dynamic libraries
* (.so, .dylib, etc). After the libray's function pointer is acquired, then you
* call `get(symbol)` to retreive a pointer to an exported symbol. You need to
* call `get___()` on the pointer to dereference it into its actual value, or
* turn the pointer into a callable function with `ForeignFunction`.
*/
function DynamicLibrary (path, mode) {
if (!(this instanceof DynamicLibrary)) {
return new DynamicLibrary(path, mode)
}
debug('new DynamicLibrary()', path, mode)
if (null == mode) {
mode = DynamicLibrary.FLAGS.RTLD_LAZY
}
this._handle = dlopen(path, mode)
assert(Buffer.isBuffer(this._handle), 'expected a Buffer instance to be returned from `dlopen()`')
if (this._handle.isNull()) {
var err = this.error()
// THIS CODE IS BASED ON GHC Trac ticket #2615
// http://hackage.haskell.org/trac/ghc/attachment/ticket/2615
// On some systems (e.g., Gentoo Linux) dynamic files (e.g. libc.so)
// contain linker scripts rather than ELF-format object code. This
// code handles the situation by recognizing the real object code
// file name given in the linker script.
// If an "invalid ELF header" error occurs, it is assumed that the
// .so file contains a linker script instead of ELF object code.
// In this case, the code looks for the GROUP ( ... ) linker
// directive. If one is found, the first file name inside the
// parentheses is treated as the name of a dynamic library and the
// code attempts to dlopen that file. If this is also unsuccessful,
// an error message is returned.
// see if the error message is due to an invalid ELF header
var match
if (match = err.match(/^(([^ \t()])+\.so([^ \t:()])*):([ \t])*/)) {
var content = read(match[1], 'ascii')
// try to find a GROUP ( ... ) command
if (match = content.match(/GROUP *\( *(([^ )])+)/)){
return DynamicLibrary.call(this, match[1], mode)
}
}
throw new Error('Dynamic Linking Error: ' + err)
}
}
module.exports = DynamicLibrary
/**
* Set the exported flags from "dlfcn.h"
*/
DynamicLibrary.FLAGS = {};
Object.keys(bindings).forEach(function (k) {
if (!/^RTLD_/.test(k)) return;
var desc = Object.getOwnPropertyDescriptor(bindings, k)
Object.defineProperty(DynamicLibrary.FLAGS, k, desc)
});
/**
* Close this library, returns the result of the dlclose() system function.
*/
DynamicLibrary.prototype.close = function () {
debug('dlclose()')
return dlclose(this._handle)
}
/**
* Get a symbol from this library, returns a Pointer for (memory address of) the symbol
*/
DynamicLibrary.prototype.get = function (symbol) {
debug('dlsym()', symbol)
assert.equal('string', typeof symbol)
var ptr = dlsym(this._handle, symbol)
assert(Buffer.isBuffer(ptr))
if (ptr.isNull()) {
throw new Error('Dynamic Symbol Retrieval Error: ' + this.error())
}
ptr.name = symbol
return ptr
}
/**
* Returns the result of the dlerror() system function
*/
DynamicLibrary.prototype.error = function error () {
debug('dlerror()')
return dlerror()
}