diff options
Diffstat (limited to 'erts/emulator/sys/vxworks/erl_vxworks_sys_ddll.c')
-rw-r--r-- | erts/emulator/sys/vxworks/erl_vxworks_sys_ddll.c | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/erts/emulator/sys/vxworks/erl_vxworks_sys_ddll.c b/erts/emulator/sys/vxworks/erl_vxworks_sys_ddll.c new file mode 100644 index 0000000000..c56c633b2f --- /dev/null +++ b/erts/emulator/sys/vxworks/erl_vxworks_sys_ddll.c @@ -0,0 +1,253 @@ +/* + * %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 */ +} + |