Ruby  2.0.0p648(2015-12-16revision53162)
handle.c
Go to the documentation of this file.
1 /* -*- C -*-
2  * $Id: handle.c 53161 2015-12-16 12:30:28Z usa $
3  */
4 
5 #include <ruby.h>
6 #include "dl.h"
7 
8 #define SafeStringValuePtr(v) (rb_string_value(&v), rb_check_safe_obj(v), RSTRING_PTR(v))
9 
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
37 dlhandle_free(void *ptr)
38 {
39  struct dl_handle *dlhandle = ptr;
40  if( dlhandle->ptr && dlhandle->open && dlhandle->enable_close ){
41  dlclose(dlhandle->ptr);
42  }
43  xfree(ptr);
44 }
45 
46 static size_t
47 dlhandle_memsize(const void *ptr)
48 {
49  return ptr ? sizeof(struct dl_handle) : 0;
50 }
51 
53  "dl/handle",
55 };
56 
57 /*
58  * call-seq: close
59  *
60  * Close this DL::Handle. Calling close more than once will raise a
61  * DL::DLError exception.
62  */
63 VALUE
65 {
66  struct dl_handle *dlhandle;
67 
68  TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
69  if(dlhandle->open) {
70  int ret = dlclose(dlhandle->ptr);
71  dlhandle->open = 0;
72 
73  /* Check dlclose for successful return value */
74  if(ret) {
75 #if defined(HAVE_DLERROR)
76  rb_raise(rb_eDLError, "%s", dlerror());
77 #else
78  rb_raise(rb_eDLError, "could not close handle");
79 #endif
80  }
81  return INT2NUM(ret);
82  }
83  rb_raise(rb_eDLError, "dlclose() called too many times");
84 
86 }
87 
88 VALUE
90 {
91  VALUE obj;
92  struct dl_handle *dlhandle;
93 
95  dlhandle->ptr = 0;
96  dlhandle->open = 0;
97  dlhandle->enable_close = 0;
98 
99  return obj;
100 }
101 
102 static VALUE
103 predefined_dlhandle(void *handle)
104 {
106  struct dl_handle *dlhandle = DATA_PTR(obj);
107 
108  dlhandle->ptr = handle;
109  dlhandle->open = 1;
110  OBJ_FREEZE(obj);
111  return obj;
112 }
113 
114 /*
115  * call-seq:
116  * initialize(lib = nil, flags = DL::RTLD_LAZY | DL::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 VALUE
123 {
124  void *ptr;
125  struct dl_handle *dlhandle;
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 : SafeStringValuePtr(lib);
138  cflag = RTLD_LAZY | RTLD_GLOBAL;
139  break;
140  case 2:
141  clib = NIL_P(lib) ? NULL : SafeStringValuePtr(lib);
142  cflag = NUM2INT(flag);
143  break;
144  default:
145  rb_bug("rb_dlhandle_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_eDLError, "%s", err);
173  }
174 #else
175  if( !ptr ){
176  err = dlerror();
177  rb_raise(rb_eDLError, "%s", err);
178  }
179 #endif
180  TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
181  if( dlhandle->ptr && dlhandle->open && dlhandle->enable_close ){
182  dlclose(dlhandle->ptr);
183  }
184  dlhandle->ptr = ptr;
185  dlhandle->open = 1;
186  dlhandle->enable_close = 0;
187 
188  if( rb_block_given_p() ){
189  rb_ensure(rb_yield, self, rb_dlhandle_close, self);
190  }
191 
192  return Qnil;
193 }
194 
195 /*
196  * call-seq: enable_close
197  *
198  * Enable a call to dlclose() when this DL::Handle is garbage collected.
199  */
200 VALUE
202 {
203  struct dl_handle *dlhandle;
204 
205  TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
206  dlhandle->enable_close = 1;
207  return Qnil;
208 }
209 
210 /*
211  * call-seq: disable_close
212  *
213  * Disable a call to dlclose() when this DL::Handle is garbage collected.
214  */
215 VALUE
217 {
218  struct dl_handle *dlhandle;
219 
220  TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
221  dlhandle->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 DL::Handle is
229  * garbage collected.
230  */
231 static VALUE
233 {
234  struct dl_handle *dlhandle;
235 
236  TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
237 
238  if(dlhandle->enable_close) return Qtrue;
239  return Qfalse;
240 }
241 
242 /*
243  * call-seq: to_i
244  *
245  * Returns the memory address for this handle.
246  */
247 VALUE
249 {
250  struct dl_handle *dlhandle;
251 
252  TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
253  return PTR2NUM(dlhandle);
254 }
255 
256 static VALUE dlhandle_sym(void *handle, const char *symbol);
257 
258 /*
259  * Document-method: sym
260  * Document-method: []
261  *
262  * call-seq: sym(name)
263  *
264  * Get the address as an Integer for the function named +name+.
265  */
266 VALUE
268 {
269  struct dl_handle *dlhandle;
270  const char *name;
271 
272  name = SafeStringValuePtr(sym);
273 
274  TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle);
275  if( ! dlhandle->open ){
276  rb_raise(rb_eDLError, "closed handle");
277  }
278 
279  return dlhandle_sym(dlhandle->ptr, name);
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  * Document-method: []
292  *
293  * call-seq: sym(name)
294  *
295  * Get the address as an Integer for the function named +name+. The function
296  * is searched via dlsym on RTLD_NEXT. See man(3) dlsym() for more info.
297  */
298 VALUE
300 {
301  return dlhandle_sym(RTLD_NEXT, StringValueCStr(sym));
302 }
303 
304 static VALUE
305 dlhandle_sym(void *handle, const char *name)
306 {
307 #if defined(HAVE_DLERROR)
308  const char *err;
309 # define CHECK_DLERROR if( err = dlerror() ){ func = 0; }
310 #else
311 # define CHECK_DLERROR
312 #endif
313  void (*func)();
314 
315  rb_secure(2);
316 #ifdef HAVE_DLERROR
317  dlerror();
318 #endif
319  func = (void (*)())(VALUE)dlsym(handle, name);
321 #if defined(FUNC_STDCALL)
322  if( !func ){
323  int i;
324  int len = (int)strlen(name);
325  char *name_n;
326 #if defined(__CYGWIN__) || defined(_WIN32) || defined(__MINGW32__)
327  {
328  char *name_a = (char*)xmalloc(len+2);
329  strcpy(name_a, name);
330  name_n = name_a;
331  name_a[len] = 'A';
332  name_a[len+1] = '\0';
333  func = dlsym(handle, name_a);
335  if( func ) goto found;
336  name_n = xrealloc(name_a, len+6);
337  }
338 #else
339  name_n = (char*)xmalloc(len+6);
340 #endif
341  memcpy(name_n, name, len);
342  name_n[len++] = '@';
343  for( i = 0; i < 256; i += 4 ){
344  sprintf(name_n + len, "%d", i);
345  func = dlsym(handle, name_n);
347  if( func ) break;
348  }
349  if( func ) goto found;
350  name_n[len-1] = 'A';
351  name_n[len++] = '@';
352  for( i = 0; i < 256; i += 4 ){
353  sprintf(name_n + len, "%d", i);
354  func = dlsym(handle, name_n);
356  if( func ) break;
357  }
358  found:
359  xfree(name_n);
360  }
361 #endif
362  if( !func ){
363  rb_raise(rb_eDLError, "unknown symbol \"%s\"", name);
364  }
365 
366  return PTR2NUM(func);
367 }
368 
369 void
371 {
372  /*
373  * Document-class: DL::Handle
374  *
375  * The DL::Handle is the manner to access the dynamic library
376  *
377  * == Example
378  *
379  * === Setup
380  *
381  * libc_so = "/lib64/libc.so.6"
382  * => "/lib64/libc.so.6"
383  * @handle = DL::Handle.new(libc_so)
384  * => #<DL::Handle:0x00000000d69ef8>
385  *
386  * === Setup, with flags
387  *
388  * libc_so = "/lib64/libc.so.6"
389  * => "/lib64/libc.so.6"
390  * @handle = DL::Handle.new(libc_so, DL::RTLD_LAZY | DL::RTLD_GLOBAL)
391  * => #<DL::Handle:0x00000000d69ef8>
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  */
434 }
435 
436 /* mode: c; tab-with=8; sw=4; ts=8; noexpandtab: */
static size_t dlhandle_memsize(const void *ptr)
Definition: handle.c:47
static VALUE rb_dlhandle_close_enabled_p(VALUE self)
Definition: handle.c:232
VALUE rb_mDL
Definition: dl.c:13
void rb_bug(const char *fmt,...)
Definition: error.c:295
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:286
#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:122
#define UNREACHABLE
Definition: ruby.h:40
static const rb_data_type_t dlhandle_data_type
Definition: handle.c:52
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
VALUE rb_dlhandle_enable_close(VALUE self)
Definition: handle.c:201
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:248
#define DATA_PTR(dta)
Definition: ruby.h:985
int rb_w32_map_errno(DWORD)
Definition: win32.c:223
#define RTLD_NEXT
Definition: handle.c:283
#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:305
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:89
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
#define SafeStringValuePtr(v)
Definition: handle.c:8
void Init_dlhandle(void)
Definition: handle.c:370
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:933
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:108
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:10
VALUE rb_dlhandle_s_sym(VALUE self, VALUE sym)
Definition: handle.c:299
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:64
static VALUE predefined_dlhandle(void *handle)
Definition: handle.c:103
VALUE rb_dlhandle_disable_close(VALUE self)
Definition: handle.c:216
#define xmalloc
Definition: defines.h:64
VALUE rb_dlhandle_sym(VALUE self, VALUE sym)
Definition: handle.c:267
static void dlhandle_free(void *ptr)
Definition: handle.c:37
#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 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:102
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1344
char ** argv
Definition: ruby.c:131