Ruby  2.0.0p247(2013-06-27revision41674)
ext/dl/dl.c
Go to the documentation of this file.
00001 /*
00002  * ext/dl/dl.c
00003  *
00004  * doumentation:
00005  * - Vincent Batts (vbatts@hashbangbash.com)
00006  *
00007  */
00008 #include <ruby/ruby.h>
00009 #include <ruby/io.h>
00010 #include <ctype.h>
00011 #include "dl.h"
00012 
00013 VALUE rb_mDL;
00014 VALUE rb_eDLError;
00015 VALUE rb_eDLTypeError;
00016 
00017 ID rbdl_id_cdecl;
00018 ID rbdl_id_stdcall;
00019 
00020 #ifndef DLTYPE_SSIZE_T
00021 # if SIZEOF_SIZE_T == SIZEOF_INT
00022 #   define DLTYPE_SSIZE_T DLTYPE_INT
00023 # elif SIZEOF_SIZE_T == SIZEOF_LONG
00024 #   define DLTYPE_SSIZE_T DLTYPE_LONG
00025 # elif defined HAVE_LONG_LONG && SIZEOF_SIZE_T == SIZEOF_LONG_LONG
00026 #   define DLTYPE_SSIZE_T DLTYPE_LONG_LONG
00027 # endif
00028 #endif
00029 #define DLTYPE_SIZE_T (-1*SIGNEDNESS_OF_SIZE_T*DLTYPE_SSIZE_T)
00030 
00031 #ifndef DLTYPE_PTRDIFF_T
00032 # if SIZEOF_PTRDIFF_T == SIZEOF_INT
00033 #   define DLTYPE_PTRDIFF_T DLTYPE_INT
00034 # elif SIZEOF_PTRDIFF_T == SIZEOF_LONG
00035 #   define DLTYPE_PTRDIFF_T DLTYPE_LONG
00036 # elif defined HAVE_LONG_LONG && SIZEOF_PTRDIFF_T == SIZEOF_LONG_LONG
00037 #   define DLTYPE_PTRDIFF_T DLTYPE_LONG_LONG
00038 # endif
00039 #endif
00040 
00041 #ifndef DLTYPE_INTPTR_T
00042 # if SIZEOF_INTPTR_T == SIZEOF_INT
00043 #   define DLTYPE_INTPTR_T DLTYPE_INT
00044 # elif SIZEOF_INTPTR_T == SIZEOF_LONG
00045 #   define DLTYPE_INTPTR_T DLTYPE_LONG
00046 # elif defined HAVE_LONG_LONG && SIZEOF_INTPTR_T == SIZEOF_LONG_LONG
00047 #   define DLTYPE_INTPTR_T DLTYPE_LONG_LONG
00048 # endif
00049 #endif
00050 #define DLTYPE_UINTPTR_T (-DLTYPE_INTPTR_T)
00051 
00052 /*
00053  * call-seq: DL.dlopen(so_lib)
00054  *
00055  * An interface to the dynamic linking loader
00056  *
00057  * This is a shortcut to DL::Handle.new and takes the same arguments.
00058  *
00059  * Example:
00060  *
00061  *   libc_so = "/lib64/libc.so.6"
00062  *   => "/lib64/libc.so.6"
00063  *
00064  *   libc = DL.dlopen(libc_so)
00065  *   => #<DL::Handle:0x00000000e05b00>
00066  */
00067 VALUE
00068 rb_dl_dlopen(int argc, VALUE argv[], VALUE self)
00069 {
00070     return rb_class_new_instance(argc, argv, rb_cDLHandle);
00071 }
00072 
00073 /*
00074  * call-seq: DL.malloc(size)
00075  *
00076  * Allocate +size+ bytes of memory and return the integer memory address
00077  * for the allocated memory.
00078  */
00079 VALUE
00080 rb_dl_malloc(VALUE self, VALUE size)
00081 {
00082     void *ptr;
00083 
00084     rb_secure(4);
00085     ptr = (void*)ruby_xmalloc(NUM2INT(size));
00086     return PTR2NUM(ptr);
00087 }
00088 
00089 /*
00090  * call-seq: DL.realloc(addr, size)
00091  *
00092  * Change the size of the memory allocated at the memory location +addr+ to
00093  * +size+ bytes.  Returns the memory address of the reallocated memory, which
00094  * may be different than the address passed in.
00095  */
00096 VALUE
00097 rb_dl_realloc(VALUE self, VALUE addr, VALUE size)
00098 {
00099     void *ptr = NUM2PTR(addr);
00100 
00101     rb_secure(4);
00102     ptr = (void*)ruby_xrealloc(ptr, NUM2INT(size));
00103     return PTR2NUM(ptr);
00104 }
00105 
00106 /*
00107  * call-seq: DL.free(addr)
00108  *
00109  * Free the memory at address +addr+
00110  */
00111 VALUE
00112 rb_dl_free(VALUE self, VALUE addr)
00113 {
00114     void *ptr = NUM2PTR(addr);
00115 
00116     rb_secure(4);
00117     ruby_xfree(ptr);
00118     return Qnil;
00119 }
00120 
00121 /*
00122  * call-seq: DL.dlunwrap(addr)
00123  *
00124  * Returns the hexadecimal representation of a memory pointer address +addr+
00125  *
00126  * Example:
00127  *
00128  *   lib = DL.dlopen('/lib64/libc-2.15.so')
00129  *   => #<DL::Handle:0x00000001342460>
00130  *
00131  *   lib['strcpy'].to_s(16)
00132  *   => "7f59de6dd240"
00133  *
00134  *   DL.dlunwrap(DL.dlwrap(lib['strcpy'].to_s(16)))
00135  *   => "7f59de6dd240"
00136  */
00137 VALUE
00138 rb_dl_ptr2value(VALUE self, VALUE addr)
00139 {
00140     rb_secure(4);
00141     return (VALUE)NUM2PTR(addr);
00142 }
00143 
00144 /*
00145  * call-seq: DL.dlwrap(val)
00146  *
00147  * Returns a memory pointer of a function's hexadecimal address location +val+
00148  *
00149  * Example:
00150  *
00151  *   lib = DL.dlopen('/lib64/libc-2.15.so')
00152  *   => #<DL::Handle:0x00000001342460>
00153  *
00154  *   DL.dlwrap(lib['strcpy'].to_s(16))
00155  *   => 25522520
00156  */
00157 VALUE
00158 rb_dl_value2ptr(VALUE self, VALUE val)
00159 {
00160     return PTR2NUM((void*)val);
00161 }
00162 
00163 static void
00164 rb_dl_init_callbacks(VALUE dl)
00165 {
00166     static const char cb[] = "dl/callback.so";
00167 
00168     rb_autoload(dl, rb_intern_const("CdeclCallbackAddrs"), cb);
00169     rb_autoload(dl, rb_intern_const("CdeclCallbackProcs"), cb);
00170 #ifdef FUNC_STDCALL
00171     rb_autoload(dl, rb_intern_const("StdcallCallbackAddrs"), cb);
00172     rb_autoload(dl, rb_intern_const("StdcallCallbackProcs"), cb);
00173 #endif
00174 }
00175 
00176 void
00177 Init_dl(void)
00178 {
00179     void Init_dlhandle(void);
00180     void Init_dlcfunc(void);
00181     void Init_dlptr(void);
00182 
00183     rbdl_id_cdecl = rb_intern_const("cdecl");
00184     rbdl_id_stdcall = rb_intern_const("stdcall");
00185 
00186     /* Document-module: DL
00187      *
00188      * A bridge to the dlopen() or dynamic library linker function.
00189      *
00190      * == Example
00191      *
00192      *   bash $> cat > sum.c <<EOF
00193      *   double sum(double *arry, int len)
00194      *   {
00195      *           double ret = 0;
00196      *           int i;
00197      *           for(i = 0; i < len; i++){
00198      *                   ret = ret + arry[i];
00199      *           }
00200      *           return ret;
00201      *   }
00202      *
00203      *   double split(double num)
00204      *   {
00205      *           double ret = 0;
00206      *           ret = num / 2;
00207      *           return ret;
00208      *   }
00209      *   EOF
00210      *   bash $> gcc -o libsum.so -shared sum.c
00211      *   bash $> cat > sum.rb <<EOF
00212      *   require 'dl'
00213      *   require 'dl/import'
00214      *
00215      *   module LibSum
00216      *           extend DL::Importer
00217      *           dlload './libsum.so'
00218      *           extern 'double sum(double*, int)'
00219      *           extern 'double split(double)'
00220      *   end
00221      *
00222      *   a = [2.0, 3.0, 4.0]
00223      *
00224      *   sum = LibSum.sum(a.pack("d*"), a.count)
00225      *   p LibSum.split(sum)
00226      *   EOF
00227      *   bash $> ruby sum.rb
00228      *   4.5
00229      *
00230      * WIN! :-)
00231      */
00232     rb_mDL = rb_define_module("DL");
00233 
00234     /*
00235      * Document-class: DL::DLError
00236      *
00237      * standard dynamic load exception
00238      */
00239     rb_eDLError = rb_define_class_under(rb_mDL, "DLError", rb_eStandardError);
00240 
00241     /*
00242      * Document-class: DL::DLTypeError
00243      *
00244      * dynamic load incorrect type exception
00245      */
00246     rb_eDLTypeError = rb_define_class_under(rb_mDL, "DLTypeError", rb_eDLError);
00247 
00248     /* Document-const: MAX_CALLBACK
00249      *
00250      * Maximum number of callbacks
00251      */
00252     rb_define_const(rb_mDL, "MAX_CALLBACK", INT2NUM(MAX_CALLBACK));
00253 
00254     /* Document-const: DLSTACK_SIZE
00255      *
00256      * Dynamic linker stack size
00257      */
00258     rb_define_const(rb_mDL, "DLSTACK_SIZE", INT2NUM(DLSTACK_SIZE));
00259 
00260     rb_dl_init_callbacks(rb_mDL);
00261 
00262     /* Document-const: RTLD_GLOBAL
00263      *
00264      * rtld DL::Handle flag.
00265      *
00266      * The symbols defined by this library will be made available for symbol
00267      * resolution of subsequently loaded libraries.
00268      */
00269     rb_define_const(rb_mDL, "RTLD_GLOBAL", INT2NUM(RTLD_GLOBAL));
00270 
00271     /* Document-const: RTLD_LAZY
00272      *
00273      * rtld DL::Handle flag.
00274      *
00275      * Perform lazy binding.  Only resolve symbols as the code that references
00276      * them is executed.  If the  symbol is never referenced, then it is never
00277      * resolved.  (Lazy binding is only performed for function references;
00278      * references to variables are always immediately bound when the library
00279      * is loaded.)
00280      */
00281     rb_define_const(rb_mDL, "RTLD_LAZY",   INT2NUM(RTLD_LAZY));
00282 
00283     /* Document-const: RTLD_NOW
00284      *
00285      * rtld DL::Handle flag.
00286      *
00287      * If this value is specified or the environment variable LD_BIND_NOW is
00288      * set to a nonempty string, all undefined symbols in the library are
00289      * resolved before dlopen() returns.  If this cannot be done an error is
00290      * returned.
00291      */
00292     rb_define_const(rb_mDL, "RTLD_NOW",    INT2NUM(RTLD_NOW));
00293 
00294     /* Document-const: TYPE_VOID
00295      *
00296      * DL::CFunc type - void
00297      */
00298     rb_define_const(rb_mDL, "TYPE_VOID",  INT2NUM(DLTYPE_VOID));
00299 
00300     /* Document-const: TYPE_VOIDP
00301      *
00302      * DL::CFunc type - void*
00303      */
00304     rb_define_const(rb_mDL, "TYPE_VOIDP",  INT2NUM(DLTYPE_VOIDP));
00305 
00306     /* Document-const: TYPE_CHAR
00307      *
00308      * DL::CFunc type - char
00309      */
00310     rb_define_const(rb_mDL, "TYPE_CHAR",  INT2NUM(DLTYPE_CHAR));
00311 
00312     /* Document-const: TYPE_SHORT
00313      *
00314      * DL::CFunc type - short
00315      */
00316     rb_define_const(rb_mDL, "TYPE_SHORT",  INT2NUM(DLTYPE_SHORT));
00317 
00318     /* Document-const: TYPE_INT
00319      *
00320      * DL::CFunc type - int
00321      */
00322     rb_define_const(rb_mDL, "TYPE_INT",  INT2NUM(DLTYPE_INT));
00323 
00324     /* Document-const: TYPE_LONG
00325      *
00326      * DL::CFunc type - long
00327      */
00328     rb_define_const(rb_mDL, "TYPE_LONG",  INT2NUM(DLTYPE_LONG));
00329 
00330 #if HAVE_LONG_LONG
00331     /* Document-const: TYPE_LONG_LONG
00332      *
00333      * DL::CFunc type - long long
00334      */
00335     rb_define_const(rb_mDL, "TYPE_LONG_LONG",  INT2NUM(DLTYPE_LONG_LONG));
00336 #endif
00337 
00338     /* Document-const: TYPE_FLOAT
00339      *
00340      * DL::CFunc type - float
00341      */
00342     rb_define_const(rb_mDL, "TYPE_FLOAT",  INT2NUM(DLTYPE_FLOAT));
00343 
00344     /* Document-const: TYPE_DOUBLE
00345      *
00346      * DL::CFunc type - double
00347      */
00348     rb_define_const(rb_mDL, "TYPE_DOUBLE",  INT2NUM(DLTYPE_DOUBLE));
00349 
00350     /* Document-const: TYPE_SIZE_T
00351      *
00352      * DL::CFunc type - size_t
00353      */
00354     rb_define_const(rb_mDL, "TYPE_SIZE_T",  INT2NUM(DLTYPE_SIZE_T));
00355 
00356     /* Document-const: TYPE_SSIZE_T
00357      *
00358      * DL::CFunc type - ssize_t
00359      */
00360     rb_define_const(rb_mDL, "TYPE_SSIZE_T", INT2NUM(DLTYPE_SSIZE_T));
00361 
00362     /* Document-const: TYPE_PTRDIFF_T
00363      *
00364      * DL::CFunc type - ptrdiff_t
00365      */
00366     rb_define_const(rb_mDL, "TYPE_PTRDIFF_T", INT2NUM(DLTYPE_PTRDIFF_T));
00367 
00368     /* Document-const: TYPE_INTPTR_T
00369      *
00370      * DL::CFunc type - intptr_t
00371      */
00372     rb_define_const(rb_mDL, "TYPE_INTPTR_T", INT2NUM(DLTYPE_INTPTR_T));
00373 
00374     /* Document-const: TYPE_UINTPTR_T
00375      *
00376      * DL::CFunc type - uintptr_t
00377      */
00378     rb_define_const(rb_mDL, "TYPE_UINTPTR_T", INT2NUM(DLTYPE_UINTPTR_T));
00379 
00380     /* Document-const: ALIGN_VOIDP
00381      *
00382      * The alignment size of a void*
00383      */
00384     rb_define_const(rb_mDL, "ALIGN_VOIDP", INT2NUM(ALIGN_VOIDP));
00385 
00386     /* Document-const: ALIGN_CHAR
00387      *
00388      * The alignment size of a char
00389      */
00390     rb_define_const(rb_mDL, "ALIGN_CHAR",  INT2NUM(ALIGN_CHAR));
00391 
00392     /* Document-const: ALIGN_SHORT
00393      *
00394      * The alignment size of a short
00395      */
00396     rb_define_const(rb_mDL, "ALIGN_SHORT", INT2NUM(ALIGN_SHORT));
00397 
00398     /* Document-const: ALIGN_INT
00399      *
00400      * The alignment size of an int
00401      */
00402     rb_define_const(rb_mDL, "ALIGN_INT",   INT2NUM(ALIGN_INT));
00403 
00404     /* Document-const: ALIGN_LONG
00405      *
00406      * The alignment size of a long
00407      */
00408     rb_define_const(rb_mDL, "ALIGN_LONG",  INT2NUM(ALIGN_LONG));
00409 
00410 #if HAVE_LONG_LONG
00411     /* Document-const: ALIGN_LONG_LONG
00412      *
00413      * The alignment size of a long long
00414      */
00415     rb_define_const(rb_mDL, "ALIGN_LONG_LONG",  INT2NUM(ALIGN_LONG_LONG));
00416 #endif
00417 
00418     /* Document-const: ALIGN_FLOAT
00419      *
00420      * The alignment size of a float
00421      */
00422     rb_define_const(rb_mDL, "ALIGN_FLOAT", INT2NUM(ALIGN_FLOAT));
00423 
00424     /* Document-const: ALIGN_DOUBLE
00425      *
00426      * The alignment size of a double
00427      */
00428     rb_define_const(rb_mDL, "ALIGN_DOUBLE",INT2NUM(ALIGN_DOUBLE));
00429 
00430     /* Document-const: ALIGN_SIZE_T
00431      *
00432      * The alignment size of a size_t
00433      */
00434     rb_define_const(rb_mDL, "ALIGN_SIZE_T", INT2NUM(ALIGN_OF(size_t)));
00435 
00436     /* Document-const: ALIGN_SSIZE_T
00437      *
00438      * The alignment size of a ssize_t
00439      */
00440     rb_define_const(rb_mDL, "ALIGN_SSIZE_T", INT2NUM(ALIGN_OF(size_t))); /* same as size_t */
00441 
00442     /* Document-const: ALIGN_PTRDIFF_T
00443      *
00444      * The alignment size of a ptrdiff_t
00445      */
00446     rb_define_const(rb_mDL, "ALIGN_PTRDIFF_T", INT2NUM(ALIGN_OF(ptrdiff_t)));
00447 
00448     /* Document-const: ALIGN_INTPTR_T
00449      *
00450      * The alignment size of a intptr_t
00451      */
00452     rb_define_const(rb_mDL, "ALIGN_INTPTR_T", INT2NUM(ALIGN_OF(intptr_t)));
00453 
00454     /* Document-const: ALIGN_UINTPTR_T
00455      *
00456      * The alignment size of a uintptr_t
00457      */
00458     rb_define_const(rb_mDL, "ALIGN_UINTPTR_T", INT2NUM(ALIGN_OF(uintptr_t)));
00459 
00460     /* Document-const: SIZEOF_VOIDP
00461      *
00462      * size of a void*
00463      */
00464     rb_define_const(rb_mDL, "SIZEOF_VOIDP", INT2NUM(sizeof(void*)));
00465 
00466     /* Document-const: SIZEOF_CHAR
00467      *
00468      * size of a char
00469      */
00470     rb_define_const(rb_mDL, "SIZEOF_CHAR",  INT2NUM(sizeof(char)));
00471 
00472     /* Document-const: SIZEOF_SHORT
00473      *
00474      * size of a short
00475      */
00476     rb_define_const(rb_mDL, "SIZEOF_SHORT", INT2NUM(sizeof(short)));
00477 
00478     /* Document-const: SIZEOF_INT
00479      *
00480      * size of an int
00481      */
00482     rb_define_const(rb_mDL, "SIZEOF_INT",   INT2NUM(sizeof(int)));
00483 
00484     /* Document-const: SIZEOF_LONG
00485      *
00486      * size of a long
00487      */
00488     rb_define_const(rb_mDL, "SIZEOF_LONG",  INT2NUM(sizeof(long)));
00489 
00490 #if HAVE_LONG_LONG
00491     /* Document-const: SIZEOF_LONG_LONG
00492      *
00493      * size of a long long
00494      */
00495     rb_define_const(rb_mDL, "SIZEOF_LONG_LONG",  INT2NUM(sizeof(LONG_LONG)));
00496 #endif
00497 
00498     /* Document-const: SIZEOF_FLOAT
00499      *
00500      * size of a float
00501      */
00502     rb_define_const(rb_mDL, "SIZEOF_FLOAT", INT2NUM(sizeof(float)));
00503 
00504     /* Document-const: SIZEOF_DOUBLE
00505      *
00506      * size of a double
00507      */
00508     rb_define_const(rb_mDL, "SIZEOF_DOUBLE",INT2NUM(sizeof(double)));
00509 
00510     /* Document-const: SIZEOF_SIZE_T
00511      *
00512      * size of a size_t
00513      */
00514     rb_define_const(rb_mDL, "SIZEOF_SIZE_T",  INT2NUM(sizeof(size_t)));
00515 
00516     /* Document-const: SIZEOF_SSIZE_T
00517      *
00518      * size of a ssize_t
00519      */
00520     rb_define_const(rb_mDL, "SIZEOF_SSIZE_T",  INT2NUM(sizeof(size_t))); /* same as size_t */
00521 
00522     /* Document-const: SIZEOF_PTRDIFF_T
00523      *
00524      * size of a ptrdiff_t
00525      */
00526     rb_define_const(rb_mDL, "SIZEOF_PTRDIFF_T",  INT2NUM(sizeof(ptrdiff_t)));
00527 
00528     /* Document-const: SIZEOF_INTPTR_T
00529      *
00530      * size of a intptr_t
00531      */
00532     rb_define_const(rb_mDL, "SIZEOF_INTPTR_T",  INT2NUM(sizeof(intptr_t)));
00533 
00534     /* Document-const: SIZEOF_UINTPTR_T
00535      *
00536      * size of a uintptr_t
00537      */
00538     rb_define_const(rb_mDL, "SIZEOF_UINTPTR_T",  INT2NUM(sizeof(uintptr_t)));
00539 
00540     rb_define_module_function(rb_mDL, "dlwrap", rb_dl_value2ptr, 1);
00541     rb_define_module_function(rb_mDL, "dlunwrap", rb_dl_ptr2value, 1);
00542 
00543     rb_define_module_function(rb_mDL, "dlopen", rb_dl_dlopen, -1);
00544     rb_define_module_function(rb_mDL, "malloc", rb_dl_malloc, 1);
00545     rb_define_module_function(rb_mDL, "realloc", rb_dl_realloc, 2);
00546     rb_define_module_function(rb_mDL, "free", rb_dl_free, 1);
00547 
00548     /* Document-const: RUBY_FREE
00549      *
00550      * Address of the ruby_xfree() function
00551      */
00552     rb_define_const(rb_mDL, "RUBY_FREE", PTR2NUM(ruby_xfree));
00553 
00554     /* Document-const: BUILD_RUBY_PLATFORM
00555      *
00556      * Platform built against (i.e. "x86_64-linux", etc.)
00557      *
00558      * See also RUBY_PLATFORM
00559      */
00560     rb_define_const(rb_mDL, "BUILD_RUBY_PLATFORM", rb_str_new2(RUBY_PLATFORM));
00561 
00562     /* Document-const: BUILD_RUBY_VERSION
00563      *
00564      * Ruby Version built. (i.e. "1.9.3")
00565      *
00566      * See also RUBY_VERSION
00567      */
00568     rb_define_const(rb_mDL, "BUILD_RUBY_VERSION",  rb_str_new2(RUBY_VERSION));
00569 
00570     Init_dlhandle();
00571     Init_dlcfunc();
00572     Init_dlptr();
00573 }
00574