|
Ruby
2.0.0p594(2014-10-27revision48167)
|
00001 /* -*- C -*- 00002 * $Id: handle.c 46508 2014-06-23 07:52:37Z usa $ 00003 */ 00004 00005 #include <ruby.h> 00006 #include "dl.h" 00007 00008 VALUE rb_cDLHandle; 00009 00010 #ifdef _WIN32 00011 # ifndef _WIN32_WCE 00012 static void * 00013 w32_coredll(void) 00014 { 00015 MEMORY_BASIC_INFORMATION m; 00016 memset(&m, 0, sizeof(m)); 00017 if( !VirtualQuery(_errno, &m, sizeof(m)) ) return NULL; 00018 return m.AllocationBase; 00019 } 00020 # endif 00021 00022 static int 00023 w32_dlclose(void *ptr) 00024 { 00025 # ifndef _WIN32_WCE 00026 if( ptr == w32_coredll() ) return 0; 00027 # endif 00028 if( FreeLibrary((HMODULE)ptr) ) return 0; 00029 return errno = rb_w32_map_errno(GetLastError()); 00030 } 00031 #define dlclose(ptr) w32_dlclose(ptr) 00032 #endif 00033 00034 static void 00035 dlhandle_free(void *ptr) 00036 { 00037 struct dl_handle *dlhandle = ptr; 00038 if( dlhandle->ptr && dlhandle->open && dlhandle->enable_close ){ 00039 dlclose(dlhandle->ptr); 00040 } 00041 xfree(ptr); 00042 } 00043 00044 static size_t 00045 dlhandle_memsize(const void *ptr) 00046 { 00047 return ptr ? sizeof(struct dl_handle) : 0; 00048 } 00049 00050 static const rb_data_type_t dlhandle_data_type = { 00051 "dl/handle", 00052 {0, dlhandle_free, dlhandle_memsize,}, 00053 }; 00054 00055 /* 00056 * call-seq: close 00057 * 00058 * Close this DL::Handle. Calling close more than once will raise a 00059 * DL::DLError exception. 00060 */ 00061 VALUE 00062 rb_dlhandle_close(VALUE self) 00063 { 00064 struct dl_handle *dlhandle; 00065 00066 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle); 00067 if(dlhandle->open) { 00068 int ret = dlclose(dlhandle->ptr); 00069 dlhandle->open = 0; 00070 00071 /* Check dlclose for successful return value */ 00072 if(ret) { 00073 #if defined(HAVE_DLERROR) 00074 rb_raise(rb_eDLError, "%s", dlerror()); 00075 #else 00076 rb_raise(rb_eDLError, "could not close handle"); 00077 #endif 00078 } 00079 return INT2NUM(ret); 00080 } 00081 rb_raise(rb_eDLError, "dlclose() called too many times"); 00082 00083 UNREACHABLE; 00084 } 00085 00086 VALUE 00087 rb_dlhandle_s_allocate(VALUE klass) 00088 { 00089 VALUE obj; 00090 struct dl_handle *dlhandle; 00091 00092 obj = TypedData_Make_Struct(rb_cDLHandle, struct dl_handle, &dlhandle_data_type, dlhandle); 00093 dlhandle->ptr = 0; 00094 dlhandle->open = 0; 00095 dlhandle->enable_close = 0; 00096 00097 return obj; 00098 } 00099 00100 static VALUE 00101 predefined_dlhandle(void *handle) 00102 { 00103 VALUE obj = rb_dlhandle_s_allocate(rb_cDLHandle); 00104 struct dl_handle *dlhandle = DATA_PTR(obj); 00105 00106 dlhandle->ptr = handle; 00107 dlhandle->open = 1; 00108 OBJ_FREEZE(obj); 00109 return obj; 00110 } 00111 00112 /* 00113 * call-seq: 00114 * initialize(lib = nil, flags = DL::RTLD_LAZY | DL::RTLD_GLOBAL) 00115 * 00116 * Create a new handler that opens library named +lib+ with +flags+. If no 00117 * library is specified, RTLD_DEFAULT is used. 00118 */ 00119 VALUE 00120 rb_dlhandle_initialize(int argc, VALUE argv[], VALUE self) 00121 { 00122 void *ptr; 00123 struct dl_handle *dlhandle; 00124 VALUE lib, flag; 00125 char *clib; 00126 int cflag; 00127 const char *err; 00128 00129 switch( rb_scan_args(argc, argv, "02", &lib, &flag) ){ 00130 case 0: 00131 clib = NULL; 00132 cflag = RTLD_LAZY | RTLD_GLOBAL; 00133 break; 00134 case 1: 00135 clib = NIL_P(lib) ? NULL : StringValuePtr(lib); 00136 cflag = RTLD_LAZY | RTLD_GLOBAL; 00137 break; 00138 case 2: 00139 clib = NIL_P(lib) ? NULL : StringValuePtr(lib); 00140 cflag = NUM2INT(flag); 00141 break; 00142 default: 00143 rb_bug("rb_dlhandle_new"); 00144 } 00145 00146 rb_secure(2); 00147 00148 #if defined(_WIN32) 00149 if( !clib ){ 00150 HANDLE rb_libruby_handle(void); 00151 ptr = rb_libruby_handle(); 00152 } 00153 else if( STRCASECMP(clib, "libc") == 0 00154 # ifdef RUBY_COREDLL 00155 || STRCASECMP(clib, RUBY_COREDLL) == 0 00156 || STRCASECMP(clib, RUBY_COREDLL".dll") == 0 00157 # endif 00158 ){ 00159 # ifdef _WIN32_WCE 00160 ptr = dlopen("coredll.dll", cflag); 00161 # else 00162 ptr = w32_coredll(); 00163 # endif 00164 } 00165 else 00166 #endif 00167 ptr = dlopen(clib, cflag); 00168 #if defined(HAVE_DLERROR) 00169 if( !ptr && (err = dlerror()) ){ 00170 rb_raise(rb_eDLError, "%s", err); 00171 } 00172 #else 00173 if( !ptr ){ 00174 err = dlerror(); 00175 rb_raise(rb_eDLError, "%s", err); 00176 } 00177 #endif 00178 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle); 00179 if( dlhandle->ptr && dlhandle->open && dlhandle->enable_close ){ 00180 dlclose(dlhandle->ptr); 00181 } 00182 dlhandle->ptr = ptr; 00183 dlhandle->open = 1; 00184 dlhandle->enable_close = 0; 00185 00186 if( rb_block_given_p() ){ 00187 rb_ensure(rb_yield, self, rb_dlhandle_close, self); 00188 } 00189 00190 return Qnil; 00191 } 00192 00193 /* 00194 * call-seq: enable_close 00195 * 00196 * Enable a call to dlclose() when this DL::Handle is garbage collected. 00197 */ 00198 VALUE 00199 rb_dlhandle_enable_close(VALUE self) 00200 { 00201 struct dl_handle *dlhandle; 00202 00203 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle); 00204 dlhandle->enable_close = 1; 00205 return Qnil; 00206 } 00207 00208 /* 00209 * call-seq: disable_close 00210 * 00211 * Disable a call to dlclose() when this DL::Handle is garbage collected. 00212 */ 00213 VALUE 00214 rb_dlhandle_disable_close(VALUE self) 00215 { 00216 struct dl_handle *dlhandle; 00217 00218 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle); 00219 dlhandle->enable_close = 0; 00220 return Qnil; 00221 } 00222 00223 /* 00224 * call-seq: close_enabled? 00225 * 00226 * Returns +true+ if dlclose() will be called when this DL::Handle is 00227 * garbage collected. 00228 */ 00229 static VALUE 00230 rb_dlhandle_close_enabled_p(VALUE self) 00231 { 00232 struct dl_handle *dlhandle; 00233 00234 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle); 00235 00236 if(dlhandle->enable_close) return Qtrue; 00237 return Qfalse; 00238 } 00239 00240 /* 00241 * call-seq: to_i 00242 * 00243 * Returns the memory address for this handle. 00244 */ 00245 VALUE 00246 rb_dlhandle_to_i(VALUE self) 00247 { 00248 struct dl_handle *dlhandle; 00249 00250 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle); 00251 return PTR2NUM(dlhandle); 00252 } 00253 00254 static VALUE dlhandle_sym(void *handle, const char *symbol); 00255 00256 /* 00257 * Document-method: sym 00258 * Document-method: [] 00259 * 00260 * call-seq: sym(name) 00261 * 00262 * Get the address as an Integer for the function named +name+. 00263 */ 00264 VALUE 00265 rb_dlhandle_sym(VALUE self, VALUE sym) 00266 { 00267 struct dl_handle *dlhandle; 00268 00269 TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle); 00270 if( ! dlhandle->open ){ 00271 rb_raise(rb_eDLError, "closed handle"); 00272 } 00273 00274 return dlhandle_sym(dlhandle->ptr, StringValueCStr(sym)); 00275 } 00276 00277 #ifndef RTLD_NEXT 00278 #define RTLD_NEXT NULL 00279 #endif 00280 #ifndef RTLD_DEFAULT 00281 #define RTLD_DEFAULT NULL 00282 #endif 00283 00284 /* 00285 * Document-method: sym 00286 * Document-method: [] 00287 * 00288 * call-seq: sym(name) 00289 * 00290 * Get the address as an Integer for the function named +name+. The function 00291 * is searched via dlsym on RTLD_NEXT. See man(3) dlsym() for more info. 00292 */ 00293 VALUE 00294 rb_dlhandle_s_sym(VALUE self, VALUE sym) 00295 { 00296 return dlhandle_sym(RTLD_NEXT, StringValueCStr(sym)); 00297 } 00298 00299 static VALUE 00300 dlhandle_sym(void *handle, const char *name) 00301 { 00302 #if defined(HAVE_DLERROR) 00303 const char *err; 00304 # define CHECK_DLERROR if( err = dlerror() ){ func = 0; } 00305 #else 00306 # define CHECK_DLERROR 00307 #endif 00308 void (*func)(); 00309 00310 rb_secure(2); 00311 #ifdef HAVE_DLERROR 00312 dlerror(); 00313 #endif 00314 func = (void (*)())(VALUE)dlsym(handle, name); 00315 CHECK_DLERROR; 00316 #if defined(FUNC_STDCALL) 00317 if( !func ){ 00318 int i; 00319 int len = (int)strlen(name); 00320 char *name_n; 00321 #if defined(__CYGWIN__) || defined(_WIN32) || defined(__MINGW32__) 00322 { 00323 char *name_a = (char*)xmalloc(len+2); 00324 strcpy(name_a, name); 00325 name_n = name_a; 00326 name_a[len] = 'A'; 00327 name_a[len+1] = '\0'; 00328 func = dlsym(handle, name_a); 00329 CHECK_DLERROR; 00330 if( func ) goto found; 00331 name_n = xrealloc(name_a, len+6); 00332 } 00333 #else 00334 name_n = (char*)xmalloc(len+6); 00335 #endif 00336 memcpy(name_n, name, len); 00337 name_n[len++] = '@'; 00338 for( i = 0; i < 256; i += 4 ){ 00339 sprintf(name_n + len, "%d", i); 00340 func = dlsym(handle, name_n); 00341 CHECK_DLERROR; 00342 if( func ) break; 00343 } 00344 if( func ) goto found; 00345 name_n[len-1] = 'A'; 00346 name_n[len++] = '@'; 00347 for( i = 0; i < 256; i += 4 ){ 00348 sprintf(name_n + len, "%d", i); 00349 func = dlsym(handle, name_n); 00350 CHECK_DLERROR; 00351 if( func ) break; 00352 } 00353 found: 00354 xfree(name_n); 00355 } 00356 #endif 00357 if( !func ){ 00358 rb_raise(rb_eDLError, "unknown symbol \"%s\"", name); 00359 } 00360 00361 return PTR2NUM(func); 00362 } 00363 00364 void 00365 Init_dlhandle(void) 00366 { 00367 /* 00368 * Document-class: DL::Handle 00369 * 00370 * The DL::Handle is the manner to access the dynamic library 00371 * 00372 * == Example 00373 * 00374 * === Setup 00375 * 00376 * libc_so = "/lib64/libc.so.6" 00377 * => "/lib64/libc.so.6" 00378 * @handle = DL::Handle.new(libc_so) 00379 * => #<DL::Handle:0x00000000d69ef8> 00380 * 00381 * === Setup, with flags 00382 * 00383 * libc_so = "/lib64/libc.so.6" 00384 * => "/lib64/libc.so.6" 00385 * @handle = DL::Handle.new(libc_so, DL::RTLD_LAZY | DL::RTLD_GLOBAL) 00386 * => #<DL::Handle:0x00000000d69ef8> 00387 * 00388 * === Addresses to symbols 00389 * 00390 * strcpy_addr = @handle['strcpy'] 00391 * => 140062278451968 00392 * 00393 * or 00394 * 00395 * strcpy_addr = @handle.sym('strcpy') 00396 * => 140062278451968 00397 * 00398 */ 00399 rb_cDLHandle = rb_define_class_under(rb_mDL, "Handle", rb_cObject); 00400 rb_define_alloc_func(rb_cDLHandle, rb_dlhandle_s_allocate); 00401 rb_define_singleton_method(rb_cDLHandle, "sym", rb_dlhandle_s_sym, 1); 00402 rb_define_singleton_method(rb_cDLHandle, "[]", rb_dlhandle_s_sym, 1); 00403 00404 /* Document-const: NEXT 00405 * 00406 * A predefined pseudo-handle of RTLD_NEXT 00407 * 00408 * Which will find the next occurrence of a function in the search order 00409 * after the current library. 00410 */ 00411 rb_define_const(rb_cDLHandle, "NEXT", predefined_dlhandle(RTLD_NEXT)); 00412 00413 /* Document-const: DEFAULT 00414 * 00415 * A predefined pseudo-handle of RTLD_DEFAULT 00416 * 00417 * Which will find the first occurrence of the desired symbol using the 00418 * default library search order 00419 */ 00420 rb_define_const(rb_cDLHandle, "DEFAULT", predefined_dlhandle(RTLD_DEFAULT)); 00421 rb_define_method(rb_cDLHandle, "initialize", rb_dlhandle_initialize, -1); 00422 rb_define_method(rb_cDLHandle, "to_i", rb_dlhandle_to_i, 0); 00423 rb_define_method(rb_cDLHandle, "close", rb_dlhandle_close, 0); 00424 rb_define_method(rb_cDLHandle, "sym", rb_dlhandle_sym, 1); 00425 rb_define_method(rb_cDLHandle, "[]", rb_dlhandle_sym, 1); 00426 rb_define_method(rb_cDLHandle, "disable_close", rb_dlhandle_disable_close, 0); 00427 rb_define_method(rb_cDLHandle, "enable_close", rb_dlhandle_enable_close, 0); 00428 rb_define_method(rb_cDLHandle, "close_enabled?", rb_dlhandle_close_enabled_p, 0); 00429 } 00430 00431 /* mode: c; tab-with=8; sw=4; ts=8; noexpandtab: */ 00432
1.7.6.1