Ruby  2.0.0p353(2013-11-22revision43784)
handle.c
Go to the documentation of this file.
1 /* -*- C -*-
2  * $Id: handle.c 35321 2012-04-13 23:45:37Z drbrain $
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 }
42 
43 static size_t
44 dlhandle_memsize(const void *ptr)
45 {
46  return ptr ? sizeof(struct dl_handle) : 0;
47 }
48 
50  "dl/handle",
52 };
53 
54 /*
55  * call-seq: close
56  *
57  * Close this DL::Handle. Calling close more than once will raise a
58  * DL::DLError exception.
59  */
60 VALUE
62 {
63  struct dl_handle *dlhandle;
64 
65  TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
66  if(dlhandle->open) {
67  int ret = dlclose(dlhandle->ptr);
68  dlhandle->open = 0;
69 
70  /* Check dlclose for successful return value */
71  if(ret) {
72 #if defined(HAVE_DLERROR)
73  rb_raise(rb_eDLError, "%s", dlerror());
74 #else
75  rb_raise(rb_eDLError, "could not close handle");
76 #endif
77  }
78  return INT2NUM(ret);
79  }
80  rb_raise(rb_eDLError, "dlclose() called too many times");
81 
83 }
84 
85 VALUE
87 {
88  VALUE obj;
89  struct dl_handle *dlhandle;
90 
92  dlhandle->ptr = 0;
93  dlhandle->open = 0;
94  dlhandle->enable_close = 0;
95 
96  return obj;
97 }
98 
99 static VALUE
100 predefined_dlhandle(void *handle)
101 {
103  struct dl_handle *dlhandle = DATA_PTR(obj);
104 
105  dlhandle->ptr = handle;
106  dlhandle->open = 1;
107  OBJ_FREEZE(obj);
108  return obj;
109 }
110 
111 /*
112  * call-seq:
113  * initialize(lib = nil, flags = DL::RTLD_LAZY | DL::RTLD_GLOBAL)
114  *
115  * Create a new handler that opens library named +lib+ with +flags+. If no
116  * library is specified, RTLD_DEFAULT is used.
117  */
118 VALUE
120 {
121  void *ptr;
122  struct dl_handle *dlhandle;
123  VALUE lib, flag;
124  char *clib;
125  int cflag;
126  const char *err;
127 
128  switch( rb_scan_args(argc, argv, "02", &lib, &flag) ){
129  case 0:
130  clib = NULL;
131  cflag = RTLD_LAZY | RTLD_GLOBAL;
132  break;
133  case 1:
134  clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
135  cflag = RTLD_LAZY | RTLD_GLOBAL;
136  break;
137  case 2:
138  clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
139  cflag = NUM2INT(flag);
140  break;
141  default:
142  rb_bug("rb_dlhandle_new");
143  }
144 
145  rb_secure(2);
146 
147 #if defined(_WIN32)
148  if( !clib ){
149  HANDLE rb_libruby_handle(void);
150  ptr = rb_libruby_handle();
151  }
152  else if( STRCASECMP(clib, "libc") == 0
153 # ifdef RUBY_COREDLL
154  || STRCASECMP(clib, RUBY_COREDLL) == 0
155  || STRCASECMP(clib, RUBY_COREDLL".dll") == 0
156 # endif
157  ){
158 # ifdef _WIN32_WCE
159  ptr = dlopen("coredll.dll", cflag);
160 # else
161  ptr = w32_coredll();
162 # endif
163  }
164  else
165 #endif
166  ptr = dlopen(clib, cflag);
167 #if defined(HAVE_DLERROR)
168  if( !ptr && (err = dlerror()) ){
169  rb_raise(rb_eDLError, "%s", err);
170  }
171 #else
172  if( !ptr ){
173  err = dlerror();
174  rb_raise(rb_eDLError, "%s", err);
175  }
176 #endif
177  TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
178  if( dlhandle->ptr && dlhandle->open && dlhandle->enable_close ){
179  dlclose(dlhandle->ptr);
180  }
181  dlhandle->ptr = ptr;
182  dlhandle->open = 1;
183  dlhandle->enable_close = 0;
184 
185  if( rb_block_given_p() ){
186  rb_ensure(rb_yield, self, rb_dlhandle_close, self);
187  }
188 
189  return Qnil;
190 }
191 
192 /*
193  * call-seq: enable_close
194  *
195  * Enable a call to dlclose() when this DL::Handle is garbage collected.
196  */
197 VALUE
199 {
200  struct dl_handle *dlhandle;
201 
202  TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
203  dlhandle->enable_close = 1;
204  return Qnil;
205 }
206 
207 /*
208  * call-seq: disable_close
209  *
210  * Disable a call to dlclose() when this DL::Handle is garbage collected.
211  */
212 VALUE
214 {
215  struct dl_handle *dlhandle;
216 
217  TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
218  dlhandle->enable_close = 0;
219  return Qnil;
220 }
221 
222 /*
223  * call-seq: close_enabled?
224  *
225  * Returns +true+ if dlclose() will be called when this DL::Handle is
226  * garbage collected.
227  */
228 static VALUE
230 {
231  struct dl_handle *dlhandle;
232 
233  TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
234 
235  if(dlhandle->enable_close) return Qtrue;
236  return Qfalse;
237 }
238 
239 /*
240  * call-seq: to_i
241  *
242  * Returns the memory address for this handle.
243  */
244 VALUE
246 {
247  struct dl_handle *dlhandle;
248 
249  TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
250  return PTR2NUM(dlhandle);
251 }
252 
253 static VALUE dlhandle_sym(void *handle, const char *symbol);
254 
255 /*
256  * Document-method: sym
257  * Document-method: []
258  *
259  * call-seq: sym(name)
260  *
261  * Get the address as an Integer for the function named +name+.
262  */
263 VALUE
265 {
266  struct dl_handle *dlhandle;
267 
268  TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
269  if( ! dlhandle->open ){
270  rb_raise(rb_eDLError, "closed handle");
271  }
272 
273  return dlhandle_sym(dlhandle->ptr, StringValueCStr(sym));
274 }
275 
276 #ifndef RTLD_NEXT
277 #define RTLD_NEXT NULL
278 #endif
279 #ifndef RTLD_DEFAULT
280 #define RTLD_DEFAULT NULL
281 #endif
282 
283 /*
284  * Document-method: sym
285  * Document-method: []
286  *
287  * call-seq: sym(name)
288  *
289  * Get the address as an Integer for the function named +name+. The function
290  * is searched via dlsym on RTLD_NEXT. See man(3) dlsym() for more info.
291  */
292 VALUE
294 {
295  return dlhandle_sym(RTLD_NEXT, StringValueCStr(sym));
296 }
297 
298 static VALUE
299 dlhandle_sym(void *handle, const char *name)
300 {
301 #if defined(HAVE_DLERROR)
302  const char *err;
303 # define CHECK_DLERROR if( err = dlerror() ){ func = 0; }
304 #else
305 # define CHECK_DLERROR
306 #endif
307  void (*func)();
308 
309  rb_secure(2);
310 #ifdef HAVE_DLERROR
311  dlerror();
312 #endif
313  func = (void (*)())(VALUE)dlsym(handle, name);
315 #if defined(FUNC_STDCALL)
316  if( !func ){
317  int i;
318  int len = (int)strlen(name);
319  char *name_n;
320 #if defined(__CYGWIN__) || defined(_WIN32) || defined(__MINGW32__)
321  {
322  char *name_a = (char*)xmalloc(len+2);
323  strcpy(name_a, name);
324  name_n = name_a;
325  name_a[len] = 'A';
326  name_a[len+1] = '\0';
327  func = dlsym(handle, name_a);
329  if( func ) goto found;
330  name_n = xrealloc(name_a, len+6);
331  }
332 #else
333  name_n = (char*)xmalloc(len+6);
334 #endif
335  memcpy(name_n, name, len);
336  name_n[len++] = '@';
337  for( i = 0; i < 256; i += 4 ){
338  sprintf(name_n + len, "%d", i);
339  func = dlsym(handle, name_n);
341  if( func ) break;
342  }
343  if( func ) goto found;
344  name_n[len-1] = 'A';
345  name_n[len++] = '@';
346  for( i = 0; i < 256; i += 4 ){
347  sprintf(name_n + len, "%d", i);
348  func = dlsym(handle, name_n);
350  if( func ) break;
351  }
352  found:
353  xfree(name_n);
354  }
355 #endif
356  if( !func ){
357  rb_raise(rb_eDLError, "unknown symbol \"%s\"", name);
358  }
359 
360  return PTR2NUM(func);
361 }
362 
363 void
365 {
366  /*
367  * Document-class: DL::Handle
368  *
369  * The DL::Handle is the manner to access the dynamic library
370  *
371  * == Example
372  *
373  * === Setup
374  *
375  * libc_so = "/lib64/libc.so.6"
376  * => "/lib64/libc.so.6"
377  * @handle = DL::Handle.new(libc_so)
378  * => #<DL::Handle:0x00000000d69ef8>
379  *
380  * === Setup, with flags
381  *
382  * libc_so = "/lib64/libc.so.6"
383  * => "/lib64/libc.so.6"
384  * @handle = DL::Handle.new(libc_so, DL::RTLD_LAZY | DL::RTLD_GLOBAL)
385  * => #<DL::Handle:0x00000000d69ef8>
386  *
387  * === Addresses to symbols
388  *
389  * strcpy_addr = @handle['strcpy']
390  * => 140062278451968
391  *
392  * or
393  *
394  * strcpy_addr = @handle.sym('strcpy')
395  * => 140062278451968
396  *
397  */
402 
403  /* Document-const: NEXT
404  *
405  * A predefined pseudo-handle of RTLD_NEXT
406  *
407  * Which will find the next occurrence of a function in the search order
408  * after the current library.
409  */
411 
412  /* Document-const: DEFAULT
413  *
414  * A predefined pseudo-handle of RTLD_DEFAULT
415  *
416  * Which will find the first occurrence of the desired symbol using the
417  * default library search order
418  */
428 }
429 
430 /* mode: c; tab-with=8; sw=4; ts=8; noexpandtab: */
static size_t dlhandle_memsize(const void *ptr)
Definition: handle.c:44
static VALUE rb_dlhandle_close_enabled_p(VALUE self)
Definition: handle.c:229
VALUE rb_mDL
Definition: dl.c:13
void rb_bug(const char *fmt,...)
Definition: error.c:290
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
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:280
#define Qtrue
Definition: ruby.h:434
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: ruby.h:1030
VALUE rb_dlhandle_initialize(int argc, VALUE argv[], VALUE self)
Definition: handle.c:119
#define UNREACHABLE
Definition: ruby.h:40
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:108
static const rb_data_type_t dlhandle_data_type
Definition: handle.c:49
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
VALUE rb_dlhandle_enable_close(VALUE self)
Definition: handle.c:198
VALUE rb_eDLError
Definition: dl.c:14
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
VALUE rb_dlhandle_to_i(VALUE self)
Definition: handle.c:245
#define DATA_PTR(dta)
Definition: ruby.h:985
int rb_w32_map_errno(DWORD)
Definition: win32.c:223
#define RTLD_NEXT
Definition: handle.c:277
#define sym(x)
Definition: date_core.c:3715
int rb_block_given_p(void)
Definition: eval.c:672
static VALUE dlhandle_sym(void *handle, const char *symbol)
Definition: handle.c:299
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1426
#define NIL_P(v)
Definition: ruby.h:446
VALUE rb_dlhandle_s_allocate(VALUE klass)
Definition: handle.c:86
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:2202
void Init_dlhandle(void)
Definition: handle.c:364
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
VALUE rb_yield(VALUE)
Definition: vm_eval.c:934
int errno
#define const
Definition: strftime.c:102
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1570
#define Qnil
Definition: ruby.h:435
VALUE rb_cDLHandle
Definition: handle.c:8
VALUE rb_dlhandle_s_sym(VALUE self, VALUE sym)
Definition: handle.c:293
unsigned long VALUE
Definition: ruby.h:104
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:804
void xfree(void *)
#define StringValueCStr(v)
Definition: ruby.h:548
VALUE rb_dlhandle_close(VALUE self)
Definition: handle.c:61
static VALUE predefined_dlhandle(void *handle)
Definition: handle.c:100
VALUE rb_dlhandle_disable_close(VALUE self)
Definition: handle.c:213
#define xmalloc
Definition: defines.h:64
VALUE rb_dlhandle_sym(VALUE self, VALUE sym)
Definition: handle.c:264
static void dlhandle_free(void *ptr)
Definition: handle.c:35
#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
#define StringValuePtr(v)
Definition: ruby.h:547
#define STRCASECMP(s1, s2)
Definition: ruby.h:1645
void rb_secure(int)
Definition: safe.c:79
#define CHECK_DLERROR
void * ptr
Definition: dl.h:182
#define NULL
Definition: _sdbm.c:103
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1344
char ** argv
Definition: ruby.c:131