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 /* -*- C -*-
2 * $Id: handle.c 45820 2014-05-04 17:32:44Z nagachika $
3 */
4
5 #include <ruby.h>
6 #include "dl.h"
7
8 VALUE rb_cDLHandle;
9
10 #ifdef _WIN32
11 # ifndef _WIN32_WCE
12 static void *
13 w32_coredll(void)
14 {
15 MEMORY_BASIC_INFORMATION m;
16 memset(&m, 0, sizeof(m));
17 if( !VirtualQuery(_errno, &m, sizeof(m)) ) return NULL;
18 return m.AllocationBase;
19 }
20 # endif
21
22 static int
23 w32_dlclose(void *ptr)
24 {
25 # ifndef _WIN32_WCE
26 if( ptr == w32_coredll() ) return 0;
27 # endif
28 if( FreeLibrary((HMODULE)ptr) ) return 0;
29 return errno = rb_w32_map_errno(GetLastError());
30 }
31 #define dlclose(ptr) w32_dlclose(ptr)
32 #endif
33
34 static void
35 dlhandle_free(void *ptr)
36 {
37 struct dl_handle *dlhandle = ptr;
38 if( dlhandle->ptr && dlhandle->open && dlhandle->enable_close ){
39 dlclose(dlhandle->ptr);
40 }
41 xfree(ptr);
42 }
43
44 static size_t
45 dlhandle_memsize(const void *ptr)
46 {
47 return ptr ? sizeof(struct dl_handle) : 0;
48 }
49
50 static const rb_data_type_t dlhandle_data_type = {
51 "dl/handle",
52 {0, dlhandle_free, dlhandle_memsize,},
53 };
54
55 /*
56 * call-seq: close
57 *
58 * Close this DL::Handle. Calling close more than once will raise a
59 * DL::DLError exception.
60 */
61 VALUE
62 rb_dlhandle_close(VALUE self)
63 {
64 struct dl_handle *dlhandle;
65
66 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
67 if(dlhandle->open) {
68 int ret = dlclose(dlhandle->ptr);
69 dlhandle->open = 0;
70
71 /* Check dlclose for successful return value */
72 if(ret) {
73 #if defined(HAVE_DLERROR)
74 rb_raise(rb_eDLError, "%s", dlerror());
75 #else
76 rb_raise(rb_eDLError, "could not close handle");
77 #endif
78 }
79 return INT2NUM(ret);
80 }
81 rb_raise(rb_eDLError, "dlclose() called too many times");
82
83 UNREACHABLE;
84 }
85
86 VALUE
87 rb_dlhandle_s_allocate(VALUE klass)
88 {
89 VALUE obj;
90 struct dl_handle *dlhandle;
91
92 obj = TypedData_Make_Struct(rb_cDLHandle, struct dl_handle, &dlhandle_data_type, dlhandle);
93 dlhandle->ptr = 0;
94 dlhandle->open = 0;
95 dlhandle->enable_close = 0;
96
97 return obj;
98 }
99
100 static VALUE
101 predefined_dlhandle(void *handle)
102 {
103 VALUE obj = rb_dlhandle_s_allocate(rb_cDLHandle);
104 struct dl_handle *dlhandle = DATA_PTR(obj);
105
106 dlhandle->ptr = handle;
107 dlhandle->open = 1;
108 OBJ_FREEZE(obj);
109 return obj;
110 }
111
112 /*
113 * call-seq:
114 * initialize(lib = nil, flags = DL::RTLD_LAZY | DL::RTLD_GLOBAL)
115 *
116 * Create a new handler that opens library named +lib+ with +flags+. If no
117 * library is specified, RTLD_DEFAULT is used.
118 */
119 VALUE
120 rb_dlhandle_initialize(int argc, VALUE argv[], VALUE self)
121 {
122 void *ptr;
123 struct dl_handle *dlhandle;
124 VALUE lib, flag;
125 char *clib;
126 int cflag;
127 const char *err;
128
129 switch( rb_scan_args(argc, argv, "02", &lib, &flag) ){
130 case 0:
131 clib = NULL;
132 cflag = RTLD_LAZY | RTLD_GLOBAL;
133 break;
134 case 1:
135 clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
136 cflag = RTLD_LAZY | RTLD_GLOBAL;
137 break;
138 case 2:
139 clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
140 cflag = NUM2INT(flag);
141 break;
142 default:
143 rb_bug("rb_dlhandle_new");
144 }
145
146 rb_secure(2);
147
148 #if defined(_WIN32)
149 if( !clib ){
150 HANDLE rb_libruby_handle(void);
151 ptr = rb_libruby_handle();
152 }
153 else if( STRCASECMP(clib, "libc") == 0
154 # ifdef RUBY_COREDLL
155 || STRCASECMP(clib, RUBY_COREDLL) == 0
156 || STRCASECMP(clib, RUBY_COREDLL".dll") == 0
157 # endif
158 ){
159 # ifdef _WIN32_WCE
160 ptr = dlopen("coredll.dll", cflag);
161 # else
162 ptr = w32_coredll();
163 # endif
164 }
165 else
166 #endif
167 ptr = dlopen(clib, cflag);
168 #if defined(HAVE_DLERROR)
169 if( !ptr && (err = dlerror()) ){
170 rb_raise(rb_eDLError, "%s", err);
171 }
172 #else
173 if( !ptr ){
174 err = dlerror();
175 rb_raise(rb_eDLError, "%s", err);
176 }
177 #endif
178 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
179 if( dlhandle->ptr && dlhandle->open && dlhandle->enable_close ){
180 dlclose(dlhandle->ptr);
181 }
182 dlhandle->ptr = ptr;
183 dlhandle->open = 1;
184 dlhandle->enable_close = 0;
185
186 if( rb_block_given_p() ){
187 rb_ensure(rb_yield, self, rb_dlhandle_close, self);
188 }
189
190 return Qnil;
191 }
192
193 /*
194 * call-seq: enable_close
195 *
196 * Enable a call to dlclose() when this DL::Handle is garbage collected.
197 */
198 VALUE
199 rb_dlhandle_enable_close(VALUE self)
200 {
201 struct dl_handle *dlhandle;
202
203 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
204 dlhandle->enable_close = 1;
205 return Qnil;
206 }
207
208 /*
209 * call-seq: disable_close
210 *
211 * Disable a call to dlclose() when this DL::Handle is garbage collected.
212 */
213 VALUE
214 rb_dlhandle_disable_close(VALUE self)
215 {
216 struct dl_handle *dlhandle;
217
218 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
219 dlhandle->enable_close = 0;
220 return Qnil;
221 }
222
223 /*
224 * call-seq: close_enabled?
225 *
226 * Returns +true+ if dlclose() will be called when this DL::Handle is
227 * garbage collected.
228 */
229 static VALUE
230 rb_dlhandle_close_enabled_p(VALUE self)
231 {
232 struct dl_handle *dlhandle;
233
234 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
235
236 if(dlhandle->enable_close) return Qtrue;
237 return Qfalse;
238 }
239
240 /*
241 * call-seq: to_i
242 *
243 * Returns the memory address for this handle.
244 */
245 VALUE
246 rb_dlhandle_to_i(VALUE self)
247 {
248 struct dl_handle *dlhandle;
249
250 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
251 return PTR2NUM(dlhandle);
252 }
253
254 static VALUE dlhandle_sym(void *handle, const char *symbol);
255
256 /*
257 * Document-method: sym
258 * Document-method: []
259 *
260 * call-seq: sym(name)
261 *
262 * Get the address as an Integer for the function named +name+.
263 */
264 VALUE
265 rb_dlhandle_sym(VALUE self, VALUE sym)
266 {
267 struct dl_handle *dlhandle;
268
269 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
270 if( ! dlhandle->open ){
271 rb_raise(rb_eDLError, "closed handle");
272 }
273
274 return dlhandle_sym(dlhandle->ptr, StringValueCStr(sym));
275 }
276
277 #ifndef RTLD_NEXT
278 #define RTLD_NEXT NULL
279 #endif
280 #ifndef RTLD_DEFAULT
281 #define RTLD_DEFAULT NULL
282 #endif
283
284 /*
285 * Document-method: sym
286 * Document-method: []
287 *
288 * call-seq: sym(name)
289 *
290 * Get the address as an Integer for the function named +name+. The function
291 * is searched via dlsym on RTLD_NEXT. See man(3) dlsym() for more info.
292 */
293 VALUE
294 rb_dlhandle_s_sym(VALUE self, VALUE sym)
295 {
296 return dlhandle_sym(RTLD_NEXT, StringValueCStr(sym));
297 }
298
299 static VALUE
300 dlhandle_sym(void *handle, const char *name)
301 {
302 #if defined(HAVE_DLERROR)
303 const char *err;
304 # define CHECK_DLERROR if( err = dlerror() ){ func = 0; }
305 #else
306 # define CHECK_DLERROR
307 #endif
308 void (*func)();
309
310 rb_secure(2);
311 #ifdef HAVE_DLERROR
312 dlerror();
313 #endif
314 func = (void (*)())(VALUE)dlsym(handle, name);
315 CHECK_DLERROR;
316 #if defined(FUNC_STDCALL)
317 if( !func ){
318 int i;
319 int len = (int)strlen(name);
320 char *name_n;
321 #if defined(__CYGWIN__) || defined(_WIN32) || defined(__MINGW32__)
322 {
323 char *name_a = (char*)xmalloc(len+2);
324 strcpy(name_a, name);
325 name_n = name_a;
326 name_a[len] = 'A';
327 name_a[len+1] = '\0';
328 func = dlsym(handle, name_a);
329 CHECK_DLERROR;
330 if( func ) goto found;
331 name_n = xrealloc(name_a, len+6);
332 }
333 #else
334 name_n = (char*)xmalloc(len+6);
335 #endif
336 memcpy(name_n, name, len);
337 name_n[len++] = '@';
338 for( i = 0; i < 256; i += 4 ){
339 sprintf(name_n + len, "%d", i);
340 func = dlsym(handle, name_n);
341 CHECK_DLERROR;
342 if( func ) break;
343 }
344 if( func ) goto found;
345 name_n[len-1] = 'A';
346 name_n[len++] = '@';
347 for( i = 0; i < 256; i += 4 ){
348 sprintf(name_n + len, "%d", i);
349 func = dlsym(handle, name_n);
350 CHECK_DLERROR;
351 if( func ) break;
352 }
353 found:
354 xfree(name_n);
355 }
356 #endif
357 if( !func ){
358 rb_raise(rb_eDLError, "unknown symbol \"%s\"", name);
359 }
360
361 return PTR2NUM(func);
362 }
363
364 void
365 Init_dlhandle(void)
366 {
367 /*
368 * Document-class: DL::Handle
369 *
370 * The DL::Handle is the manner to access the dynamic library
371 *
372 * == Example
373 *
374 * === Setup
375 *
376 * libc_so = "/lib64/libc.so.6"
377 * => "/lib64/libc.so.6"
378 * @handle = DL::Handle.new(libc_so)
379 * => #<DL::Handle:0x00000000d69ef8>
380 *
381 * === Setup, with flags
382 *
383 * libc_so = "/lib64/libc.so.6"
384 * => "/lib64/libc.so.6"
385 * @handle = DL::Handle.new(libc_so, DL::RTLD_LAZY | DL::RTLD_GLOBAL)
386 * => #<DL::Handle:0x00000000d69ef8>
387 *
388 * === Addresses to symbols
389 *
390 * strcpy_addr = @handle['strcpy']
391 * => 140062278451968
392 *
393 * or
394 *
395 * strcpy_addr = @handle.sym('strcpy')
396 * => 140062278451968
397 *
398 */
399 rb_cDLHandle = rb_define_class_under(rb_mDL, "Handle", rb_cObject);
400 rb_define_alloc_func(rb_cDLHandle, rb_dlhandle_s_allocate);
401 rb_define_singleton_method(rb_cDLHandle, "sym", rb_dlhandle_s_sym, 1);
402 rb_define_singleton_method(rb_cDLHandle, "[]", rb_dlhandle_s_sym, 1);
403
404 /* Document-const: NEXT
405 *
406 * A predefined pseudo-handle of RTLD_NEXT
407 *
408 * Which will find the next occurrence of a function in the search order
409 * after the current library.
410 */
411 rb_define_const(rb_cDLHandle, "NEXT", predefined_dlhandle(RTLD_NEXT));
412
413 /* Document-const: DEFAULT
414 *
415 * A predefined pseudo-handle of RTLD_DEFAULT
416 *
417 * Which will find the first occurrence of the desired symbol using the
418 * default library search order
419 */
420 rb_define_const(rb_cDLHandle, "DEFAULT", predefined_dlhandle(RTLD_DEFAULT));
421 rb_define_method(rb_cDLHandle, "initialize", rb_dlhandle_initialize, -1);
422 rb_define_method(rb_cDLHandle, "to_i", rb_dlhandle_to_i, 0);
423 rb_define_method(rb_cDLHandle, "close", rb_dlhandle_close, 0);
424 rb_define_method(rb_cDLHandle, "sym", rb_dlhandle_sym, 1);
425 rb_define_method(rb_cDLHandle, "[]", rb_dlhandle_sym, 1);
426 rb_define_method(rb_cDLHandle, "disable_close", rb_dlhandle_disable_close, 0);
427 rb_define_method(rb_cDLHandle, "enable_close", rb_dlhandle_enable_close, 0);
428 rb_define_method(rb_cDLHandle, "close_enabled?", rb_dlhandle_close_enabled_p, 0);
429 }
430
431 /* mode: c; tab-with=8; sw=4; ts=8; noexpandtab: */
dlhandle_memsize
static size_t dlhandle_memsize(const void *ptr)
Definition: handle.c:45
rb_dlhandle_close_enabled_p
static VALUE rb_dlhandle_close_enabled_p(VALUE self)
Definition: handle.c:230
rb_mDL
VALUE rb_mDL
Definition: dl.c:13
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:327
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_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
RTLD_DEFAULT
#define RTLD_DEFAULT
Definition: handle.c:281
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
rb_dlhandle_initialize
VALUE rb_dlhandle_initialize(int argc, VALUE argv[], VALUE self)
Definition: handle.c:120
dl.h
UNREACHABLE
#define UNREACHABLE
Definition: ruby.h:42
dlhandle_data_type
static const rb_data_type_t dlhandle_data_type
Definition: handle.c:50
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_dlhandle_enable_close
VALUE rb_dlhandle_enable_close(VALUE self)
Definition: handle.c:199
rb_eDLError
VALUE rb_eDLError
Definition: dl.c:14
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
rb_dlhandle_to_i
VALUE rb_dlhandle_to_i(VALUE self)
Definition: handle.c:246
DATA_PTR
#define DATA_PTR(dta)
Definition: ruby.h:992
rb_w32_map_errno
int rb_w32_map_errno(DWORD)
Definition: win32.c:250
RTLD_NEXT
#define RTLD_NEXT
Definition: handle.c:278
sym
#define sym(x)
Definition: date_core.c:3695
rb_block_given_p
int rb_block_given_p(void)
Definition: eval.c:712
dlhandle_sym
static VALUE dlhandle_sym(void *handle, const char *symbol)
Definition: handle.c:300
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1553
NIL_P
#define NIL_P(v)
Definition: ruby.h:438
rb_dlhandle_s_allocate
VALUE rb_dlhandle_s_allocate(VALUE klass)
Definition: handle.c:87
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
Init_dlhandle
void Init_dlhandle(void)
Definition: handle.c:365
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
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:942
func
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:113
errno
int errno
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
rb_cDLHandle
VALUE rb_cDLHandle
Definition: handle.c:8
rb_dlhandle_s_sym
VALUE rb_dlhandle_s_sym(VALUE self, VALUE sym)
Definition: handle.c:294
VALUE
unsigned long VALUE
Definition: ruby.h:88
rb_ensure
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:839
StringValueCStr
#define StringValueCStr(v)
Definition: ruby.h:541
rb_dlhandle_close
VALUE rb_dlhandle_close(VALUE self)
Definition: handle.c:62
predefined_dlhandle
static VALUE predefined_dlhandle(void *handle)
Definition: handle.c:101
rb_dlhandle_disable_close
VALUE rb_dlhandle_disable_close(VALUE self)
Definition: handle.c:214
xmalloc
#define xmalloc
Definition: defines.h:108
rb_data_type_struct
Definition: ruby.h:966
rb_dlhandle_sym
VALUE rb_dlhandle_sym(VALUE self, VALUE sym)
Definition: handle.c:265
dlhandle_free
static void dlhandle_free(void *ptr)
Definition: handle.c:35
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
StringValuePtr
#define StringValuePtr(v)
Definition: ruby.h:540
STRCASECMP
#define STRCASECMP(s1, s2)
Definition: ruby.h:1783
rb_secure
void rb_secure(int)
Definition: safe.c:88
xfree
void void xfree(void *)
CHECK_DLERROR
#define CHECK_DLERROR
dl_handle::ptr
void * ptr
Definition: dl.h:182
NULL
#define NULL
Definition: _sdbm.c:103
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1488
argv
char ** argv
Definition: ruby.c:132