Ruby  1.9.3p429(2013-05-15revision40747)
cfunc.c
Go to the documentation of this file.
1 /* -*- C -*-
2  * $Id: cfunc.c 37007 2012-09-21 10:53:50Z naruse $
3  */
4 
5 #include <ruby.h>
6 #include <errno.h>
7 #include "dl.h"
8 
10 
12 
13 static VALUE
15 {
17 }
18 
19 static VALUE
21 {
23  return Qnil;
24 }
25 
26 #if defined(_WIN32)
27 #include <windows.h>
28 static ID id_win32_last_error;
29 
30 static VALUE
31 rb_dl_get_win32_last_error(VALUE self)
32 {
33  return rb_thread_local_aref(rb_thread_current(), id_win32_last_error);
34 }
35 
36 static VALUE
37 rb_dl_set_win32_last_error(VALUE self, VALUE val)
38 {
39  rb_thread_local_aset(rb_thread_current(), id_win32_last_error, val);
40  return Qnil;
41 }
42 #endif
43 
44 static void
45 dlcfunc_mark(void *ptr)
46 {
47  struct cfunc_data *data = ptr;
48  if (data->wrap) {
49  rb_gc_mark(data->wrap);
50  }
51 }
52 
53 static void
55 {
56  struct cfunc_data *data = ptr;
57  if( data->name ){
58  xfree(data->name);
59  }
60  xfree(data);
61 }
62 
63 static size_t
64 dlcfunc_memsize(const void *ptr)
65 {
66  const struct cfunc_data *data = ptr;
67  size_t size = 0;
68  if( data ){
69  size += sizeof(*data);
70  if( data->name ){
71  size += strlen(data->name) + 1;
72  }
73  }
74  return size;
75 }
76 
78  "dl/cfunc",
80 };
81 
82 VALUE
83 rb_dlcfunc_new(void (*func)(), int type, const char *name, ID calltype)
84 {
85  VALUE val;
86  struct cfunc_data *data;
87 
88  rb_secure(4);
89  if( func ){
90  val = TypedData_Make_Struct(rb_cDLCFunc, struct cfunc_data, &dlcfunc_data_type, data);
91  data->ptr = (void *)(VALUE)func;
92  data->name = name ? strdup(name) : NULL;
93  data->type = type;
94  data->calltype = calltype;
95  }
96  else{
97  val = Qnil;
98  }
99 
100  return val;
101 }
102 
103 void *
105 {
106  struct cfunc_data *data;
107  void * func;
108 
109  if( rb_typeddata_is_kind_of(val, &dlcfunc_data_type) ){
110  data = DATA_PTR(val);
111  func = data->ptr;
112  }
113  else if( val == Qnil ){
114  func = NULL;
115  }
116  else{
117  rb_raise(rb_eTypeError, "DL::CFunc was expected");
118  }
119 
120  return func;
121 }
122 
123 static VALUE
125 {
126  VALUE obj;
127  struct cfunc_data *data;
128 
129  obj = TypedData_Make_Struct(klass, struct cfunc_data, &dlcfunc_data_type, data);
130  data->ptr = 0;
131  data->name = 0;
132  data->type = 0;
133  data->calltype = CFUNC_CDECL;
134 
135  return obj;
136 }
137 
138 int
140 {
141  return rb_typeddata_is_kind_of(func, &dlcfunc_data_type);
142 }
143 
144 /*
145  * call-seq:
146  * DL::CFunc.new(address, type=DL::TYPE_VOID, name=nil, calltype=:cdecl)
147  *
148  * Create a new function that points to +address+ with an optional return type
149  * of +type+, a name of +name+ and a calltype of +calltype+.
150  */
151 static VALUE
153 {
154  VALUE addr, name, type, calltype, addrnum;
155  struct cfunc_data *data;
156  void *saddr;
157  const char *sname;
158 
159  rb_scan_args(argc, argv, "13", &addr, &type, &name, &calltype);
160 
161  addrnum = rb_Integer(addr);
162  saddr = (void*)(NUM2PTR(addrnum));
163  sname = NIL_P(name) ? NULL : StringValuePtr(name);
164 
165  TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, data);
166  if( data->name ) xfree(data->name);
167  data->ptr = saddr;
168  data->name = sname ? strdup(sname) : 0;
169  data->type = NIL_P(type) ? DLTYPE_VOID : NUM2INT(type);
170  data->calltype = NIL_P(calltype) ? CFUNC_CDECL : SYM2ID(calltype);
171  data->wrap = (addrnum == addr) ? 0 : addr;
172 
173  return Qnil;
174 }
175 
176 /*
177  * call-seq:
178  * name => str
179  *
180  * Get the name of this function
181  */
182 static VALUE
184 {
185  struct cfunc_data *cfunc;
186 
187  TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
188  return cfunc->name ? rb_tainted_str_new2(cfunc->name) : Qnil;
189 }
190 
191 /*
192  * call-seq:
193  * cfunc.ctype => num
194  *
195  * Get the C function return value type. See DL for a list of constants
196  * corresponding to this method's return value.
197  */
198 static VALUE
200 {
201  struct cfunc_data *cfunc;
202 
203  TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
204  return INT2NUM(cfunc->type);
205 }
206 
207 /*
208  * call-seq:
209  * cfunc.ctype = type
210  *
211  * Set the C function return value type to +type+.
212  */
213 static VALUE
215 {
216  struct cfunc_data *cfunc;
217 
218  TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
219  cfunc->type = NUM2INT(ctype);
220  return ctype;
221 }
222 
223 /*
224  * call-seq:
225  * cfunc.calltype => symbol
226  *
227  * Get the call type of this function.
228  */
229 static VALUE
231 {
232  struct cfunc_data *cfunc;
233 
234  TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
235  return ID2SYM(cfunc->calltype);
236 }
237 
238 /*
239  * call-seq:
240  * cfunc.calltype = symbol
241  *
242  * Set the call type for this function.
243  */
244 static VALUE
246 {
247  struct cfunc_data *cfunc;
248 
249  TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
250  cfunc->calltype = SYM2ID(sym);
251  return sym;
252 }
253 
254 /*
255  * call-seq:
256  * cfunc.ptr
257  *
258  * Get the underlying function pointer as a DL::CPtr object.
259  */
260 static VALUE
262 {
263  struct cfunc_data *cfunc;
264 
265  TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
266  return PTR2NUM(cfunc->ptr);
267 }
268 
269 /*
270  * call-seq:
271  * cfunc.ptr = pointer
272  *
273  * Set the underlying function pointer to a DL::CPtr named +pointer+.
274  */
275 static VALUE
277 {
278  struct cfunc_data *cfunc;
279 
280  TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
281  cfunc->ptr = NUM2PTR(addr);
282 
283  return Qnil;
284 }
285 
286 /*
287  * call-seq: inspect
288  *
289  * Returns a string formatted with an easily readable representation of the
290  * internal state of the DL::CFunc
291  */
292 static VALUE
294 {
295  VALUE val;
296  struct cfunc_data *cfunc;
297 
298  TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
299 
300  val = rb_sprintf("#<DL::CFunc:%p ptr=%p type=%d name='%s'>",
301  cfunc,
302  cfunc->ptr,
303  cfunc->type,
304  cfunc->name ? cfunc->name : "");
305  OBJ_TAINT(val);
306  return val;
307 }
308 
309 
310 # define DECL_FUNC_CDECL(f,ret,args,val) \
311  ret (FUNC_CDECL(*(f)))(args) = (ret (FUNC_CDECL(*))(args))(VALUE)(val)
312 #ifdef FUNC_STDCALL
313 # define DECL_FUNC_STDCALL(f,ret,args,val) \
314  ret (FUNC_STDCALL(*(f)))(args) = (ret (FUNC_STDCALL(*))(args))(VALUE)(val)
315 #endif
316 
317 #define CALL_CASE switch( RARRAY_LEN(ary) ){ \
318  CASE(0); break; \
319  CASE(1); break; CASE(2); break; CASE(3); break; CASE(4); break; CASE(5); break; \
320  CASE(6); break; CASE(7); break; CASE(8); break; CASE(9); break; CASE(10);break; \
321  CASE(11);break; CASE(12);break; CASE(13);break; CASE(14);break; CASE(15);break; \
322  CASE(16);break; CASE(17);break; CASE(18);break; CASE(19);break; CASE(20);break; \
323  default: rb_raise(rb_eArgError, "too many arguments"); \
324 }
325 
326 
327 #if defined(_MSC_VER) && defined(_M_AMD64) && _MSC_VER >= 1400 && _MSC_VER < 1600
328 # pragma optimize("", off)
329 #endif
330 /*
331  * call-seq:
332  * dlcfunc.call(ary) => some_value
333  * dlcfunc[ary] => some_value
334  *
335  * Calls the function pointer passing in +ary+ as values to the underlying
336  * C function. The return value depends on the ctype.
337  */
338 static VALUE
340 {
341  struct cfunc_data *cfunc;
342  int i;
343  DLSTACK_TYPE stack[DLSTACK_SIZE];
344  VALUE result = Qnil;
345 
346  rb_secure_update(self);
347 
348  memset(stack, 0, sizeof(DLSTACK_TYPE) * DLSTACK_SIZE);
349  Check_Type(ary, T_ARRAY);
350 
351  TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
352 
353  if( cfunc->ptr == 0 ){
354  rb_raise(rb_eDLError, "can't call null-function");
355  return Qnil;
356  }
357 
358  for( i = 0; i < RARRAY_LEN(ary); i++ ){
359  VALUE arg;
360  if( i >= DLSTACK_SIZE ){
361  rb_raise(rb_eDLError, "too many arguments (stack overflow)");
362  }
363  arg = rb_to_int(RARRAY_PTR(ary)[i]);
364  rb_check_safe_obj(arg);
365  if (FIXNUM_P(arg)) {
366  stack[i] = (DLSTACK_TYPE)FIX2LONG(arg);
367  }
368  else if (RB_TYPE_P(arg, T_BIGNUM)) {
369 #if SIZEOF_VOIDP == SIZEOF_LONG
370  stack[i] = (DLSTACK_TYPE)rb_big2ulong_pack(arg);
371 #else
372  stack[i] = (DLSTACK_TYPE)rb_big2ull(arg);
373 #endif
374  }
375  else {
376  Check_Type(arg, T_FIXNUM);
377  }
378  }
379 
380  /* calltype == CFUNC_CDECL */
381  if( cfunc->calltype == CFUNC_CDECL
382 #ifndef FUNC_STDCALL
383  || cfunc->calltype == CFUNC_STDCALL
384 #endif
385  ){
386  switch( cfunc->type ){
387  case DLTYPE_VOID:
388 #define CASE(n) case n: { \
389  DECL_FUNC_CDECL(f,void,DLSTACK_PROTO##n,cfunc->ptr); \
390  f(DLSTACK_ARGS##n(stack)); \
391  result = Qnil; \
392 }
393  CALL_CASE;
394 #undef CASE
395  break;
396  case DLTYPE_VOIDP:
397 #define CASE(n) case n: { \
398  DECL_FUNC_CDECL(f,void*,DLSTACK_PROTO##n,cfunc->ptr); \
399  void * ret; \
400  ret = f(DLSTACK_ARGS##n(stack)); \
401  result = PTR2NUM(ret); \
402 }
403  CALL_CASE;
404 #undef CASE
405  break;
406  case DLTYPE_CHAR:
407 #define CASE(n) case n: { \
408  DECL_FUNC_CDECL(f,char,DLSTACK_PROTO##n,cfunc->ptr); \
409  char ret; \
410  ret = f(DLSTACK_ARGS##n(stack)); \
411  result = CHR2FIX(ret); \
412 }
413  CALL_CASE;
414 #undef CASE
415  break;
416  case DLTYPE_SHORT:
417 #define CASE(n) case n: { \
418  DECL_FUNC_CDECL(f,short,DLSTACK_PROTO##n,cfunc->ptr); \
419  short ret; \
420  ret = f(DLSTACK_ARGS##n(stack)); \
421  result = INT2NUM((int)ret); \
422 }
423  CALL_CASE;
424 #undef CASE
425  break;
426  case DLTYPE_INT:
427 #define CASE(n) case n: { \
428  DECL_FUNC_CDECL(f,int,DLSTACK_PROTO##n,cfunc->ptr); \
429  int ret; \
430  ret = f(DLSTACK_ARGS##n(stack)); \
431  result = INT2NUM(ret); \
432 }
433  CALL_CASE;
434 #undef CASE
435  break;
436  case DLTYPE_LONG:
437 #define CASE(n) case n: { \
438  DECL_FUNC_CDECL(f,long,DLSTACK_PROTO##n,cfunc->ptr); \
439  long ret; \
440  ret = f(DLSTACK_ARGS##n(stack)); \
441  result = LONG2NUM(ret); \
442 }
443  CALL_CASE;
444 #undef CASE
445  break;
446 #if HAVE_LONG_LONG /* used in ruby.h */
447  case DLTYPE_LONG_LONG:
448 #define CASE(n) case n: { \
449  DECL_FUNC_CDECL(f,LONG_LONG,DLSTACK_PROTO##n,cfunc->ptr); \
450  LONG_LONG ret; \
451  ret = f(DLSTACK_ARGS##n(stack)); \
452  result = LL2NUM(ret); \
453 }
454  CALL_CASE;
455 #undef CASE
456  break;
457 #endif
458  case DLTYPE_FLOAT:
459 #define CASE(n) case n: { \
460  DECL_FUNC_CDECL(f,float,DLSTACK_PROTO##n,cfunc->ptr); \
461  float ret; \
462  ret = f(DLSTACK_ARGS##n(stack)); \
463  result = rb_float_new(ret); \
464 }
465  CALL_CASE;
466 #undef CASE
467  break;
468  case DLTYPE_DOUBLE:
469 #define CASE(n) case n: { \
470  DECL_FUNC_CDECL(f,double,DLSTACK_PROTO##n,cfunc->ptr); \
471  double ret; \
472  ret = f(DLSTACK_ARGS##n(stack)); \
473  result = rb_float_new(ret); \
474 }
475  CALL_CASE;
476 #undef CASE
477  break;
478  default:
479  rb_raise(rb_eDLTypeError, "unknown type %d", cfunc->type);
480  }
481  }
482 #ifdef FUNC_STDCALL
483  else if( cfunc->calltype == CFUNC_STDCALL ){
484  /* calltype == CFUNC_STDCALL */
485  switch( cfunc->type ){
486  case DLTYPE_VOID:
487 #define CASE(n) case n: { \
488  DECL_FUNC_STDCALL(f,void,DLSTACK_PROTO##n##_,cfunc->ptr); \
489  f(DLSTACK_ARGS##n(stack)); \
490  result = Qnil; \
491 }
492  CALL_CASE;
493 #undef CASE
494  break;
495  case DLTYPE_VOIDP:
496 #define CASE(n) case n: { \
497  DECL_FUNC_STDCALL(f,void*,DLSTACK_PROTO##n##_,cfunc->ptr); \
498  void * ret; \
499  ret = f(DLSTACK_ARGS##n(stack)); \
500  result = PTR2NUM(ret); \
501 }
502  CALL_CASE;
503 #undef CASE
504  break;
505  case DLTYPE_CHAR:
506 #define CASE(n) case n: { \
507  DECL_FUNC_STDCALL(f,char,DLSTACK_PROTO##n##_,cfunc->ptr); \
508  char ret; \
509  ret = f(DLSTACK_ARGS##n(stack)); \
510  result = CHR2FIX(ret); \
511 }
512  CALL_CASE;
513 #undef CASE
514  break;
515  case DLTYPE_SHORT:
516 #define CASE(n) case n: { \
517  DECL_FUNC_STDCALL(f,short,DLSTACK_PROTO##n##_,cfunc->ptr); \
518  short ret; \
519  ret = f(DLSTACK_ARGS##n(stack)); \
520  result = INT2NUM((int)ret); \
521 }
522  CALL_CASE;
523 #undef CASE
524  break;
525  case DLTYPE_INT:
526 #define CASE(n) case n: { \
527  DECL_FUNC_STDCALL(f,int,DLSTACK_PROTO##n##_,cfunc->ptr); \
528  int ret; \
529  ret = f(DLSTACK_ARGS##n(stack)); \
530  result = INT2NUM(ret); \
531 }
532  CALL_CASE;
533 #undef CASE
534  break;
535  case DLTYPE_LONG:
536 #define CASE(n) case n: { \
537  DECL_FUNC_STDCALL(f,long,DLSTACK_PROTO##n##_,cfunc->ptr); \
538  long ret; \
539  ret = f(DLSTACK_ARGS##n(stack)); \
540  result = LONG2NUM(ret); \
541 }
542  CALL_CASE;
543 #undef CASE
544  break;
545 #if HAVE_LONG_LONG /* used in ruby.h */
546  case DLTYPE_LONG_LONG:
547 #define CASE(n) case n: { \
548  DECL_FUNC_STDCALL(f,LONG_LONG,DLSTACK_PROTO##n##_,cfunc->ptr); \
549  LONG_LONG ret; \
550  ret = f(DLSTACK_ARGS##n(stack)); \
551  result = LL2NUM(ret); \
552 }
553  CALL_CASE;
554 #undef CASE
555  break;
556 #endif
557  case DLTYPE_FLOAT:
558 #define CASE(n) case n: { \
559  DECL_FUNC_STDCALL(f,float,DLSTACK_PROTO##n##_,cfunc->ptr); \
560  float ret; \
561  ret = f(DLSTACK_ARGS##n(stack)); \
562  result = rb_float_new(ret); \
563 }
564  CALL_CASE;
565 #undef CASE
566  break;
567  case DLTYPE_DOUBLE:
568 #define CASE(n) case n: { \
569  DECL_FUNC_STDCALL(f,double,DLSTACK_PROTO##n##_,cfunc->ptr); \
570  double ret; \
571  ret = f(DLSTACK_ARGS##n(stack)); \
572  result = rb_float_new(ret); \
573 }
574  CALL_CASE;
575 #undef CASE
576  break;
577  default:
578  rb_raise(rb_eDLTypeError, "unknown type %d", cfunc->type);
579  }
580  }
581 #endif
582  else{
583  const char *name = rb_id2name(cfunc->calltype);
584  if( name ){
585  rb_raise(rb_eDLError, "unsupported call type: %s",
586  name);
587  }
588  else{
589  rb_raise(rb_eDLError, "unsupported call type: %"PRIxVALUE,
590  cfunc->calltype);
591  }
592  }
593 
595 #if defined(_WIN32)
596  rb_dl_set_win32_last_error(self, INT2NUM(GetLastError()));
597 #endif
598 
599  return result;
600 }
601 #if defined(_MSC_VER) && defined(_M_AMD64) && _MSC_VER >= 1400 && _MSC_VER < 1600
602 # pragma optimize("", on)
603 #endif
604 
605 /*
606  * call-seq:
607  * dlfunc.to_i => integer
608  *
609  * Returns the memory location of this function pointer as an integer.
610  */
611 static VALUE
613 {
614  struct cfunc_data *cfunc;
615 
616  TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
617  return PTR2NUM(cfunc->ptr);
618 }
619 
620 void
622 {
623  id_last_error = rb_intern("__DL2_LAST_ERROR__");
624 #if defined(_WIN32)
625  id_win32_last_error = rb_intern("__DL2_WIN32_LAST_ERROR__");
626 #endif
627 
628  /*
629  * Document-class: DL::CFunc
630  *
631  * A direct accessor to a function in a C library
632  *
633  * == Example
634  *
635  * libc_so = "/lib64/libc.so.6"
636  * => "/lib64/libc.so.6"
637  * libc = DL::dlopen(libc_so)
638  * => #<DL::Handle:0x00000000e05b00>
639  * @cfunc = DL::CFunc.new(libc,['strcpy'], DL::TYPE_VOIDP, 'strcpy')
640  * => #<DL::CFunc:0x000000012daec0 ptr=0x007f62ca5a8300 type=1 name='strcpy'>
641  *
642  */
645 
646  /*
647  * Document-method: last_error
648  *
649  * Returns the last error for the current executing thread
650  */
652 #if defined(_WIN32)
653 
654  /*
655  * Document-method: win32_last_error
656  *
657  * Returns the last win32 error for the current executing thread
658  */
659  rb_define_module_function(rb_cDLCFunc, "win32_last_error", rb_dl_get_win32_last_error, 0);
660 #endif
674 }
675