/* * %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 #include #include #include #include #include #include #include #include #include #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 */ }