Ruby  2.0.0p645(2015-04-13revision50299)
handle.c
Go to the documentation of this file.
1 #include <ruby.h>
2 #include <fiddle.h>
3 
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
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 
53  "fiddle/handle",
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
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 
87 }
88 
89 static VALUE
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
105 {
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(lib = nil, flags = Fiddle::RTLD_LAZY | Fiddle::RTLD_GLOBAL)
118  *
119  * Create a new handler that opens library named +lib+ with +flags+. If no
120  * library is specified, RTLD_DEFAULT is used.
121  */
122 static VALUE
124 {
125  void *ptr;
126  struct dl_handle *fiddle_handle;
127  VALUE lib, flag;
128  char *clib;
129  int cflag;
130  const char *err;
131 
132  switch( rb_scan_args(argc, argv, "02", &lib, &flag) ){
133  case 0:
134  clib = NULL;
135  cflag = RTLD_LAZY | RTLD_GLOBAL;
136  break;
137  case 1:
138  clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
139  cflag = RTLD_LAZY | RTLD_GLOBAL;
140  break;
141  case 2:
142  clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
143  cflag = NUM2INT(flag);
144  break;
145  default:
146  rb_bug("rb_fiddle_handle_new");
147  }
148 
149  rb_secure(2);
150 
151 #if defined(_WIN32)
152  if( !clib ){
153  HANDLE rb_libruby_handle(void);
154  ptr = rb_libruby_handle();
155  }
156  else if( STRCASECMP(clib, "libc") == 0
157 # ifdef RUBY_COREDLL
158  || STRCASECMP(clib, RUBY_COREDLL) == 0
159  || STRCASECMP(clib, RUBY_COREDLL".dll") == 0
160 # endif
161  ){
162 # ifdef _WIN32_WCE
163  ptr = dlopen("coredll.dll", cflag);
164 # else
165  ptr = w32_coredll();
166 # endif
167  }
168  else
169 #endif
170  ptr = dlopen(clib, cflag);
171 #if defined(HAVE_DLERROR)
172  if( !ptr && (err = dlerror()) ){
173  rb_raise(rb_eFiddleError, "%s", err);
174  }
175 #else
176  if( !ptr ){
177  err = dlerror();
178  rb_raise(rb_eFiddleError, "%s", err);
179  }
180 #endif
181  TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
182  if( fiddle_handle->ptr && fiddle_handle->open && fiddle_handle->enable_close ){
183  dlclose(fiddle_handle->ptr);
184  }
185  fiddle_handle->ptr = ptr;
186  fiddle_handle->open = 1;
187  fiddle_handle->enable_close = 0;
188 
189  if( rb_block_given_p() ){
191  }
192 
193  return Qnil;
194 }
195 
196 /*
197  * call-seq: enable_close
198  *
199  * Enable a call to dlclose() when this handle is garbage collected.
200  */
201 static VALUE
203 {
204  struct dl_handle *fiddle_handle;
205 
206  TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
207  fiddle_handle->enable_close = 1;
208  return Qnil;
209 }
210 
211 /*
212  * call-seq: disable_close
213  *
214  * Disable a call to dlclose() when this handle is garbage collected.
215  */
216 static VALUE
218 {
219  struct dl_handle *fiddle_handle;
220 
221  TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
222  fiddle_handle->enable_close = 0;
223  return Qnil;
224 }
225 
226 /*
227  * call-seq: close_enabled?
228  *
229  * Returns +true+ if dlclose() will be called when this handle is garbage collected.
230  *
231  * See man(3) dlclose() for more info.
232  */
233 static VALUE
235 {
236  struct dl_handle *fiddle_handle;
237 
238  TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
239 
240  if(fiddle_handle->enable_close) return Qtrue;
241  return Qfalse;
242 }
243 
244 /*
245  * call-seq: to_i
246  *
247  * Returns the memory address for this handle.
248  */
249 static VALUE
251 {
252  struct dl_handle *fiddle_handle;
253 
254  TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
255  return PTR2NUM(fiddle_handle);
256 }
257 
258 static VALUE fiddle_handle_sym(void *handle, const char *symbol);
259 
260 /*
261  * Document-method: sym
262  *
263  * call-seq: sym(name)
264  *
265  * Get the address as an Integer for the function named +name+.
266  */
267 static VALUE
269 {
270  struct dl_handle *fiddle_handle;
271 
272  TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
273  if( ! fiddle_handle->open ){
274  rb_raise(rb_eFiddleError, "closed handle");
275  }
276 
277  return fiddle_handle_sym(fiddle_handle->ptr, StringValueCStr(sym));
278 }
279 
280 #ifndef RTLD_NEXT
281 #define RTLD_NEXT NULL
282 #endif
283 #ifndef RTLD_DEFAULT
284 #define RTLD_DEFAULT NULL
285 #endif
286 
287 /*
288  * Document-method: sym
289  *
290  * call-seq: sym(name)
291  *
292  * Get the address as an Integer for the function named +name+. The function
293  * is searched via dlsym on RTLD_NEXT.
294  *
295  * See man(3) dlsym() for more info.
296  */
297 static VALUE
299 {
301 }
302 
303 static VALUE
304 fiddle_handle_sym(void *handle, const char *name)
305 {
306 #if defined(HAVE_DLERROR)
307  const char *err;
308 # define CHECK_DLERROR if( err = dlerror() ){ func = 0; }
309 #else
310 # define CHECK_DLERROR
311 #endif
312  void (*func)();
313 
314  rb_secure(2);
315 #ifdef HAVE_DLERROR
316  dlerror();
317 #endif
318  func = (void (*)())(VALUE)dlsym(handle, name);
320 #if defined(FUNC_STDCALL)
321  if( !func ){
322  int i;
323  int len = (int)strlen(name);
324  char *name_n;
325 #if defined(__CYGWIN__) || defined(_WIN32) || defined(__MINGW32__)
326  {
327  char *name_a = (char*)xmalloc(len+2);
328  strcpy(name_a, name);
329  name_n = name_a;
330  name_a[len] = 'A';
331  name_a[len+1] = '\0';
332  func = dlsym(handle, name_a);
334  if( func ) goto found;
335  name_n = xrealloc(name_a, len+6);
336  }
337 #else
338  name_n = (char*)xmalloc(len+6);
339 #endif
340  memcpy(name_n, name, len);
341  name_n[len++] = '@';
342  for( i = 0; i < 256; i += 4 ){
343  sprintf(name_n + len, "%d", i);
344  func = dlsym(handle, name_n);
346  if( func ) break;
347  }
348  if( func ) goto found;
349  name_n[len-1] = 'A';
350  name_n[len++] = '@';
351  for( i = 0; i < 256; i += 4 ){
352  sprintf(name_n + len, "%d", i);
353  func = dlsym(handle, name_n);
355  if( func ) break;
356  }
357  found:
358  xfree(name_n);
359  }
360 #endif
361  if( !func ){
362  rb_raise(rb_eFiddleError, "unknown symbol \"%s\"", name);
363  }
364 
365  return PTR2NUM(func);
366 }
367 
368 void
370 {
371  /*
372  * Document-class: Fiddle::Handle
373  *
374  * The Fiddle::Handle is the manner to access the dynamic library
375  *
376  * == Example
377  *
378  * === Setup
379  *
380  * libc_so = "/lib64/libc.so.6"
381  * => "/lib64/libc.so.6"
382  * @handle = Fiddle::Handle.new(libc_so)
383  * => #<Fiddle::Handle:0x00000000d69ef8>
384  *
385  * === Setup, with flags
386  *
387  * libc_so = "/lib64/libc.so.6"
388  * => "/lib64/libc.so.6"
389  * @handle = Fiddle::Handle.new(libc_so, Fiddle::RTLD_LAZY | Fiddle::RTLD_GLOBAL)
390  * => #<Fiddle::Handle:0x00000000d69ef8>
391  *
392  * See RTLD_LAZY and RTLD_GLOBAL
393  *
394  * === Addresses to symbols
395  *
396  * strcpy_addr = @handle['strcpy']
397  * => 140062278451968
398  *
399  * or
400  *
401  * strcpy_addr = @handle.sym('strcpy')
402  * => 140062278451968
403  *
404  */
409 
410  /* Document-const: NEXT
411  *
412  * A predefined pseudo-handle of RTLD_NEXT
413  *
414  * Which will find the next occurrence of a function in the search order
415  * after the current library.
416  */
418 
419  /* Document-const: DEFAULT
420  *
421  * A predefined pseudo-handle of RTLD_DEFAULT
422  *
423  * Which will find the first occurrence of the desired symbol using the
424  * default library search order
425  */
427 
428  /* Document-const: RTLD_GLOBAL
429  *
430  * rtld Fiddle::Handle flag.
431  *
432  * The symbols defined by this library will be made available for symbol
433  * resolution of subsequently loaded libraries.
434  */
435  rb_define_const(rb_cHandle, "RTLD_GLOBAL", INT2NUM(RTLD_GLOBAL));
436 
437  /* Document-const: RTLD_LAZY
438  *
439  * rtld Fiddle::Handle flag.
440  *
441  * Perform lazy binding. Only resolve symbols as the code that references
442  * them is executed. If the symbol is never referenced, then it is never
443  * resolved. (Lazy binding is only performed for function references;
444  * references to variables are always immediately bound when the library
445  * is loaded.)
446  */
447  rb_define_const(rb_cHandle, "RTLD_LAZY", INT2NUM(RTLD_LAZY));
448 
449  /* Document-const: RTLD_NOW
450  *
451  * rtld Fiddle::Handle flag.
452  *
453  * If this value is specified or the environment variable LD_BIND_NOW is
454  * set to a nonempty string, all undefined symbols in the library are
455  * resolved before Fiddle.dlopen returns. If this cannot be done an error
456  * is returned.
457  */
458  rb_define_const(rb_cHandle, "RTLD_NOW", INT2NUM(RTLD_NOW));
459 
468 }
469 
470 /* vim: set noet sws=4 sw=4: */
VALUE sym
Definition: tkutil.c:1298
#define RTLD_DEFAULT
Definition: handle.c:284
VP_EXPORT int
Definition: bigdecimal.c:5071
void rb_bug(const char *fmt,...)
Definition: error.c:295
VALUE mFiddle
Definition: fiddle.c:3
size_t strlen(const char *)
int open
Definition: dl.h:183
static VALUE rb_fiddle_handle_close(VALUE self)
Definition: handle.c:65
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1497
Definition: dl.h:181
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:108
void rb_secure(int)
Definition: safe.c:79
ssize_t i
Definition: bigdecimal.c:5676
int ret
Definition: tcltklib.c:280
#define OBJ_FREEZE(x)
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
#define UNREACHABLE
Definition: ruby.h:40
static VALUE rb_fiddle_handle_sym(VALUE self, VALUE sym)
Definition: handle.c:268
NIL_P(eventloop_thread)
Definition: tcltklib.c:4067
#define xfree
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:534
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1788
return Qtrue
Definition: tcltklib.c:9609
static VALUE rb_fiddle_handle_s_allocate(VALUE klass)
Definition: handle.c:90
int rb_w32_map_errno(DWORD)
Definition: win32.c:223
flag
Definition: tcltklib.c:2047
static VALUE rb_fiddle_handle_disable_close(VALUE self)
Definition: handle.c:217
VALUE rb_eFiddleError
Definition: fiddle.c:4
strcpy(cmd2, cmd)
void Init_fiddle_handle(void)
Definition: handle.c:369
memset(y->frac+ix+1, 0,(y->Prec-(ix+1))*sizeof(BDIGIT))
BDIGIT m
Definition: bigdecimal.c:5106
static VALUE predefined_fiddle_handle(void *handle)
Definition: handle.c:104
return Qfalse
Definition: tcltklib.c:6778
#define TypedData_Get_Struct(obj, type, data_type, sval)
int rb_block_given_p(void)
Definition: eval.c:672
#define Qnil
Definition: tcltklib.c:1895
#define StringValuePtr(v)
#define STRCASECMP(s1, s2)
#define StringValueCStr(v)
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2204
static VALUE VALUE obj
Definition: tcltklib.c:3157
int enable_close
Definition: dl.h:184
#define PTR2NUM(x)
Definition: dl.h:168
#define xmalloc
#define xrealloc
int err
Definition: win32.c:87
static size_t fiddle_handle_memsize(const void *ptr)
Definition: handle.c:47
VALUE * argv
Definition: tcltklib.c:1970
VALUE rb_yield(VALUE)
Definition: vm_eval.c:933
memcpy(buf+1, str, len)
int errno
static VALUE rb_fiddle_handle_initialize(int argc, VALUE argv[], VALUE self)
Definition: handle.c:123
static VALUE rb_fiddle_handle_close_enabled_p(VALUE self)
Definition: handle.c:234
#define const
Definition: strftime.c:102
VP_EXPORT void
Definition: bigdecimal.c:5104
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1570
int argc
Definition: tcltklib.c:1969
#define RTLD_NEXT
Definition: handle.c:281
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:804
return ptr
Definition: tcltklib.c:784
static const rb_data_type_t fiddle_handle_data_type
Definition: handle.c:52
static VALUE rb_fiddle_handle_to_i(VALUE self)
Definition: handle.c:250
VALUE rb_cHandle
Definition: handle.c:4
DATA_PTR(self)
#define TypedData_Make_Struct(klass, type, data_type, sval)
static VALUE rb_fiddle_handle_enable_close(VALUE self)
Definition: handle.c:202
RUBY_EXTERN VALUE rb_cObject
Definition: ripper.y:1426
klass
Definition: tcltklib.c:3503
#define INT2NUM(x)
#define NUM2INT(x)
static void fiddle_handle_free(void *ptr)
Definition: handle.c:37
unsigned long VALUE
Definition: ripper.y:104
#define CHECK_DLERROR
void * ptr
Definition: dl.h:182
#define NULL
Definition: _sdbm.c:102
const char * name
Definition: nkf.c:208
static VALUE fiddle_handle_sym(void *handle, const char *symbol)
Definition: handle.c:304
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1344
static VALUE rb_fiddle_handle_s_sym(VALUE self, VALUE sym)
Definition: handle.c:298
size_t len
Definition: tcltklib.c:3567