aboutsummaryrefslogblamecommitdiffstats
path: root/erts/emulator/sys/vxworks/erl_vxworks_sys_ddll.c
blob: c56c633b2ff6aa245aeaba55d4a327b2ecb887f5 (plain) (tree)




























































































































































































































































                                                                                                 
/*
 * %CopyrightBegin%
 * 
 * Copyright Ericsson AB 2006-2009. All Rights Reserved.
 * 
 * The contents of this file are subject to the Erlang Public License,
 * Version 1.1, (the "License"); you may not use this file except in
 * compliance with the License. You should have received a copy of the
 * Erlang Public License along with this software. If not, it can be
 * retrieved online at http://www.erlang.org/.
 * 
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 * 
 * %CopyrightEnd%
 */

/* 
 * Interface functions to the dynamic linker using dl* functions.
 * (As far as I know it works on SunOS 4, 5, Linux and FreeBSD. /Seb) 
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif
#include <vxWorks.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <a_out.h>
#include <symLib.h>
#include <loadLib.h>
#include <unldLib.h>
#include <moduleLib.h>
#include <sysSymTbl.h>
#include "sys.h"
#include "global.h"
#include "erl_alloc.h"
#include "erl_driver.h"

#define EXT_LEN          4
#define FILE_EXT         ".eld"
#define ALT_FILE_EXT     ".o"
/* ALT_FILE_EXT must not be longer than FILE_EXT */
#define DRIVER_INIT_SUFFIX "_init"

static MODULE_ID get_mid(char *);
static FUNCPTR lookup(char *);

typedef enum {
    NoError,
    ModuleNotFound,
    ModuleNotUnloadable,
    UnknownError
} FakeSytemError;

static char *errcode_tab[] = {
    "No error",
    "Module/file not found",
    "Module cannot be unloaded",
    "Unknown error"
};

void erl_sys_ddll_init(void) {
    return;
}
/* 
 * Open a shared object
 */
int erts_sys_ddll_open2(char *full_name, void **handle, ErtsSysDdllError* err)
{
    int len;
    
    if (erts_sys_ddll_open_noext(full_name, handle, err) == ERL_DE_NO_ERROR) {
	return ERL_DE_NO_ERROR;
    }
    if ((len = sys_strlen(full_name)) > PATH_MAX-EXT_LEN) {
	return ERL_DE_LOAD_ERROR_NAME_TO_LONG;
    } else {
	static char dlname[PATH_MAX + 1];
	
	sys_strcpy(dlname, full_name);
	sys_strcpy(dlname+len, FILE_EXT);
	if (erts_sys_ddll_open_noext(dlname, handle, err) == ERL_DE_NO_ERROR) {
	    return ERL_DE_NO_ERROR;
	}
	sys_strcpy(dlname+len, ALT_FILE_EXT);
	return erts_sys_ddll_open_noext(dlname, handle, err);
    }
}
int erts_sys_ddll_open_noext(char *dlname, void **handle, ErtsSysDdllError* err)
{
    MODULE_ID mid;
    
    if((mid = get_mid(dlname)) == NULL) {
	return ERL_DE_DYNAMIC_ERROR_OFFSET - ((int) ModuleNotFound);
    }
    *handle = (void *) mid;
    return ERL_DE_NO_ERROR;
}

/* 
 * Find a symbol in the shared object
 */
#define PREALLOC_BUFFER_SIZE 256
int erts_sys_ddll_sym2(void *handle, char *func_name, void **function, ErtsSysDdllError* err)
{
    FUNCPTR proc;
    static char statbuf[PREALLOC_BUFFER_SIZE];
    char *buf = statbuf;
    int need;

    if ((proc = lookup(func_name)) == NULL) {
	if ((need = strlen(func_name)+2) > PREALLOC_BUFFER_SIZE) {
	    buf = erts_alloc(ERTS_ALC_T_DDLL_TMP_BUF,need);
	}
	buf[0] = '_';
	sys_strcpy(buf+1,func_name);
	proc = lookup(buf);
	if (buf != statbuf) {
	    erts_free(ERTS_ALC_T_DDLL_TMP_BUF, buf);
	}
	if (proc == NULL) {
	    return  ERL_DE_LOOKUP_ERROR_NOT_FOUND;
	}
    }
    *function = (void *) proc;
    return ERL_DE_NO_ERROR;
}

/* XXX:PaN These two will be changed with new driver interface! */

/* 
 * Load the driver init function, might appear under different names depending on object arch... 
 */

int erts_sys_ddll_load_driver_init(void *handle, void **function)
{
    MODULE_ID mid = (MODULE_ID) handle;
    char *modname;
    char *cp;
    static char statbuf[PREALLOC_BUFFER_SIZE];
    char *fname = statbuf;
    int len;
    int res;
    void *func;
    int need;

    if((modname = moduleNameGet(mid)) == NULL) {
	return ERL_DE_DYNAMIC_ERROR_OFFSET - ((int) ModuleNotFound);
    }
    
    if((cp = strrchr(modname, '.')) == NULL) {
	len = strlen(modname);
    } else {
	len = cp - modname;
    }
    
    need =  len + strlen(DRIVER_INIT_SUFFIX) + 1;
    if (need > PREALLOC_BUFFER_SIZE) {
	fname = erts_alloc(ERTS_ALC_T_DDLL_TMP_BUF, need); /* erts_alloc exits on failure */
    }
    sys_strncpy(fname, modname, len);
    fname[len] = '\0';
    sys_strcat(fname, DRIVER_INIT_SUFFIX);
    res = erts_sys_ddll_sym(handle, fname, &func);
    if (fname != statbuf) {
	erts_free(ERTS_ALC_T_DDLL_TMP_BUF, fname);
    }
    if ( res != ERL_DE_NO_ERROR) {
	return res;
    }
    *function = func;
    return ERL_DE_NO_ERROR;
}

int erts_sys_ddll_load_nif_init(void *handle, void **function, ErtsSysDdllError* err)
{
    /* NIFs not implemented for vxworks */
    return ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY;
}

/* 
 * Call the driver_init function, whatever it's really called, simple on unix... 
*/
void *erts_sys_ddll_call_init(void *function) {
    void *(*initfn)(void) = function;
    return (*initfn)();
}
void *erts_sys_ddll_call_nif_init(void *function) {
    return erts_sys_ddll_call_init(function);
}


/* 
 * Close a chared object
 */
int erts_sys_ddll_close2(void *handle, ErtsSysDdllError* err)
{
    MODULE_ID mid = (MODULE_ID) handle;
    if (unld(mid, 0) < 0) {
	return  ERL_DE_DYNAMIC_ERROR_OFFSET - ((int) ModuleNotUnloadable);
    }
    return  ERL_DE_NO_ERROR;
}

/*
 * Return string that describes the (current) error
 */
char *erts_sys_ddll_error(int code)
{
    int actual_code;
    if (code > ERL_DE_DYNAMIC_ERROR_OFFSET) {
	return "Unspecified error";
    }
    actual_code = -1*(code - ERL_DE_DYNAMIC_ERROR_OFFSET);
    if (actual_code > ((int) UnknownError)) {
	actual_code = UnknownError;
    }
    return  errcode_tab[actual_code];
}

static FUNCPTR lookup(char *sym)
{
    FUNCPTR entry;
    SYM_TYPE type;
    
    if (symFindByNameAndType(sysSymTbl, sym, (char **)&entry,
			     &type, N_EXT | N_TEXT, N_EXT | N_TEXT) != OK) {
	return NULL ;
    }
    return entry;
}

static MODULE_ID get_mid(char* name) 
{ 
    int fd;
    MODULE_ID mid = NULL;
    
    if((fd = open(name, O_RDONLY, 0664)) >= 0) {
	mid = loadModule(fd, GLOBAL_SYMBOLS);
	close(fd);
    }
    return mid;
}

void erts_sys_ddll_free_error(ErtsSysDdllError* err)
{
    /* NYI */
}