ext/dl/dl.c

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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7