Ruby  2.1.10p492(2016-04-01revision54464)
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
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(library = nil, flags = Fiddle::RTLD_LAZY | Fiddle::RTLD_GLOBAL)
120  *
121  * Create a new handler that opens +library+ with +flags+.
122  *
123  * If no +library+ is specified or +nil+ is given, DEFAULT is used, which is
124  * the equivalent to RTLD_DEFAULT. See <code>man 3 dlopen</code> for more.
125  *
126  * lib = Fiddle::Handle.new
127  *
128  * The default is dependent on OS, and provide a handle for all libraries
129  * already loaded. For example, in most cases you can use this to access +libc+
130  * functions, or ruby functions like +rb_str_new+.
131  */
132 static VALUE
134 {
135  void *ptr;
136  struct dl_handle *fiddle_handle;
137  VALUE lib, flag;
138  char *clib;
139  int cflag;
140  const char *err;
141 
142  switch( rb_scan_args(argc, argv, "02", &lib, &flag) ){
143  case 0:
144  clib = NULL;
145  cflag = RTLD_LAZY | RTLD_GLOBAL;
146  break;
147  case 1:
148  clib = NIL_P(lib) ? NULL : SafeStringValueCStr(lib);
149  cflag = RTLD_LAZY | RTLD_GLOBAL;
150  break;
151  case 2:
152  clib = NIL_P(lib) ? NULL : SafeStringValueCStr(lib);
153  cflag = NUM2INT(flag);
154  break;
155  default:
156  rb_bug("rb_fiddle_handle_new");
157  }
158 
159  rb_secure(2);
160 
161 #if defined(_WIN32)
162  if( !clib ){
163  HANDLE rb_libruby_handle(void);
164  ptr = rb_libruby_handle();
165  }
166  else if( STRCASECMP(clib, "libc") == 0
167 # ifdef RUBY_COREDLL
168  || STRCASECMP(clib, RUBY_COREDLL) == 0
169  || STRCASECMP(clib, RUBY_COREDLL".dll") == 0
170 # endif
171  ){
172 # ifdef _WIN32_WCE
173  ptr = dlopen("coredll.dll", cflag);
174 # else
175  ptr = w32_coredll();
176 # endif
177  }
178  else
179 #endif
180  ptr = dlopen(clib, cflag);
181 #if defined(HAVE_DLERROR)
182  if( !ptr && (err = dlerror()) ){
183  rb_raise(rb_eFiddleError, "%s", err);
184  }
185 #else
186  if( !ptr ){
187  err = dlerror();
188  rb_raise(rb_eFiddleError, "%s", err);
189  }
190 #endif
191  TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
192  if( fiddle_handle->ptr && fiddle_handle->open && fiddle_handle->enable_close ){
193  dlclose(fiddle_handle->ptr);
194  }
195  fiddle_handle->ptr = ptr;
196  fiddle_handle->open = 1;
197  fiddle_handle->enable_close = 0;
198 
199  if( rb_block_given_p() ){
201  }
202 
203  return Qnil;
204 }
205 
206 /*
207  * call-seq: enable_close
208  *
209  * Enable a call to dlclose() when this handle is garbage collected.
210  */
211 static VALUE
213 {
214  struct dl_handle *fiddle_handle;
215 
216  TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
217  fiddle_handle->enable_close = 1;
218  return Qnil;
219 }
220 
221 /*
222  * call-seq: disable_close
223  *
224  * Disable a call to dlclose() when this handle is garbage collected.
225  */
226 static VALUE
228 {
229  struct dl_handle *fiddle_handle;
230 
231  TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
232  fiddle_handle->enable_close = 0;
233  return Qnil;
234 }
235 
236 /*
237  * call-seq: close_enabled?
238  *
239  * Returns +true+ if dlclose() will be called when this handle is garbage collected.
240  *
241  * See man(3) dlclose() for more info.
242  */
243 static VALUE
245 {
246  struct dl_handle *fiddle_handle;
247 
248  TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
249 
250  if(fiddle_handle->enable_close) return Qtrue;
251  return Qfalse;
252 }
253 
254 /*
255  * call-seq: to_i
256  *
257  * Returns the memory address for this handle.
258  */
259 static VALUE
261 {
262  struct dl_handle *fiddle_handle;
263 
264  TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
265  return PTR2NUM(fiddle_handle);
266 }
267 
268 static VALUE fiddle_handle_sym(void *handle, VALUE symbol);
269 
270 /*
271  * Document-method: sym
272  *
273  * call-seq: sym(name)
274  *
275  * Get the address as an Integer for the function named +name+.
276  */
277 static VALUE
279 {
280  struct dl_handle *fiddle_handle;
281 
282  TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
283  if( ! fiddle_handle->open ){
284  rb_raise(rb_eFiddleError, "closed handle");
285  }
286 
287  return fiddle_handle_sym(fiddle_handle->ptr, sym);
288 }
289 
290 #ifndef RTLD_NEXT
291 #define RTLD_NEXT NULL
292 #endif
293 #ifndef RTLD_DEFAULT
294 #define RTLD_DEFAULT NULL
295 #endif
296 
297 /*
298  * Document-method: sym
299  *
300  * call-seq: sym(name)
301  *
302  * Get the address as an Integer for the function named +name+. The function
303  * is searched via dlsym on RTLD_NEXT.
304  *
305  * See man(3) dlsym() for more info.
306  */
307 static VALUE
309 {
311 }
312 
313 static VALUE
314 fiddle_handle_sym(void *handle, VALUE symbol)
315 {
316 #if defined(HAVE_DLERROR)
317  const char *err;
318 # define CHECK_DLERROR if( err = dlerror() ){ func = 0; }
319 #else
320 # define CHECK_DLERROR
321 #endif
322  void (*func)();
323  const char *name = SafeStringValueCStr(symbol);
324 
325  rb_secure(2);
326 #ifdef HAVE_DLERROR
327  dlerror();
328 #endif
329  func = (void (*)())(VALUE)dlsym(handle, name);
331 #if defined(FUNC_STDCALL)
332  if( !func ){
333  int i;
334  int len = (int)strlen(name);
335  char *name_n;
336 #if defined(__CYGWIN__) || defined(_WIN32) || defined(__MINGW32__)
337  {
338  char *name_a = (char*)xmalloc(len+2);
339  strcpy(name_a, name);
340  name_n = name_a;
341  name_a[len] = 'A';
342  name_a[len+1] = '\0';
343  func = dlsym(handle, name_a);
345  if( func ) goto found;
346  name_n = xrealloc(name_a, len+6);
347  }
348 #else
349  name_n = (char*)xmalloc(len+6);
350 #endif
351  memcpy(name_n, name, len);
352  name_n[len++] = '@';
353  for( i = 0; i < 256; i += 4 ){
354  sprintf(name_n + len, "%d", i);
355  func = dlsym(handle, name_n);
357  if( func ) break;
358  }
359  if( func ) goto found;
360  name_n[len-1] = 'A';
361  name_n[len++] = '@';
362  for( i = 0; i < 256; i += 4 ){
363  sprintf(name_n + len, "%d", i);
364  func = dlsym(handle, name_n);
366  if( func ) break;
367  }
368  found:
369  xfree(name_n);
370  }
371 #endif
372  if( !func ){
373  rb_raise(rb_eFiddleError, "unknown symbol \"%"PRIsVALUE"\"", symbol);
374  }
375 
376  return PTR2NUM(func);
377 }
378 
379 void
381 {
382  /*
383  * Document-class: Fiddle::Handle
384  *
385  * The Fiddle::Handle is the manner to access the dynamic library
386  *
387  * == Example
388  *
389  * === Setup
390  *
391  * libc_so = "/lib64/libc.so.6"
392  * => "/lib64/libc.so.6"
393  * @handle = Fiddle::Handle.new(libc_so)
394  * => #<Fiddle::Handle:0x00000000d69ef8>
395  *
396  * === Setup, with flags
397  *
398  * libc_so = "/lib64/libc.so.6"
399  * => "/lib64/libc.so.6"
400  * @handle = Fiddle::Handle.new(libc_so, Fiddle::RTLD_LAZY | Fiddle::RTLD_GLOBAL)
401  * => #<Fiddle::Handle:0x00000000d69ef8>
402  *
403  * See RTLD_LAZY and RTLD_GLOBAL
404  *
405  * === Addresses to symbols
406  *
407  * strcpy_addr = @handle['strcpy']
408  * => 140062278451968
409  *
410  * or
411  *
412  * strcpy_addr = @handle.sym('strcpy')
413  * => 140062278451968
414  *
415  */
420 
421  /* Document-const: NEXT
422  *
423  * A predefined pseudo-handle of RTLD_NEXT
424  *
425  * Which will find the next occurrence of a function in the search order
426  * after the current library.
427  */
429 
430  /* Document-const: DEFAULT
431  *
432  * A predefined pseudo-handle of RTLD_DEFAULT
433  *
434  * Which will find the first occurrence of the desired symbol using the
435  * default library search order
436  */
438 
439  /* Document-const: RTLD_GLOBAL
440  *
441  * rtld Fiddle::Handle flag.
442  *
443  * The symbols defined by this library will be made available for symbol
444  * resolution of subsequently loaded libraries.
445  */
446  rb_define_const(rb_cHandle, "RTLD_GLOBAL", INT2NUM(RTLD_GLOBAL));
447 
448  /* Document-const: RTLD_LAZY
449  *
450  * rtld Fiddle::Handle flag.
451  *
452  * Perform lazy binding. Only resolve symbols as the code that references
453  * them is executed. If the symbol is never referenced, then it is never
454  * resolved. (Lazy binding is only performed for function references;
455  * references to variables are always immediately bound when the library
456  * is loaded.)
457  */
458  rb_define_const(rb_cHandle, "RTLD_LAZY", INT2NUM(RTLD_LAZY));
459 
460  /* Document-const: RTLD_NOW
461  *
462  * rtld Fiddle::Handle flag.
463  *
464  * If this value is specified or the environment variable LD_BIND_NOW is
465  * set to a nonempty string, all undefined symbols in the library are
466  * resolved before Fiddle.dlopen returns. If this cannot be done an error
467  * is returned.
468  */
469  rb_define_const(rb_cHandle, "RTLD_NOW", INT2NUM(RTLD_NOW));
470 
479 }
480 
481 /* vim: set noet sws=4 sw=4: */
#define RTLD_DEFAULT
Definition: handle.c:294
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:1296
int open
Definition: dl.h:183
#define NUM2INT(x)
Definition: ruby.h:630
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:1646
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:278
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:113
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:657
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
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:92
int rb_w32_map_errno(DWORD)
Definition: win32.c:250
void Init_fiddle_handle(void)
Definition: handle.c:380
#define sym(x)
Definition: date_core.c:3695
static VALUE rb_fiddle_handle_disable_close(VALUE self)
Definition: handle.c:227
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:712
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1561
#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:2228
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:1194
static size_t fiddle_handle_memsize(const void *ptr)
Definition: handle.c:49
VALUE rb_yield(VALUE)
Definition: vm_eval.c:948
int errno
static VALUE rb_fiddle_handle_initialize(int argc, VALUE argv[], VALUE self)
Definition: handle.c:133
static VALUE rb_fiddle_handle_close_enabled_p(VALUE self)
Definition: handle.c:244
#define const
Definition: strftime.c:102
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1719
#define PRIsVALUE
Definition: ruby.h:137
#define Qnil
Definition: ruby.h:427
unsigned long VALUE
Definition: ruby.h:88
#define RTLD_NEXT
Definition: handle.c:291
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:54
static VALUE rb_fiddle_handle_to_i(VALUE self)
Definition: handle.c:260
VALUE rb_cHandle
Definition: handle.c:6
#define SafeStringValueCStr(v)
Definition: handle.c:4
#define xmalloc
Definition: defines.h:108
static VALUE rb_fiddle_handle_enable_close(VALUE self)
Definition: handle.c:212
static VALUE fiddle_handle_sym(void *handle, VALUE symbol)
Definition: handle.c:314
#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:39
#define STRCASECMP(s1, s2)
Definition: ruby.h:1791
#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:102
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1479
static VALUE rb_fiddle_handle_s_sym(VALUE self, VALUE sym)
Definition: handle.c:308
char ** argv
Definition: ruby.c:132