From e34354d1de06ac4e28948d8597fc1442d2169eb3 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Thu, 21 May 2015 22:28:52 -0700 Subject: [PATCH 01/17] dlopen: add libuv dynamic library loader binding --- lib/dlopen.js | 32 ++++++++++++ node.gyp | 2 + src/node_dlopen.cc | 119 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 lib/dlopen.js create mode 100644 src/node_dlopen.cc diff --git a/lib/dlopen.js b/lib/dlopen.js new file mode 100644 index 00000000000000..773a0afbdb777f --- /dev/null +++ b/lib/dlopen.js @@ -0,0 +1,32 @@ +const binding = process.binding('dlopen'); + +exports.dlopen = function dlopen(name) { + var lib = new Buffer(binding.sizeof_uv_lib_t); + + if (binding.dlopen(name, lib) !== 0) { + // error + throw new Error(exports.dlerror(lib)); + } + + return lib; +}; + +exports.dlclose = function dlclose(lib) { + return binding.dlclose(lib); +}; + +exports.dlsym = function dlsym(lib, name) { + // TODO: use `sizeof.pointer` for buffer size when nodejs/io.js#1759 is merged + var sym = new Buffer(8); + + if (binding.dlsym(lib, name, sym) !== 0) { + // error + throw new Error(exports.dlerror(lib)); + } + + return sym; +}; + +exports.dlerror = function dlerror(lib) { + return binding.dlerror(lib); +}; diff --git a/node.gyp b/node.gyp index 70c9841a89a176..478e4bedb2ba4e 100644 --- a/node.gyp +++ b/node.gyp @@ -26,6 +26,7 @@ 'lib/crypto.js', 'lib/cluster.js', 'lib/dgram.js', + 'lib/dlopen.js', 'lib/dns.js', 'lib/domain.js', 'lib/events.js', @@ -108,6 +109,7 @@ 'src/node_buffer.cc', 'src/node_constants.cc', 'src/node_contextify.cc', + 'src/node_dlopen.cc', 'src/node_file.cc', 'src/node_http_parser.cc', 'src/node_javascript.cc', diff --git a/src/node_dlopen.cc b/src/node_dlopen.cc new file mode 100644 index 00000000000000..473be7d6e8460f --- /dev/null +++ b/src/node_dlopen.cc @@ -0,0 +1,119 @@ +#include "node.h" +#include "node_buffer.h" +#include "v8.h" +#include "env.h" +#include "env-inl.h" + +namespace node { +namespace dlopen { + +using v8::Boolean; +using v8::Context; +using v8::FunctionCallbackInfo; +using v8::Handle; +using v8::HandleScope; +using v8::Integer; +using v8::Local; +using v8::Number; +using v8::Object; +using v8::String; +using v8::Value; +using v8::Uint32; + + +static void Dlopen(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + HandleScope scope(env->isolate()); + + const char *filename; + if (args[0]->IsNull()) { + filename = NULL; + } else if (args[0]->IsString()) { + String::Utf8Value name(args[0]); + filename = *name; + } else { + return env->ThrowTypeError("expected a string filename or null as first argument"); + } + + if (!Buffer::HasInstance(args[1])) + return env->ThrowTypeError("expected a Buffer instance as second argument"); + + Local buf = args[1].As(); + uv_lib_t *lib = reinterpret_cast(Buffer::Data(buf)); + + int r = uv_dlopen(filename, lib); + + args.GetReturnValue().Set(r); +} + + +static void Dlclose(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + HandleScope scope(env->isolate()); + + if (!Buffer::HasInstance(args[0])) + return env->ThrowTypeError("expected a Buffer instance as first argument"); + + Local buf = args[0].As(); + uv_lib_t *lib = reinterpret_cast(Buffer::Data(buf)); + + uv_dlclose(lib); +} + + +static void Dlsym(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + HandleScope scope(env->isolate()); + + if (!Buffer::HasInstance(args[0])) + return env->ThrowTypeError("expected a Buffer instance as first argument"); + if (!args[1]->IsString()) + return env->ThrowTypeError("expected a string as second argument"); + if (!Buffer::HasInstance(args[2])) + return env->ThrowTypeError("expected a Buffer instance as third argument"); + + Local buf = args[0].As(); + uv_lib_t *lib = reinterpret_cast(Buffer::Data(buf)); + + Local sym_buf = args[2].As(); + void *sym = reinterpret_cast(Buffer::Data(sym_buf)); + + String::Utf8Value name(args[1]); + + int r = uv_dlsym(lib, *name, &sym); + + args.GetReturnValue().Set(r); +} + + +static void Dlerror(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + HandleScope scope(env->isolate()); + + if (!Buffer::HasInstance(args[0])) + return env->ThrowTypeError("expected a Buffer instance as first argument"); + + Local buf = args[0].As(); + uv_lib_t *lib = reinterpret_cast(Buffer::Data(buf)); + + args.GetReturnValue().Set(OneByteString(env->isolate(), uv_dlerror(lib))); +} + + +void Initialize(Handle target, + Handle unused, + Handle context) { + Environment* env = Environment::GetCurrent(context); + env->SetMethod(target, "dlopen", Dlopen); + env->SetMethod(target, "dlclose", Dlclose); + env->SetMethod(target, "dlsym", Dlsym); + env->SetMethod(target, "dlerror", Dlerror); + + target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "sizeof_uv_lib_t"), + Uint32::NewFromUnsigned(env->isolate(), static_cast(sizeof(uv_lib_t)))); +} + +} // namespace dlopen +} // namespace node + +NODE_MODULE_CONTEXT_AWARE_BUILTIN(dlopen, node::dlopen::Initialize) From 557450265962ac3da8a61ad9bfddb3b19f146c8b Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 09:50:33 -0700 Subject: [PATCH 02/17] dlopen: remove HandleScope --- src/node_dlopen.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/node_dlopen.cc b/src/node_dlopen.cc index 473be7d6e8460f..baa229253bf26a 100644 --- a/src/node_dlopen.cc +++ b/src/node_dlopen.cc @@ -11,7 +11,6 @@ using v8::Boolean; using v8::Context; using v8::FunctionCallbackInfo; using v8::Handle; -using v8::HandleScope; using v8::Integer; using v8::Local; using v8::Number; @@ -23,7 +22,6 @@ using v8::Uint32; static void Dlopen(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - HandleScope scope(env->isolate()); const char *filename; if (args[0]->IsNull()) { @@ -49,7 +47,6 @@ static void Dlopen(const FunctionCallbackInfo& args) { static void Dlclose(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - HandleScope scope(env->isolate()); if (!Buffer::HasInstance(args[0])) return env->ThrowTypeError("expected a Buffer instance as first argument"); @@ -63,7 +60,6 @@ static void Dlclose(const FunctionCallbackInfo& args) { static void Dlsym(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - HandleScope scope(env->isolate()); if (!Buffer::HasInstance(args[0])) return env->ThrowTypeError("expected a Buffer instance as first argument"); @@ -88,7 +84,6 @@ static void Dlsym(const FunctionCallbackInfo& args) { static void Dlerror(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - HandleScope scope(env->isolate()); if (!Buffer::HasInstance(args[0])) return env->ThrowTypeError("expected a Buffer instance as first argument"); From e3c51fa7e42f0aeef4fdf6314851ccac866b6cfe Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 09:51:12 -0700 Subject: [PATCH 03/17] dlopen: use node::Utf8Value --- src/node_dlopen.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node_dlopen.cc b/src/node_dlopen.cc index baa229253bf26a..0aeb0acf597569 100644 --- a/src/node_dlopen.cc +++ b/src/node_dlopen.cc @@ -27,7 +27,7 @@ static void Dlopen(const FunctionCallbackInfo& args) { if (args[0]->IsNull()) { filename = NULL; } else if (args[0]->IsString()) { - String::Utf8Value name(args[0]); + node::Utf8Value name(env->isolate(), args[0]); filename = *name; } else { return env->ThrowTypeError("expected a string filename or null as first argument"); @@ -74,7 +74,7 @@ static void Dlsym(const FunctionCallbackInfo& args) { Local sym_buf = args[2].As(); void *sym = reinterpret_cast(Buffer::Data(sym_buf)); - String::Utf8Value name(args[1]); + node::Utf8Value name(env->isolate(), args[1]); int r = uv_dlsym(lib, *name, &sym); From 77f7a12379c0381d5cfc732e03ae71908530b062 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 09:51:50 -0700 Subject: [PATCH 04/17] dlopen: memcpy() the sym pointer into the Buffer --- src/node_dlopen.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/node_dlopen.cc b/src/node_dlopen.cc index 0aeb0acf597569..e907fdd9724e06 100644 --- a/src/node_dlopen.cc +++ b/src/node_dlopen.cc @@ -71,13 +71,14 @@ static void Dlsym(const FunctionCallbackInfo& args) { Local buf = args[0].As(); uv_lib_t *lib = reinterpret_cast(Buffer::Data(buf)); - Local sym_buf = args[2].As(); - void *sym = reinterpret_cast(Buffer::Data(sym_buf)); - + void *sym; node::Utf8Value name(env->isolate(), args[1]); - int r = uv_dlsym(lib, *name, &sym); + Local sym_buf = args[2].As(); + + memcpy(Buffer::Data(sym_buf), &sym, sizeof(sym)); + args.GetReturnValue().Set(r); } From ae5091fc0ccda87828d2dbf2fab0504c352df255 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 09:53:28 -0700 Subject: [PATCH 05/17] dlopen: add 'use strict' to lib module --- lib/dlopen.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/dlopen.js b/lib/dlopen.js index 773a0afbdb777f..641733fdd59529 100644 --- a/lib/dlopen.js +++ b/lib/dlopen.js @@ -1,3 +1,5 @@ +'use strict'; + const binding = process.binding('dlopen'); exports.dlopen = function dlopen(name) { From 015e817b8762c4643401eda87e4f3ace63d8d382 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 09:57:56 -0700 Subject: [PATCH 06/17] dlopen: use `nullptr` --- src/node_dlopen.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_dlopen.cc b/src/node_dlopen.cc index e907fdd9724e06..0caf0399bf3d5c 100644 --- a/src/node_dlopen.cc +++ b/src/node_dlopen.cc @@ -25,7 +25,7 @@ static void Dlopen(const FunctionCallbackInfo& args) { const char *filename; if (args[0]->IsNull()) { - filename = NULL; + filename = nullptr; } else if (args[0]->IsString()) { node::Utf8Value name(env->isolate(), args[0]); filename = *name; From 58662e3bc44f6f6400ee00bedaf4e52c0b9e4d5f Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 09:58:07 -0700 Subject: [PATCH 07/17] dlopen: nix long lines --- src/node_dlopen.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/node_dlopen.cc b/src/node_dlopen.cc index 0caf0399bf3d5c..c252607a2115e6 100644 --- a/src/node_dlopen.cc +++ b/src/node_dlopen.cc @@ -30,7 +30,9 @@ static void Dlopen(const FunctionCallbackInfo& args) { node::Utf8Value name(env->isolate(), args[0]); filename = *name; } else { - return env->ThrowTypeError("expected a string filename or null as first argument"); + return env->ThrowTypeError( + "expected a string filename or null as first argument" + ); } if (!Buffer::HasInstance(args[1])) @@ -106,7 +108,8 @@ void Initialize(Handle target, env->SetMethod(target, "dlerror", Dlerror); target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "sizeof_uv_lib_t"), - Uint32::NewFromUnsigned(env->isolate(), static_cast(sizeof(uv_lib_t)))); + Uint32::NewFromUnsigned(env->isolate(), + static_cast(sizeof(uv_lib_t)))); } } // namespace dlopen From b7aaf11e818b0d40e05063e13b1e7f23e89cbc9b Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 09:59:23 -0700 Subject: [PATCH 08/17] dlopen: asterisks lean to the left --- src/node_dlopen.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/node_dlopen.cc b/src/node_dlopen.cc index c252607a2115e6..92f14b8a041cec 100644 --- a/src/node_dlopen.cc +++ b/src/node_dlopen.cc @@ -23,7 +23,7 @@ using v8::Uint32; static void Dlopen(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - const char *filename; + const char* filename; if (args[0]->IsNull()) { filename = nullptr; } else if (args[0]->IsString()) { @@ -39,7 +39,7 @@ static void Dlopen(const FunctionCallbackInfo& args) { return env->ThrowTypeError("expected a Buffer instance as second argument"); Local buf = args[1].As(); - uv_lib_t *lib = reinterpret_cast(Buffer::Data(buf)); + uv_lib_t* lib = reinterpret_cast(Buffer::Data(buf)); int r = uv_dlopen(filename, lib); @@ -54,7 +54,7 @@ static void Dlclose(const FunctionCallbackInfo& args) { return env->ThrowTypeError("expected a Buffer instance as first argument"); Local buf = args[0].As(); - uv_lib_t *lib = reinterpret_cast(Buffer::Data(buf)); + uv_lib_t* lib = reinterpret_cast(Buffer::Data(buf)); uv_dlclose(lib); } @@ -71,9 +71,9 @@ static void Dlsym(const FunctionCallbackInfo& args) { return env->ThrowTypeError("expected a Buffer instance as third argument"); Local buf = args[0].As(); - uv_lib_t *lib = reinterpret_cast(Buffer::Data(buf)); + uv_lib_t* lib = reinterpret_cast(Buffer::Data(buf)); - void *sym; + void* sym; node::Utf8Value name(env->isolate(), args[1]); int r = uv_dlsym(lib, *name, &sym); @@ -92,7 +92,7 @@ static void Dlerror(const FunctionCallbackInfo& args) { return env->ThrowTypeError("expected a Buffer instance as first argument"); Local buf = args[0].As(); - uv_lib_t *lib = reinterpret_cast(Buffer::Data(buf)); + uv_lib_t* lib = reinterpret_cast(Buffer::Data(buf)); args.GetReturnValue().Set(OneByteString(env->isolate(), uv_dlerror(lib))); } From f644a49e14b5391350a99bbe3e75eb67a2631a99 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 12:23:36 -0700 Subject: [PATCH 09/17] dlopen: remove superfluous comments --- lib/dlopen.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/dlopen.js b/lib/dlopen.js index 641733fdd59529..47014176f507e8 100644 --- a/lib/dlopen.js +++ b/lib/dlopen.js @@ -6,7 +6,6 @@ exports.dlopen = function dlopen(name) { var lib = new Buffer(binding.sizeof_uv_lib_t); if (binding.dlopen(name, lib) !== 0) { - // error throw new Error(exports.dlerror(lib)); } @@ -22,7 +21,6 @@ exports.dlsym = function dlsym(lib, name) { var sym = new Buffer(8); if (binding.dlsym(lib, name, sym) !== 0) { - // error throw new Error(exports.dlerror(lib)); } From da31bbc2530dcac7bd0aa350f6b813fa0fb8f192 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Fri, 22 May 2015 15:26:44 -0700 Subject: [PATCH 10/17] repl: add "dlopen" module to builtinLibs array --- lib/repl.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/repl.js b/lib/repl.js index 40496559bf452f..4aaa87a5d190ec 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -59,10 +59,10 @@ function hasOwnProperty(obj, prop) { exports.writer = util.inspect; exports._builtinLibs = ['assert', 'buffer', 'child_process', 'cluster', - 'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https', 'net', - 'os', 'path', 'punycode', 'querystring', 'readline', 'stream', - 'string_decoder', 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'zlib', - 'smalloc']; + 'crypto', 'dgram', 'dlopen', 'dns', 'domain', 'events', 'fs', 'http', + 'https', 'net', 'os', 'path', 'punycode', 'querystring', 'readline', + 'stream', 'string_decoder', 'tls', 'tty', 'url', 'util', 'v8', 'vm', + 'zlib', 'smalloc']; const BLOCK_SCOPED_ERROR = 'Block-scoped declarations (let, ' + From 85e56bf1200d2b428d22faca786f825224c0c852 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Sat, 23 May 2015 15:44:36 -0700 Subject: [PATCH 11/17] doc: add "dlopen" initial docs --- doc/api/_toc.markdown | 1 + doc/api/dlopen.markdown | 81 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 doc/api/dlopen.markdown diff --git a/doc/api/_toc.markdown b/doc/api/_toc.markdown index c838ab383e2ed7..e704bacfea8c37 100644 --- a/doc/api/_toc.markdown +++ b/doc/api/_toc.markdown @@ -10,6 +10,7 @@ * [Console](console.html) * [Crypto](crypto.html) * [Debugger](debugger.html) +* [Dlopen](dlopen.html) * [DNS](dns.html) * [Domain](domain.html) * [Errors](errors.html) diff --git a/doc/api/dlopen.markdown b/doc/api/dlopen.markdown new file mode 100644 index 00000000000000..1d8a15ece1443e --- /dev/null +++ b/doc/api/dlopen.markdown @@ -0,0 +1,81 @@ +# dlopen + + Stability: 1 - Experimental + +Dynamic library loader module. + +Use `require('dlopen')` to access this module. + +## dlopen.dlopen(name) + +* `name` String or `null` - library filename +* Return: Buffer - backing store for the `uv_lib_t` instance + +Load and link a dynamic library with filename `name`. +If `null` is given as the name, then the current node process is +dynamically loaded instead (i.e. you can load symbols already +loaded into memory). + +Example: + + var libc = dlopen.dlopen('libc.so'); + // + + // null for the current process' memory + var currentProcess = dlopen.dlopen(null); + // + + // error is thrown if something goes wrong + dlopen.dlopen('libdoesnotexist.so') + // Error: dlopen(libdoesnotexist.so, 1): image not found + // at Object.dlopen (dlopen.js:9:11) + +## dlopen.dlclose(lib) + +* `lib` Buffer - the buffer previously returned from `dlopen()` + +Closes dynamic library `lib`. + +Example: + + dlopen.dlclose(libc); + +## dlopen.dlsym(lib, namem) + +* `lib` Buffer - the buffer previously returned from `dlopen()` +* `name` String - name of the symbol to retrieve from `lib` +* Return: Buffer - a pointer-sized buffer containing the address of `name` + +Get the memory address of symbol `name` from dynamic library `lib`. +A new Buffer instance is returned containing the memory address of +the loaded symbol. + +Almost always, you will call one of the Buffer `readPointer*()` +functions on the returned buffer in order to interact with the symbol +further. + +Example: + + var absSymPtr = dlopen.dlsym(libc, 'abs'); + // + + // error is thrown if symbol does not exist + dlopen.dlsym(libc, 'doesnotexist') + // Error: dlsym(0x7fff6ad9f898, doesnotexist): symbol not found + // at Object.dlsym (dlopen.js:24:11) + +## dlopen.dlerror(lib) + +* `lib` Buffer - the buffer previously returned from `dlopen()` +* Return: String - most recent error that has occured on `lib` + +Get previous error message from dynamic library `lib`. + +You most likely won't need to use this function, since `dlopen()` +and `dlsym()` use them internally when something goes wrong. + + +Example: + + dlopen.dlerror(libc) + // 'no error' From fae99e12f630aefd1c75849f62f8ba05b43f3573 Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Sat, 23 May 2015 15:51:58 -0700 Subject: [PATCH 12/17] test: add "libtest" build target Will be used for the "dlopen" module tests. --- node.gyp | 12 +++++++++++- test/libtest/libtest.c | 27 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 test/libtest/libtest.c diff --git a/node.gyp b/node.gyp index 478e4bedb2ba4e..9f0d28737a67e3 100644 --- a/node.gyp +++ b/node.gyp @@ -651,6 +651,16 @@ 'sources': [ 'test/cctest/util.cc', ], - } + }, + + # "libtest" dynamic library for "dlopen" tests + { + 'target_name': 'test', + 'type': 'shared_library', + 'product_prefix': 'lib', + 'sources': [ + 'test/libtest/libtest.c' + ], + }, ] # end targets } diff --git a/test/libtest/libtest.c b/test/libtest/libtest.c new file mode 100644 index 00000000000000..d852c141efb9ae --- /dev/null +++ b/test/libtest/libtest.c @@ -0,0 +1,27 @@ +#include +#include + +#if defined(WIN32) || defined(_WIN32) +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +EXPORT int six = 6; + +EXPORT void* n = NULL; + +EXPORT char str[] = "hello world"; + +EXPORT uint64_t factorial(int max) { + int i = max; + uint64_t result = 1; + + while (i >= 2) { + result *= i--; + } + + return result; +} + +EXPORT intptr_t factorial_addr = (intptr_t)&factorial; From 0bfd0d80c49a59a544d00f0ad1f9cf4c13394aba Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Sat, 23 May 2015 18:10:38 -0700 Subject: [PATCH 13/17] dlopen: add "dlopen.extension" string --- lib/dlopen.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/dlopen.js b/lib/dlopen.js index 47014176f507e8..8270c3c2a9c7cd 100644 --- a/lib/dlopen.js +++ b/lib/dlopen.js @@ -30,3 +30,13 @@ exports.dlsym = function dlsym(lib, name) { exports.dlerror = function dlerror(lib) { return binding.dlerror(lib); }; + +exports.extension = { + linux: '.so', + sunos: '.so', + solaris: '.so', + freebsd: '.so', + openbsd: '.so', + darwin: '.dylib', + win32: '.dll' +}[process.platform]; From ee31f290445d2d16cb9c4dd4befbc8916aba7a0a Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Sat, 23 May 2015 18:10:58 -0700 Subject: [PATCH 14/17] dlopen: fix cpp lint --- src/node_dlopen.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/node_dlopen.cc b/src/node_dlopen.cc index 92f14b8a041cec..82f11c6001ec84 100644 --- a/src/node_dlopen.cc +++ b/src/node_dlopen.cc @@ -31,8 +31,7 @@ static void Dlopen(const FunctionCallbackInfo& args) { filename = *name; } else { return env->ThrowTypeError( - "expected a string filename or null as first argument" - ); + "expected a string filename or null as first argument"); } if (!Buffer::HasInstance(args[1])) From 2889d63730215898e36be49f4e283517a15e9fef Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Sat, 23 May 2015 18:11:20 -0700 Subject: [PATCH 15/17] test: add initial "dlopen" module tests --- test/libtest/libtest.c | 2 +- test/parallel/test-dlopen.js | 49 ++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-dlopen.js diff --git a/test/libtest/libtest.c b/test/libtest/libtest.c index d852c141efb9ae..67c95148c56364 100644 --- a/test/libtest/libtest.c +++ b/test/libtest/libtest.c @@ -24,4 +24,4 @@ EXPORT uint64_t factorial(int max) { return result; } -EXPORT intptr_t factorial_addr = (intptr_t)&factorial; +EXPORT intptr_t factorial_addr = (intptr_t)factorial; diff --git a/test/parallel/test-dlopen.js b/test/parallel/test-dlopen.js new file mode 100644 index 00000000000000..095501ee3149b3 --- /dev/null +++ b/test/parallel/test-dlopen.js @@ -0,0 +1,49 @@ +'use strict'; +var common = require('../common'); +var assert = require('assert'); +var path = require('path'); +var endianness = require('os').endianness(); + +var dl = require('dlopen'); + +var root = path.join(__dirname, '..', '..'); +var libPath = path.join(root, 'out', 'Release', 'libtest' + dl.extension); +console.log(libPath); + +var libtest = dl.dlopen(libPath); +console.log(libtest); + +// EXPORT int six = 6 +var sixSymPtr = dl.dlsym(libtest, 'six'); +// TODO: use `sizeof.int` +var sixSym = sixSymPtr['readPointer' + endianness](0, 4); +assert.equal(6, sixSym['readInt' + (4 * 8) + endianness](0)); + +// EXPORT void* n = NULL; +var nSymPtr = dl.dlsym(libtest, 'n'); +// TODO: use `sizeof.pointer` +var nSym = nSymPtr['readPointer' + endianness](0, 8); +assert.strictEqual(null, nSym['readPointer' + endianness](0)); + +// EXPORT char str[] = "hello world"; +var strSymPtr = dl.dlsym(libtest, 'str'); +// XXX: We need a way to read a null-terminated array :( :( :( +var strSym = strSymPtr['readPointer' + endianness](0, 12); +assert.equal('hello world', strSym.toString('ascii', 0, 11)); +assert.equal(0, strSym[11]); + +// EXPORT uint64_t factorial(int max) +var factorialSymPtr = dl.dlsym(libtest, 'factorial'); +// TODO: use `sizeof.pointer` +var factorialSym = factorialSymPtr['readPointer' + endianness](0, 0); + +// EXPORT intptr_t factorial_addr = (intptr_t)factorial; +var factorialAddrSymPtr = dl.dlsym(libtest, 'factorial_addr'); +var factorialAddrSym = factorialAddrSymPtr['readPointer' + endianness](0, 8); +var factorialSym2 = factorialAddrSym['readPointer' + endianness](0, 0); + +assert.equal(factorialSym.address(), factorialSym2.address()); + + +// we're done ☺ +dl.dlclose(libtest); From 43ed14fc60d611dbee8770e77323b7b983d2f2af Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Sat, 23 May 2015 18:13:20 -0700 Subject: [PATCH 16/17] doc: add "dlopen.extension" docs --- doc/api/dlopen.markdown | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/api/dlopen.markdown b/doc/api/dlopen.markdown index 1d8a15ece1443e..01539493834fcb 100644 --- a/doc/api/dlopen.markdown +++ b/doc/api/dlopen.markdown @@ -6,6 +6,17 @@ Dynamic library loader module. Use `require('dlopen')` to access this module. +## dlopen.extension + +* String + +File extension used for dynamic libraries. + +For example, on Mac OS X: + + console.log(dlopen.extension); + // '.dylib' + ## dlopen.dlopen(name) * `name` String or `null` - library filename From ab08bc0e7a59c36f1db27dbfbb79f67ee9d70d3c Mon Sep 17 00:00:00 2001 From: Nathan Rajlich Date: Sun, 24 May 2015 13:48:21 -0700 Subject: [PATCH 17/17] test: use uintptr_t for `factorial_addr` symbol --- test/libtest/libtest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/libtest/libtest.c b/test/libtest/libtest.c index 67c95148c56364..144e6e1594b1ab 100644 --- a/test/libtest/libtest.c +++ b/test/libtest/libtest.c @@ -24,4 +24,4 @@ EXPORT uint64_t factorial(int max) { return result; } -EXPORT intptr_t factorial_addr = (intptr_t)factorial; +EXPORT uintptr_t factorial_addr = (uintptr_t)factorial;