類別 Fiddle::Handle

Fiddle::Handle 是存取動態函式庫的方式

範例

設定

libc_so = "/lib64/libc.so.6"
=> "/lib64/libc.so.6"
@handle = Fiddle::Handle.new(libc_so)
=> #<Fiddle::Handle:0x00000000d69ef8>

設定,含旗標

libc_so = "/lib64/libc.so.6"
=> "/lib64/libc.so.6"
@handle = Fiddle::Handle.new(libc_so, Fiddle::RTLD_LAZY | Fiddle::RTLD_GLOBAL)
=> #<Fiddle::Handle:0x00000000d69ef8>

請參閱 RTLD_LAZYRTLD_GLOBAL

位址對應符號

strcpy_addr = @handle['strcpy']
=> 140062278451968

strcpy_addr = @handle.sym('strcpy')
=> 140062278451968

常數

DEFAULT

DEFAULT

RTLD_DEFAULT 的預定義偽處理

將使用預設函式庫搜尋順序,找出所需符號的第一個出現位置

NEXT

NEXT

RTLD_NEXT 的預定義偽處理

將在目前函式庫後的搜尋順序中,找出函式的下一個出現位置。

RTLD_GLOBAL

RTLD_GLOBAL

rtld Fiddle::Handle 旗標。

此函式庫定義的符號,將提供給後續載入函式庫的符號解析。

RTLD_LAZY

RTLD_LAZY

rtld Fiddle::Handle 旗標。

執行延遲繫結。僅在執行參考它們的程式碼時,才解析符號。如果從未參考符號,則永遠不會解析它。(延遲繫結僅對函式參考執行;在載入函式庫時,對變數的參考總是立即繫結。)

RTLD_NOW

RTLD_NOW

rtld Fiddle::Handle 旗標。

如果指定此值或將環境變數 LD_BIND_NOW 設為非空字串,則在 Fiddle.dlopen 傳回之前,將解析函式庫中的所有未定義符號。如果無法執行此動作,則會傳回錯誤。

公開類別方法

sym(name) 按一下以切換來源

取得名為 name 的函數的地址,作為 Integer。函數會透過 RTLD_NEXT 上的 dlsym 搜尋。

有關更多資訊,請參閱 man(3) dlsym()。

static VALUE
rb_fiddle_handle_s_sym(VALUE self, VALUE sym)
{
    return fiddle_handle_sym(RTLD_NEXT, sym);
}
new(library = nil, flags = Fiddle::RTLD_LAZY | Fiddle::RTLD_GLOBAL) 按一下以切換來源

建立一個新的處理常式,它會以 flags 開啟 library

如果未指定 library 或給定 nil,則會使用 DEFAULT,它等同於 RTLD_DEFAULT。有關更多資訊,請參閱 man 3 dlopen

lib = Fiddle::Handle.new

預設值會依作業系統而定,並提供一個已載入所有函式庫的處理常式。例如,在大部分情況下,您可以使用它來存取 libc 函數或 rb_str_new 等 Ruby 函數。

static VALUE
rb_fiddle_handle_initialize(int argc, VALUE argv[], VALUE self)
{
    void *ptr;
    struct dl_handle *fiddle_handle;
    VALUE lib, flag;
    char  *clib;
    int   cflag;
    const char *err;

    switch( rb_scan_args(argc, argv, "02", &lib, &flag) ){
      case 0:
        clib = NULL;
        cflag = RTLD_LAZY | RTLD_GLOBAL;
        break;
      case 1:
        clib = NIL_P(lib) ? NULL : StringValueCStr(lib);
        cflag = RTLD_LAZY | RTLD_GLOBAL;
        break;
      case 2:
        clib = NIL_P(lib) ? NULL : StringValueCStr(lib);
        cflag = NUM2INT(flag);
        break;
      default:
        rb_bug("rb_fiddle_handle_new");
    }

#if defined(_WIN32)
    if( !clib ){
        HANDLE rb_libruby_handle(void);
        ptr = rb_libruby_handle();
    }
    else if( STRCASECMP(clib, "libc") == 0
# ifdef RUBY_COREDLL
             || STRCASECMP(clib, RUBY_COREDLL) == 0
             || STRCASECMP(clib, RUBY_COREDLL".dll") == 0
# endif
        ){
# ifdef _WIN32_WCE
        ptr = dlopen("coredll.dll", cflag);
# else
        (void)cflag;
        ptr = w32_coredll();
# endif
    }
    else
#endif
        ptr = dlopen(clib, cflag);
#if defined(HAVE_DLERROR)
    if( !ptr && (err = dlerror()) ){
        rb_raise(rb_eFiddleDLError, "%s", err);
    }
#else
    if( !ptr ){
        err = dlerror();
        rb_raise(rb_eFiddleDLError, "%s", err);
    }
#endif
    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    if( fiddle_handle->ptr && fiddle_handle->open && fiddle_handle->enable_close ){
        dlclose(fiddle_handle->ptr);
    }
    fiddle_handle->ptr = ptr;
    fiddle_handle->open = 1;
    fiddle_handle->enable_close = 0;

    if( rb_block_given_p() ){
        rb_ensure(rb_yield, self, rb_fiddle_handle_close, self);
    }

    return Qnil;
}
sym(name) 按一下以切換來源

取得名為 name 的函數的地址,作為 Integer

static VALUE
rb_fiddle_handle_s_sym(VALUE self, VALUE sym)
{
    return fiddle_handle_sym(RTLD_NEXT, sym);
}
sym_defined?(p1) 按一下以切換來源
static VALUE
rb_fiddle_handle_s_sym_defined(VALUE self, VALUE sym)
{
    fiddle_void_func func;

    func = fiddle_handle_find_func(RTLD_NEXT, sym);

    if( func ) {
        return PTR2NUM(func);
    }
    else {
        return Qnil;
    }
}

公用實例方法

[]
別名為:sym
close 按一下以切換來源

關閉此處理常式。

呼叫 close 多次會引發 Fiddle::DLError 例外。

static VALUE
rb_fiddle_handle_close(VALUE self)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    if(fiddle_handle->open) {
        int ret = dlclose(fiddle_handle->ptr);
        fiddle_handle->open = 0;

        /* Check dlclose for successful return value */
        if(ret) {
#if defined(HAVE_DLERROR)
            rb_raise(rb_eFiddleDLError, "%s", dlerror());
#else
            rb_raise(rb_eFiddleDLError, "could not close handle");
#endif
        }
        return INT2NUM(ret);
    }
    rb_raise(rb_eFiddleDLError, "dlclose() called too many times");

    UNREACHABLE;
}
close_enabled? 按一下以切換來源

如果會在垃圾回收此處理常式時呼叫 dlclose(),則傳回 true

有關更多資訊,請參閱 man(3) dlclose()。

static VALUE
rb_fiddle_handle_close_enabled_p(VALUE self)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);

    if(fiddle_handle->enable_close) return Qtrue;
    return Qfalse;
}
disable_close 按一下以切換來源

在垃圾回收此處理常式時停用對 dlclose() 的呼叫。

static VALUE
rb_fiddle_handle_disable_close(VALUE self)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    fiddle_handle->enable_close = 0;
    return Qnil;
}
enable_close 按一下以切換來源

在垃圾回收此處理常式時啟用對 dlclose() 的呼叫。

static VALUE
rb_fiddle_handle_enable_close(VALUE self)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    fiddle_handle->enable_close = 1;
    return Qnil;
}
file_name 按一下以切換來源

傳回此處理常式的檔案名稱。

static VALUE
rb_fiddle_handle_file_name(VALUE self)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);

#if defined(HAVE_DLINFO) && defined(HAVE_CONST_RTLD_DI_LINKMAP)
    {
        struct link_map *lm = NULL;
        int res = dlinfo(fiddle_handle->ptr, RTLD_DI_LINKMAP, &lm);
        if (res == 0 && lm != NULL) {
            return rb_str_new_cstr(lm->l_name);
        }
        else {
#if defined(HAVE_DLERROR)
            rb_raise(rb_eFiddleDLError, "could not get handle file name: %s", dlerror());
#else
            rb_raise(rb_eFiddleDLError, "could not get handle file name");
#endif
        }
    }
#elif defined(HAVE_GETMODULEFILENAME)
    {
        char filename[MAX_PATH];
        DWORD res = GetModuleFileName(fiddle_handle->ptr, filename, MAX_PATH);
        if (res == 0) {
            rb_raise(rb_eFiddleDLError, "could not get handle file name: %s", dlerror());
        }
        return rb_str_new_cstr(filename);
    }
#else
    (void)fiddle_handle;
    return Qnil;
#endif
}
sym(name) 按一下以切換來源

取得名為 name 的函數的地址,作為 Integer

static VALUE
rb_fiddle_handle_sym(VALUE self, VALUE sym)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    if( ! fiddle_handle->open ){
        rb_raise(rb_eFiddleDLError, "closed handle");
    }

    return fiddle_handle_sym(fiddle_handle->ptr, sym);
}
別名:[]、[]
sym_defined?(p1) 按一下以切換來源
static VALUE
rb_fiddle_handle_sym_defined(VALUE self, VALUE sym)
{
    struct dl_handle *fiddle_handle;
    fiddle_void_func func;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    if( ! fiddle_handle->open ){
        rb_raise(rb_eFiddleDLError, "closed handle");
    }

    func = fiddle_handle_find_func(fiddle_handle->ptr, sym);

    if( func ) {
        return PTR2NUM(func);
    }
    else {
        return Qnil;
    }
}
to_i 按一下以切換原始碼

傳回此控制項的記憶體位址。

static VALUE
rb_fiddle_handle_to_i(VALUE self)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    return PTR2NUM(fiddle_handle->ptr);
}
to_ptr 按一下以切換原始碼

傳回此控制項的 Fiddle::Pointer

static VALUE
rb_fiddle_handle_to_ptr(VALUE self)
{
    struct dl_handle *fiddle_handle;

    TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle);
    return rb_fiddle_ptr_new_wrap(fiddle_handle->ptr, 0, 0, self, 0);
}