Ruby  2.1.3p242(2014-09-19revision47630)
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(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
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() ){
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
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
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
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
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
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
307 {
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);
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);
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);
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);
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
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  */
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  */
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  */
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 
476 }
477 
478 /* vim: set noet sws=4 sw=4: */
#define RTLD_DEFAULT
Definition: handle.c:292
void rb_bug(const char *fmt,...)
Definition: error.c:327
VALUE mFiddle
Definition: fiddle.c:3
size_t strlen(const char *)
#define INT2NUM(x)
Definition: ruby.h:1288
int open
Definition: dl.h:183
#define NUM2INT(x)
Definition: ruby.h:630
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:1655
Definition: dl.h:181
#define Qtrue
Definition: ruby.h:426
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1041
#define UNREACHABLE
Definition: ruby.h:42
static VALUE rb_fiddle_handle_sym(VALUE self, VALUE sym)
Definition: handle.c:276
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:676
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1854
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
#define DATA_PTR(dta)
Definition: ruby.h:992
static VALUE rb_fiddle_handle_s_allocate(VALUE klass)
Definition: handle.c:90
int rb_w32_map_errno(DWORD)
Definition: win32.c:250
void Init_fiddle_handle(void)
Definition: handle.c:377
#define sym(x)
Definition: date_core.c:3695
static VALUE rb_fiddle_handle_disable_close(VALUE self)
Definition: handle.c:225
VALUE rb_eFiddleError
Definition: fiddle.c:4
static VALUE predefined_fiddle_handle(void *handle)
Definition: handle.c:104
int rb_block_given_p(void)
Definition: eval.c:712
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1553
#define NIL_P(v)
Definition: ruby.h:438
int enable_close
Definition: dl.h:184
#define PTR2NUM(x)
Definition: dl.h:168
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2225
int argc
Definition: ruby.c:131
#define Qfalse
Definition: ruby.h:425
int err
Definition: win32.c:114
#define OBJ_FREEZE(x)
Definition: ruby.h:1186
static size_t fiddle_handle_memsize(const void *ptr)
Definition: handle.c:47
VALUE rb_yield(VALUE)
Definition: vm_eval.c:942
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:113
int errno
static VALUE rb_fiddle_handle_initialize(int argc, VALUE argv[], VALUE self)
Definition: handle.c:131
static VALUE rb_fiddle_handle_close_enabled_p(VALUE self)
Definition: handle.c:242
#define const
Definition: strftime.c:102
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1728
#define Qnil
Definition: ruby.h:427
unsigned long VALUE
Definition: ruby.h:88
#define RTLD_NEXT
Definition: handle.c:289
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:839
static const rb_data_type_t fiddle_handle_data_type
Definition: handle.c:52
#define StringValueCStr(v)
Definition: ruby.h:541
static VALUE rb_fiddle_handle_to_i(VALUE self)
Definition: handle.c:258
VALUE rb_cHandle
Definition: handle.c:4
#define xmalloc
Definition: defines.h:108
static VALUE rb_fiddle_handle_enable_close(VALUE self)
Definition: handle.c:210
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1030
const char * name
Definition: nkf.c:208
#define xrealloc
Definition: defines.h:111
static void fiddle_handle_free(void *ptr)
Definition: handle.c:37
#define StringValuePtr(v)
Definition: ruby.h:540
#define STRCASECMP(s1, s2)
Definition: ruby.h:1783
#define CHECK_DLERROR
void rb_secure(int)
Definition: safe.c:88
void void xfree(void *)
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:312
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1488
static VALUE rb_fiddle_handle_s_sym(VALUE self, VALUE sym)
Definition: handle.c:306
char ** argv
Definition: ruby.c:132