In Files

  • dl/cfunc.c

DL::CFunc

A direct accessor to a function in a C library

Example

libc_so = "/lib64/libc.so.6"
=> "/lib64/libc.so.6"
libc = DL::dlopen(libc_so)
=> #<DL::Handle:0x00000000e05b00>
@cfunc = DL::CFunc.new(libc,['strcpy'], DL::TYPE_VOIDP, 'strcpy')
=> #<DL::CFunc:0x000000012daec0 ptr=0x007f62ca5a8300 type=1 name='strcpy'>

Public Class Methods

last_error() click to toggle source

Returns the last error for the current executing thread

 
               static VALUE
rb_dl_get_last_error(VALUE self)
{
    return rb_thread_local_aref(rb_thread_current(), id_last_error);
}
            
DL::CFunc.new(address, type=DL::TYPE_VOID, name=nil, calltype=:cdecl) click to toggle source

Create a new function that points to address with an optional return type of type, a name of name and a calltype of calltype.

 
               static VALUE
rb_dlcfunc_initialize(int argc, VALUE argv[], VALUE self)
{
    VALUE addr, name, type, calltype, addrnum;
    struct cfunc_data *data;
    void *saddr;
    const char *sname;

    rb_scan_args(argc, argv, "13", &addr, &type, &name, &calltype);

    addrnum = rb_Integer(addr);
    saddr = (void*)(NUM2PTR(addrnum));
    sname = NIL_P(name) ? NULL : StringValuePtr(name);

    TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, data);
    if( data->name ) xfree(data->name);
    data->ptr  = saddr;
    data->name = sname ? strdup(sname) : 0;
    data->type = NIL_P(type) ? DLTYPE_VOID : NUM2INT(type);
    data->calltype = NIL_P(calltype) ? CFUNC_CDECL : SYM2ID(calltype);
    data->wrap = (addrnum == addr) ? 0 : addr;

    return Qnil;
}
            
win32_last_error() click to toggle source

Returns the last win32 error for the current executing thread

 
               static VALUE
rb_dl_get_win32_last_error(VALUE self)
{
    return rb_thread_local_aref(rb_thread_current(), id_win32_last_error);
}
            

Public Instance Methods

call(ary) => some_value click to toggle source
dlcfunc[ary] => some_value

Calls the function pointer passing in ary as values to the underlying C function. The return value depends on the ctype.

 
               static VALUE
rb_dlcfunc_call(VALUE self, VALUE ary)
{
    struct cfunc_data *cfunc;
    int i;
    DLSTACK_TYPE stack[DLSTACK_SIZE];
    VALUE result = Qnil;

    rb_secure_update(self);

    memset(stack, 0, sizeof(DLSTACK_TYPE) * DLSTACK_SIZE);
    Check_Type(ary, T_ARRAY);

    TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);

    if( cfunc->ptr == 0 ){
        rb_raise(rb_eDLError, "can't call null-function");
        return Qnil;
    }

    for( i = 0; i < RARRAY_LEN(ary); i++ ){
        VALUE arg;
        if( i >= DLSTACK_SIZE ){
            rb_raise(rb_eDLError, "too many arguments (stack overflow)");
        }
        arg = rb_to_int(RARRAY_PTR(ary)[i]);
        rb_check_safe_obj(arg);
        if (FIXNUM_P(arg)) {
            stack[i] = (DLSTACK_TYPE)FIX2LONG(arg);
        }
        else if (RB_TYPE_P(arg, T_BIGNUM)) {
#if SIZEOF_VOIDP == SIZEOF_LONG
            stack[i] = (DLSTACK_TYPE)rb_big2ulong_pack(arg);
#else
            stack[i] = (DLSTACK_TYPE)rb_big2ull(arg);
#endif
        }
        else {
            Check_Type(arg, T_FIXNUM);
        }
    }

    /* calltype == CFUNC_CDECL */
    if( cfunc->calltype == CFUNC_CDECL
#ifndef FUNC_STDCALL
        || cfunc->calltype == CFUNC_STDCALL
#endif
        ){
        switch( cfunc->type ){
        case DLTYPE_VOID:
#define CASE(n) case n: { \
            DECL_FUNC_CDECL(f,void,DLSTACK_PROTO##n,cfunc->ptr); \
            f(DLSTACK_ARGS##n(stack)); \
            result = Qnil; \
}
            
call(ary) => some_value click to toggle source
dlcfunc[ary] => some_value

Calls the function pointer passing in ary as values to the underlying C function. The return value depends on the ctype.

 
               static VALUE
rb_dlcfunc_call(VALUE self, VALUE ary)
{
    struct cfunc_data *cfunc;
    int i;
    DLSTACK_TYPE stack[DLSTACK_SIZE];
    VALUE result = Qnil;

    rb_secure_update(self);

    memset(stack, 0, sizeof(DLSTACK_TYPE) * DLSTACK_SIZE);
    Check_Type(ary, T_ARRAY);

    TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);

    if( cfunc->ptr == 0 ){
        rb_raise(rb_eDLError, "can't call null-function");
        return Qnil;
    }

    for( i = 0; i < RARRAY_LEN(ary); i++ ){
        VALUE arg;
        if( i >= DLSTACK_SIZE ){
            rb_raise(rb_eDLError, "too many arguments (stack overflow)");
        }
        arg = rb_to_int(RARRAY_PTR(ary)[i]);
        rb_check_safe_obj(arg);
        if (FIXNUM_P(arg)) {
            stack[i] = (DLSTACK_TYPE)FIX2LONG(arg);
        }
        else if (RB_TYPE_P(arg, T_BIGNUM)) {
#if SIZEOF_VOIDP == SIZEOF_LONG
            stack[i] = (DLSTACK_TYPE)rb_big2ulong_pack(arg);
#else
            stack[i] = (DLSTACK_TYPE)rb_big2ull(arg);
#endif
        }
        else {
            Check_Type(arg, T_FIXNUM);
        }
    }

    /* calltype == CFUNC_CDECL */
    if( cfunc->calltype == CFUNC_CDECL
#ifndef FUNC_STDCALL
        || cfunc->calltype == CFUNC_STDCALL
#endif
        ){
        switch( cfunc->type ){
        case DLTYPE_VOID:
#define CASE(n) case n: { \
            DECL_FUNC_CDECL(f,void,DLSTACK_PROTO##n,cfunc->ptr); \
            f(DLSTACK_ARGS##n(stack)); \
            result = Qnil; \
}
            
calltype => symbol click to toggle source

Get the call type of this function.

 
               static VALUE
rb_dlcfunc_calltype(VALUE self)
{
    struct cfunc_data *cfunc;

    TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
    return ID2SYM(cfunc->calltype);
}
            
calltype = symbol click to toggle source

Set the call type for this function.

 
               static VALUE
rb_dlcfunc_set_calltype(VALUE self, VALUE sym)
{
    struct cfunc_data *cfunc;

    TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
    cfunc->calltype = SYM2ID(sym);
    return sym;
}
            
ctype => num click to toggle source

Get the C function return value type. See DL for a list of constants corresponding to this method's return value.

 
               static VALUE
rb_dlcfunc_ctype(VALUE self)
{
    struct cfunc_data *cfunc;

    TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
    return INT2NUM(cfunc->type);
}
            
ctype = type click to toggle source

Set the C function return value type to type.

 
               static VALUE
rb_dlcfunc_set_ctype(VALUE self, VALUE ctype)
{
    struct cfunc_data *cfunc;

    TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
    cfunc->type = NUM2INT(ctype);
    return ctype;
}
            
inspect click to toggle source

Returns a string formatted with an easily readable representation of the internal state of the DL::CFunc

 
               static VALUE
rb_dlcfunc_inspect(VALUE self)
{
    VALUE val;
    struct cfunc_data *cfunc;

    TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);

    val = rb_sprintf("#<DL::CFunc:%p ptr=%p type=%d name='%s'>",
             cfunc,
             cfunc->ptr,
             cfunc->type,
             cfunc->name ? cfunc->name : "");
    OBJ_TAINT(val);
    return val;
}
            
name => str click to toggle source

Get the name of this function

 
               static VALUE
rb_dlcfunc_name(VALUE self)
{
    struct cfunc_data *cfunc;

    TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
    return cfunc->name ? rb_tainted_str_new2(cfunc->name) : Qnil;
}
            
ptr click to toggle source

Get the underlying function pointer as a DL::CPtr object.

 
               static VALUE
rb_dlcfunc_ptr(VALUE self)
{
    struct cfunc_data *cfunc;

    TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
    return PTR2NUM(cfunc->ptr);
}
            
ptr = pointer click to toggle source

Set the underlying function pointer to a DL::CPtr named pointer.

 
               static VALUE
rb_dlcfunc_set_ptr(VALUE self, VALUE addr)
{
    struct cfunc_data *cfunc;

    TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
    cfunc->ptr = NUM2PTR(addr);

    return Qnil;
}
            
to_i => integer click to toggle source

Returns the memory location of this function pointer as an integer.

 
               static VALUE
rb_dlcfunc_to_i(VALUE self)
{
  struct cfunc_data *cfunc;

  TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);
  return PTR2NUM(cfunc->ptr);
}
            
inspect click to toggle source

Returns a string formatted with an easily readable representation of the internal state of the DL::CFunc

 
               static VALUE
rb_dlcfunc_inspect(VALUE self)
{
    VALUE val;
    struct cfunc_data *cfunc;

    TypedData_Get_Struct(self, struct cfunc_data, &dlcfunc_data_type, cfunc);

    val = rb_sprintf("#<DL::CFunc:%p ptr=%p type=%d name='%s'>",
             cfunc,
             cfunc->ptr,
             cfunc->type,
             cfunc->name ? cfunc->name : "");
    OBJ_TAINT(val);
    return val;
}