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