Ruby  2.0.0p645(2015-04-13revision50299)
handle.c
Go to the documentation of this file.
1 /* -*- C -*-
2  * $Id: handle.c 46508 2014-06-23 07:52:37Z usa $
3  */
4 
5 #include <ruby.h>
6 #include "dl.h"
7 
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 
51  "dl/handle",
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
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 
84 }
85 
86 VALUE
88 {
89  VALUE obj;
90  struct dl_handle *dlhandle;
91 
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 {
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
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
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
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
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
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
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
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);
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);
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);
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);
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
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  */
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  */
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  */
429 }
430 
431 /* mode: c; tab-with=8; sw=4; ts=8; noexpandtab: */
static size_t dlhandle_memsize(const void *ptr)
Definition: handle.c:45
static VALUE rb_dlhandle_close_enabled_p(VALUE self)
Definition: handle.c:230
VALUE sym
Definition: tkutil.c:1298
VP_EXPORT int
Definition: bigdecimal.c:5071
VALUE rb_mDL
Definition: dl.c:13
void rb_bug(const char *fmt,...)
Definition: error.c:295
size_t strlen(const char *)
int open
Definition: dl.h:183
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 RTLD_DEFAULT
Definition: handle.c:281
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
VALUE rb_dlhandle_initialize(int argc, VALUE argv[], VALUE self)
Definition: handle.c:120
#define OBJ_FREEZE(x)
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
#define UNREACHABLE
Definition: ruby.h:40
NIL_P(eventloop_thread)
Definition: tcltklib.c:4067
static const rb_data_type_t dlhandle_data_type
Definition: handle.c:50
#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
VALUE rb_dlhandle_enable_close(VALUE self)
Definition: handle.c:199
VALUE rb_eDLError
Definition: dl.c:14
VALUE rb_dlhandle_to_i(VALUE self)
Definition: handle.c:246
int rb_w32_map_errno(DWORD)
Definition: win32.c:223
flag
Definition: tcltklib.c:2047
#define RTLD_NEXT
Definition: handle.c:278
strcpy(cmd2, cmd)
memset(y->frac+ix+1, 0,(y->Prec-(ix+1))*sizeof(BDIGIT))
BDIGIT m
Definition: bigdecimal.c:5106
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)
static VALUE dlhandle_sym(void *handle, const char *symbol)
Definition: handle.c:300
#define StringValueCStr(v)
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:2204
VALUE rb_dlhandle_s_allocate(VALUE klass)
Definition: handle.c:87
static VALUE VALUE obj
Definition: tcltklib.c:3157
int enable_close
Definition: dl.h:184
#define PTR2NUM(x)
Definition: dl.h:168
void Init_dlhandle(void)
Definition: handle.c:365
#define xmalloc
#define xrealloc
int err
Definition: win32.c:87
VALUE * argv
Definition: tcltklib.c:1970
VALUE rb_yield(VALUE)
Definition: vm_eval.c:933
memcpy(buf+1, str, len)
int errno
#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
VALUE rb_dlhandle_s_sym(VALUE self, VALUE sym)
Definition: handle.c:294
int argc
Definition: tcltklib.c:1969
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
VALUE rb_dlhandle_close(VALUE self)
Definition: handle.c:62
static VALUE predefined_dlhandle(void *handle)
Definition: handle.c:101
VALUE rb_dlhandle_disable_close(VALUE self)
Definition: handle.c:214
VALUE rb_dlhandle_sym(VALUE self, VALUE sym)
Definition: handle.c:265
DATA_PTR(self)
#define TypedData_Make_Struct(klass, type, data_type, sval)
RUBY_EXTERN VALUE rb_cObject
Definition: ripper.y:1426
klass
Definition: tcltklib.c:3503
#define INT2NUM(x)
static void dlhandle_free(void *ptr)
Definition: handle.c:35
#define NUM2INT(x)
unsigned long VALUE
Definition: ripper.y:104
VALUE rb_cDLHandle
Definition: handle.c:8
#define CHECK_DLERROR
void * ptr
Definition: dl.h:182
#define NULL
Definition: _sdbm.c:102
const char * name
Definition: nkf.c:208
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1344
size_t len
Definition: tcltklib.c:3567