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