Ruby 2.1.5p273(2014-11-13revision48405)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

handle.c
Go to the documentation of this file.
1 #include <ruby.h>
2 #include <fiddle.h>
3
4 VALUE rb_cHandle;
5
6 struct dl_handle {
7 void *ptr;
8 int open;
9 int enable_close;
10 };
11
12 #ifdef _WIN32
13 # ifndef _WIN32_WCE
14 static void *
15 w32_coredll(void)
16 {
17 MEMORY_BASIC_INFORMATION m;
18 memset(&m, 0, sizeof(m));
19 if( !VirtualQuery(_errno, &m, sizeof(m)) ) return NULL;
20 return m.AllocationBase;
21 }
22 # endif
23
24 static int
25 w32_dlclose(void *ptr)
26 {
27 # ifndef _WIN32_WCE
28 if( ptr == w32_coredll() ) return 0;
29 # endif
30 if( FreeLibrary((HMODULE)ptr) ) return 0;
31 return errno = rb_w32_map_errno(GetLastError());
32 }
33 #define dlclose(ptr) w32_dlclose(ptr)
34 #endif
35
36 static void
37 fiddle_handle_free(void *ptr)
38 {
39 struct dl_handle *fiddle_handle = ptr;
40 if( fiddle_handle->ptr && fiddle_handle->open && fiddle_handle->enable_close ){
41 dlclose(fiddle_handle->ptr);
42 }
43 xfree(ptr);
44 }
45
46 static size_t
47 fiddle_handle_memsize(const void *ptr)
48 {
49 return ptr ? sizeof(struct dl_handle) : 0;
50 }
51
52 static const rb_data_type_t fiddle_handle_data_type = {
53 "fiddle/handle",
54 {0, fiddle_handle_free, fiddle_handle_memsize,},
55 };
56
57 /*
58 * call-seq: close
59 *
60 * Close this handle.
61 *
62 * Calling close more than once will raise a Fiddle::DLError exception.
63 */
64 static VALUE
65 rb_fiddle_handle_close(VALUE self)
66 {
67 struct dl_handle *fiddle_handle;
68
69 TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
70 if(fiddle_handle->open) {
71 int ret = dlclose(fiddle_handle->ptr);
72 fiddle_handle->open = 0;
73
74 /* Check dlclose for successful return value */
75 if(ret) {
76 #if defined(HAVE_DLERROR)
77 rb_raise(rb_eFiddleError, "%s", dlerror());
78 #else
79 rb_raise(rb_eFiddleError, "could not close handle");
80 #endif
81 }
82 return INT2NUM(ret);
83 }
84 rb_raise(rb_eFiddleError, "dlclose() called too many times");
85
86 UNREACHABLE;
87 }
88
89 static VALUE
90 rb_fiddle_handle_s_allocate(VALUE klass)
91 {
92 VALUE obj;
93 struct dl_handle *fiddle_handle;
94
95 obj = TypedData_Make_Struct(rb_cHandle, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
96 fiddle_handle->ptr = 0;
97 fiddle_handle->open = 0;
98 fiddle_handle->enable_close = 0;
99
100 return obj;
101 }
102
103 static VALUE
104 predefined_fiddle_handle(void *handle)
105 {
106 VALUE obj = rb_fiddle_handle_s_allocate(rb_cHandle);
107 struct dl_handle *fiddle_handle = DATA_PTR(obj);
108
109 fiddle_handle->ptr = handle;
110 fiddle_handle->open = 1;
111 OBJ_FREEZE(obj);
112 return obj;
113 }
114
115 /*
116 * call-seq:
117 * new(library = nil, flags = Fiddle::RTLD_LAZY | Fiddle::RTLD_GLOBAL)
118 *
119 * Create a new handler that opens +library+ with +flags+.
120 *
121 * If no +library+ is specified or +nil+ is given, DEFAULT is used, which is
122 * the equivalent to RTLD_DEFAULT. See <code>man 3 dlopen</code> for more.
123 *
124 * lib = Fiddle::Handle.new
125 *
126 * The default is dependent on OS, and provide a handle for all libraries
127 * already loaded. For example, in most cases you can use this to access +libc+
128 * functions, or ruby functions like +rb_str_new+.
129 */
130 static VALUE
131 rb_fiddle_handle_initialize(int argc, VALUE argv[], VALUE self)
132 {
133 void *ptr;
134 struct dl_handle *fiddle_handle;
135 VALUE lib, flag;
136 char *clib;
137 int cflag;
138 const char *err;
139
140 switch( rb_scan_args(argc, argv, "02", &lib, &flag) ){
141 case 0:
142 clib = NULL;
143 cflag = RTLD_LAZY | RTLD_GLOBAL;
144 break;
145 case 1:
146 clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
147 cflag = RTLD_LAZY | RTLD_GLOBAL;
148 break;
149 case 2:
150 clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
151 cflag = NUM2INT(flag);
152 break;
153 default:
154 rb_bug("rb_fiddle_handle_new");
155 }
156
157 rb_secure(2);
158
159 #if defined(_WIN32)
160 if( !clib ){
161 HANDLE rb_libruby_handle(void);
162 ptr = rb_libruby_handle();
163 }
164 else if( STRCASECMP(clib, "libc") == 0
165 # ifdef RUBY_COREDLL
166 || STRCASECMP(clib, RUBY_COREDLL) == 0
167 || STRCASECMP(clib, RUBY_COREDLL".dll") == 0
168 # endif
169 ){
170 # ifdef _WIN32_WCE
171 ptr = dlopen("coredll.dll", cflag);
172 # else
173 ptr = w32_coredll();
174 # endif
175 }
176 else
177 #endif
178 ptr = dlopen(clib, cflag);
179 #if defined(HAVE_DLERROR)
180 if( !ptr && (err = dlerror()) ){
181 rb_raise(rb_eFiddleError, "%s", err);
182 }
183 #else
184 if( !ptr ){
185 err = dlerror();
186 rb_raise(rb_eFiddleError, "%s", err);
187 }
188 #endif
189 TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
190 if( fiddle_handle->ptr && fiddle_handle->open && fiddle_handle->enable_close ){
191 dlclose(fiddle_handle->ptr);
192 }
193 fiddle_handle->ptr = ptr;
194 fiddle_handle->open = 1;
195 fiddle_handle->enable_close = 0;
196
197 if( rb_block_given_p() ){
198 rb_ensure(rb_yield, self, rb_fiddle_handle_close, self);
199 }
200
201 return Qnil;
202 }
203
204 /*
205 * call-seq: enable_close
206 *
207 * Enable a call to dlclose() when this handle is garbage collected.
208 */
209 static VALUE
210 rb_fiddle_handle_enable_close(VALUE self)
211 {
212 struct dl_handle *fiddle_handle;
213
214 TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
215 fiddle_handle->enable_close = 1;
216 return Qnil;
217 }
218
219 /*
220 * call-seq: disable_close
221 *
222 * Disable a call to dlclose() when this handle is garbage collected.
223 */
224 static VALUE
225 rb_fiddle_handle_disable_close(VALUE self)
226 {
227 struct dl_handle *fiddle_handle;
228
229 TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
230 fiddle_handle->enable_close = 0;
231 return Qnil;
232 }
233
234 /*
235 * call-seq: close_enabled?
236 *
237 * Returns +true+ if dlclose() will be called when this handle is garbage collected.
238 *
239 * See man(3) dlclose() for more info.
240 */
241 static VALUE
242 rb_fiddle_handle_close_enabled_p(VALUE self)
243 {
244 struct dl_handle *fiddle_handle;
245
246 TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
247
248 if(fiddle_handle->enable_close) return Qtrue;
249 return Qfalse;
250 }
251
252 /*
253 * call-seq: to_i
254 *
255 * Returns the memory address for this handle.
256 */
257 static VALUE
258 rb_fiddle_handle_to_i(VALUE self)
259 {
260 struct dl_handle *fiddle_handle;
261
262 TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
263 return PTR2NUM(fiddle_handle);
264 }
265
266 static VALUE fiddle_handle_sym(void *handle, const char *symbol);
267
268 /*
269 * Document-method: sym
270 *
271 * call-seq: sym(name)
272 *
273 * Get the address as an Integer for the function named +name+.
274 */
275 static VALUE
276 rb_fiddle_handle_sym(VALUE self, VALUE sym)
277 {
278 struct dl_handle *fiddle_handle;
279
280 TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
281 if( ! fiddle_handle->open ){
282 rb_raise(rb_eFiddleError, "closed handle");
283 }
284
285 return fiddle_handle_sym(fiddle_handle->ptr, StringValueCStr(sym));
286 }
287
288 #ifndef RTLD_NEXT
289 #define RTLD_NEXT NULL
290 #endif
291 #ifndef RTLD_DEFAULT
292 #define RTLD_DEFAULT NULL
293 #endif
294
295 /*
296 * Document-method: sym
297 *
298 * call-seq: sym(name)
299 *
300 * Get the address as an Integer for the function named +name+. The function
301 * is searched via dlsym on RTLD_NEXT.
302 *
303 * See man(3) dlsym() for more info.
304 */
305 static VALUE
306 rb_fiddle_handle_s_sym(VALUE self, VALUE sym)
307 {
308 return fiddle_handle_sym(RTLD_NEXT, StringValueCStr(sym));
309 }
310
311 static VALUE
312 fiddle_handle_sym(void *handle, const char *name)
313 {
314 #if defined(HAVE_DLERROR)
315 const char *err;
316 # define CHECK_DLERROR if( err = dlerror() ){ func = 0; }
317 #else
318 # define CHECK_DLERROR
319 #endif
320 void (*func)();
321
322 rb_secure(2);
323 #ifdef HAVE_DLERROR
324 dlerror();
325 #endif
326 func = (void (*)())(VALUE)dlsym(handle, name);
327 CHECK_DLERROR;
328 #if defined(FUNC_STDCALL)
329 if( !func ){
330 int i;
331 int len = (int)strlen(name);
332 char *name_n;
333 #if defined(__CYGWIN__) || defined(_WIN32) || defined(__MINGW32__)
334 {
335 char *name_a = (char*)xmalloc(len+2);
336 strcpy(name_a, name);
337 name_n = name_a;
338 name_a[len] = 'A';
339 name_a[len+1] = '\0';
340 func = dlsym(handle, name_a);
341 CHECK_DLERROR;
342 if( func ) goto found;
343 name_n = xrealloc(name_a, len+6);
344 }
345 #else
346 name_n = (char*)xmalloc(len+6);
347 #endif
348 memcpy(name_n, name, len);
349 name_n[len++] = '@';
350 for( i = 0; i < 256; i += 4 ){
351 sprintf(name_n + len, "%d", i);
352 func = dlsym(handle, name_n);
353 CHECK_DLERROR;
354 if( func ) break;
355 }
356 if( func ) goto found;
357 name_n[len-1] = 'A';
358 name_n[len++] = '@';
359 for( i = 0; i < 256; i += 4 ){
360 sprintf(name_n + len, "%d", i);
361 func = dlsym(handle, name_n);
362 CHECK_DLERROR;
363 if( func ) break;
364 }
365 found:
366 xfree(name_n);
367 }
368 #endif
369 if( !func ){
370 rb_raise(rb_eFiddleError, "unknown symbol \"%s\"", name);
371 }
372
373 return PTR2NUM(func);
374 }
375
376 void
377 Init_fiddle_handle(void)
378 {
379 /*
380 * Document-class: Fiddle::Handle
381 *
382 * The Fiddle::Handle is the manner to access the dynamic library
383 *
384 * == Example
385 *
386 * === Setup
387 *
388 * libc_so = "/lib64/libc.so.6"
389 * => "/lib64/libc.so.6"
390 * @handle = Fiddle::Handle.new(libc_so)
391 * => #<Fiddle::Handle:0x00000000d69ef8>
392 *
393 * === Setup, with flags
394 *
395 * libc_so = "/lib64/libc.so.6"
396 * => "/lib64/libc.so.6"
397 * @handle = Fiddle::Handle.new(libc_so, Fiddle::RTLD_LAZY | Fiddle::RTLD_GLOBAL)
398 * => #<Fiddle::Handle:0x00000000d69ef8>
399 *
400 * See RTLD_LAZY and RTLD_GLOBAL
401 *
402 * === Addresses to symbols
403 *
404 * strcpy_addr = @handle['strcpy']
405 * => 140062278451968
406 *
407 * or
408 *
409 * strcpy_addr = @handle.sym('strcpy')
410 * => 140062278451968
411 *
412 */
413 rb_cHandle = rb_define_class_under(mFiddle, "Handle", rb_cObject);
414 rb_define_alloc_func(rb_cHandle, rb_fiddle_handle_s_allocate);
415 rb_define_singleton_method(rb_cHandle, "sym", rb_fiddle_handle_s_sym, 1);
416 rb_define_singleton_method(rb_cHandle, "[]", rb_fiddle_handle_s_sym, 1);
417
418 /* Document-const: NEXT
419 *
420 * A predefined pseudo-handle of RTLD_NEXT
421 *
422 * Which will find the next occurrence of a function in the search order
423 * after the current library.
424 */
425 rb_define_const(rb_cHandle, "NEXT", predefined_fiddle_handle(RTLD_NEXT));
426
427 /* Document-const: DEFAULT
428 *
429 * A predefined pseudo-handle of RTLD_DEFAULT
430 *
431 * Which will find the first occurrence of the desired symbol using the
432 * default library search order
433 */
434 rb_define_const(rb_cHandle, "DEFAULT", predefined_fiddle_handle(RTLD_DEFAULT));
435
436 /* Document-const: RTLD_GLOBAL
437 *
438 * rtld Fiddle::Handle flag.
439 *
440 * The symbols defined by this library will be made available for symbol
441 * resolution of subsequently loaded libraries.
442 */
443 rb_define_const(rb_cHandle, "RTLD_GLOBAL", INT2NUM(RTLD_GLOBAL));
444
445 /* Document-const: RTLD_LAZY
446 *
447 * rtld Fiddle::Handle flag.
448 *
449 * Perform lazy binding. Only resolve symbols as the code that references
450 * them is executed. If the symbol is never referenced, then it is never
451 * resolved. (Lazy binding is only performed for function references;
452 * references to variables are always immediately bound when the library
453 * is loaded.)
454 */
455 rb_define_const(rb_cHandle, "RTLD_LAZY", INT2NUM(RTLD_LAZY));
456
457 /* Document-const: RTLD_NOW
458 *
459 * rtld Fiddle::Handle flag.
460 *
461 * If this value is specified or the environment variable LD_BIND_NOW is
462 * set to a nonempty string, all undefined symbols in the library are
463 * resolved before Fiddle.dlopen returns. If this cannot be done an error
464 * is returned.
465 */
466 rb_define_const(rb_cHandle, "RTLD_NOW", INT2NUM(RTLD_NOW));
467
468 rb_define_method(rb_cHandle, "initialize", rb_fiddle_handle_initialize, -1);
469 rb_define_method(rb_cHandle, "to_i", rb_fiddle_handle_to_i, 0);
470 rb_define_method(rb_cHandle, "close", rb_fiddle_handle_close, 0);
471 rb_define_method(rb_cHandle, "sym", rb_fiddle_handle_sym, 1);
472 rb_define_method(rb_cHandle, "[]", rb_fiddle_handle_sym, 1);
473 rb_define_method(rb_cHandle, "disable_close", rb_fiddle_handle_disable_close, 0);
474 rb_define_method(rb_cHandle, "enable_close", rb_fiddle_handle_enable_close, 0);
475 rb_define_method(rb_cHandle, "close_enabled?", rb_fiddle_handle_close_enabled_p, 0);
476 }
477
478 /* vim: set noet sws=4 sw=4: */
RTLD_DEFAULT
#define RTLD_DEFAULT
Definition: handle.c:292
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:327
fiddle.h
mFiddle
VALUE mFiddle
Definition: fiddle.c:3
strlen
size_t strlen(const char *)
INT2NUM
#define INT2NUM(x)
Definition: ruby.h:1288
dl_handle::open
int open
Definition: dl.h:183
NUM2INT
#define NUM2INT(x)
Definition: ruby.h:630
rb_fiddle_handle_close
static VALUE rb_fiddle_handle_close(VALUE self)
Definition: handle.c:65
rb_define_singleton_method
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1655
dl_handle
Definition: dl.h:181
Qtrue
#define Qtrue
Definition: ruby.h:426
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1041
ruby.h
UNREACHABLE
#define UNREACHABLE
Definition: ruby.h:42
rb_fiddle_handle_sym
static VALUE rb_fiddle_handle_sym(VALUE self, VALUE sym)
Definition: handle.c:276
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:676
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
DATA_PTR
#define DATA_PTR(dta)
Definition: ruby.h:992
rb_fiddle_handle_s_allocate
static VALUE rb_fiddle_handle_s_allocate(VALUE klass)
Definition: handle.c:90
rb_w32_map_errno
int rb_w32_map_errno(DWORD)
Definition: win32.c:250
Init_fiddle_handle
void Init_fiddle_handle(void)
Definition: handle.c:377
sym
#define sym(x)
Definition: date_core.c:3695
rb_fiddle_handle_disable_close
static VALUE rb_fiddle_handle_disable_close(VALUE self)
Definition: handle.c:225
rb_eFiddleError
VALUE rb_eFiddleError
Definition: fiddle.c:4
predefined_fiddle_handle
static VALUE predefined_fiddle_handle(void *handle)
Definition: handle.c:104
rb_block_given_p
int rb_block_given_p(void)
Definition: eval.c:712
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1553
NIL_P
#define NIL_P(v)
Definition: ruby.h:438
dl_handle::enable_close
int enable_close
Definition: dl.h:184
PTR2NUM
#define PTR2NUM(x)
Definition: dl.h:168
rb_define_const
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2225
argc
int argc
Definition: ruby.c:131
Qfalse
#define Qfalse
Definition: ruby.h:425
err
int err
Definition: win32.c:114
OBJ_FREEZE
#define OBJ_FREEZE(x)
Definition: ruby.h:1186
fiddle_handle_memsize
static size_t fiddle_handle_memsize(const void *ptr)
Definition: handle.c:47
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:942
func
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:113
errno
int errno
rb_fiddle_handle_initialize
static VALUE rb_fiddle_handle_initialize(int argc, VALUE argv[], VALUE self)
Definition: handle.c:131
rb_fiddle_handle_close_enabled_p
static VALUE rb_fiddle_handle_close_enabled_p(VALUE self)
Definition: handle.c:242
const
#define const
Definition: strftime.c:102
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1728
Qnil
#define Qnil
Definition: ruby.h:427
VALUE
unsigned long VALUE
Definition: ruby.h:88
RTLD_NEXT
#define RTLD_NEXT
Definition: handle.c:289
rb_ensure
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:839
fiddle_handle_data_type
static const rb_data_type_t fiddle_handle_data_type
Definition: handle.c:52
StringValueCStr
#define StringValueCStr(v)
Definition: ruby.h:541
rb_fiddle_handle_to_i
static VALUE rb_fiddle_handle_to_i(VALUE self)
Definition: handle.c:258
rb_cHandle
VALUE rb_cHandle
Definition: handle.c:4
xmalloc
#define xmalloc
Definition: defines.h:108
rb_data_type_struct
Definition: ruby.h:966
rb_fiddle_handle_enable_close
static VALUE rb_fiddle_handle_enable_close(VALUE self)
Definition: handle.c:210
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1030
name
const char * name
Definition: nkf.c:208
xrealloc
#define xrealloc
Definition: defines.h:111
fiddle_handle_free
static void fiddle_handle_free(void *ptr)
Definition: handle.c:37
StringValuePtr
#define StringValuePtr(v)
Definition: ruby.h:540
STRCASECMP
#define STRCASECMP(s1, s2)
Definition: ruby.h:1783
CHECK_DLERROR
#define CHECK_DLERROR
rb_secure
void rb_secure(int)
Definition: safe.c:88
xfree
void void xfree(void *)
dl_handle::ptr
void * ptr
Definition: dl.h:182
NULL
#define NULL
Definition: _sdbm.c:103
fiddle_handle_sym
static VALUE fiddle_handle_sym(void *handle, const char *symbol)
Definition: handle.c:312
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1488
rb_fiddle_handle_s_sym
static VALUE rb_fiddle_handle_s_sym(VALUE self, VALUE sym)
Definition: handle.c:306
argv
char ** argv
Definition: ruby.c:132