/* * Copyright (c) 2019, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef FARF_ERROR #define FARF_ERROR 1 #endif #include #include "verify.h" #include "HAP_farf.h" #include "HAP_pls.h" #include "mutex.h" #include "mod_table.h" #include "platform_libs.h" #include "remote64.h" #include "uthash.h" #include "AEEstd.h" #include "AEEStdErr.h" #include "sbuf_parser.h" #include #define DLOPEN dlopen #define DLCLOSE dlclose #define DLSYM dlsym #define DLERROR dlerror /** * structure for the mod table * * you need to define a rw_mutex type and its read/write lock/unlock api's * which are under the RW_MUTEX namespace. * * this library defines 2 functions for opening modules, open_static and * open_dynamic. Both return a handle that should be closed via close. * * you can also register a const handle, an invoke function for a known handle * value. since handle keys are allocated, you should pick handle values that are * not going to be returned by malloc (0, or odd). */ struct static_mod_table { RW_MUTEX_T mut; struct static_mod* staticModOverrides; struct static_mod* staticMods; struct const_mod* constMods; boolean bInit; }; struct open_mod_table { RW_MUTEX_T mut; struct open_mod* openMods; struct static_mod_table* smt; }; typedef int (*invoke_fn)(uint32, remote_arg*); typedef int (*handle_invoke_fn)(remote_handle64, uint32, remote_arg*); struct static_mod { invoke_fn invoke; handle_invoke_fn handle_invoke; UT_hash_handle hh; char uri[1]; }; struct const_mod { invoke_fn invoke; handle_invoke_fn handle_invoke; uint32 key; remote_handle64 h64; UT_hash_handle hh; char uri[1]; }; struct parsed_uri { const char *file; int filelen; const char *sym; int symlen; const char *ver; int verlen; }; struct open_mod { void* dlhandle; invoke_fn invoke; handle_invoke_fn handle_invoke; uint64 key; UT_hash_handle hh; remote_handle64 h64; int refs; struct parsed_uri vals; char uri[1]; }; static int static_mod_table_ctor(struct static_mod_table* me) { if(me->bInit == 0) { RW_MUTEX_CTOR(me->mut); me->staticMods = 0; me->staticModOverrides = 0; me->bInit = 1; } return 0; } static void static_mod_table_dtor_imp(struct static_mod_table* me) { struct static_mod *sm, *stmp; struct const_mod *dm, *ftmp; if(me->bInit != 0) { if( me->staticMods || me->constMods || me->staticModOverrides) { RW_MUTEX_LOCK_WRITE(me->mut); HASH_ITER(hh, me->staticMods, sm, stmp) { if(me->staticMods) { HASH_DEL(me->staticMods,sm); } free(sm); sm = NULL; } HASH_ITER(hh, me->staticModOverrides, sm, stmp) { if(me->staticModOverrides) { HASH_DEL(me->staticModOverrides,sm); } free(sm); sm = NULL; } HASH_ITER(hh, me->constMods, dm, ftmp) { if(me->constMods) { HASH_DEL(me->constMods,dm); } free(dm); dm = NULL; } RW_MUTEX_UNLOCK_WRITE(me->mut); } RW_MUTEX_DTOR(me->mut); me->staticMods = 0; me->staticModOverrides = 0; me->bInit = 0; } } static int open_mod_table_ctor_imp(void* ctx, void* data) { struct open_mod_table* me = (struct open_mod_table*)data; RW_MUTEX_CTOR(me->mut); me->openMods = 0; me->smt = (struct static_mod_table*) ctx; return 0; } static int open_mod_handle_close(struct open_mod *mod, remote_handle64 h); static void open_mod_table_dtor_imp(void* data) { struct open_mod_table* me = (struct open_mod_table*)data; struct open_mod *dm, *ftmp; if( me->openMods) { RW_MUTEX_LOCK_WRITE(me->mut); HASH_ITER(hh, me->openMods, dm, ftmp) { if(me->openMods) { HASH_DEL(me->openMods,dm); } if(dm->h64) { (void)open_mod_handle_close(dm, dm->h64); } if(dm->dlhandle) { DLCLOSE(dm->dlhandle); } free(dm); } RW_MUTEX_UNLOCK_WRITE(me->mut); } RW_MUTEX_DTOR(me->mut); me->openMods = 0; } static int open_mod_table_open_from_static(struct open_mod_table* me, struct static_mod** tbl, const char* uri, remote_handle* handle); static int open_mod_table_open_static_override(struct open_mod_table* me, const char* uri, remote_handle* handle) { FARF(HIGH, "open_mod_table_open_static_override"); return open_mod_table_open_from_static(me, &me->smt->staticModOverrides, uri, handle); } static int open_mod_table_open_static(struct open_mod_table* me, const char* uri, remote_handle* handle) { FARF(HIGH, "open_mod_table_open_static"); return open_mod_table_open_from_static(me, &me->smt->staticMods, uri, handle); } static int static_mod_add(struct static_mod_table* me, struct static_mod** tbl, const char* uri, int(*invoke)(uint32 sc, remote_arg* pra), int(*handle_invoke)(remote_handle64, uint32 sc, remote_arg* pra)) { int nErr = AEE_SUCCESS; struct static_mod *sm = 0; int len = std_strlen(uri) + 1; VERIFYC(NULL != (sm = ((struct static_mod*)calloc(1, sizeof(struct static_mod) + len))), AEE_ENOMEMORY); std_strlcpy(sm->uri, uri, len); sm->invoke = invoke; sm->handle_invoke = handle_invoke; RW_MUTEX_LOCK_WRITE(me->mut); HASH_ADD_STR(*tbl, uri, sm); RW_MUTEX_UNLOCK_WRITE(me->mut); bail: if(nErr != AEE_SUCCESS) { VERIFY_EPRINTF("Error %x: static module addition failed\n", nErr); if(sm) { free(sm); sm = NULL; } } return nErr; } static int static_mod_table_register_static_override(struct static_mod_table* me, const char* uri, int(*pfn)(uint32 sc, remote_arg* pra)) { return static_mod_add(me, &me->staticModOverrides, uri, pfn, 0); } static int static_mod_table_register_static_override1(struct static_mod_table* me, const char* uri, int(*pfn)(remote_handle64, uint32 sc, remote_arg* pra)) { return static_mod_add(me, &me->staticModOverrides, uri, 0, pfn); } static int static_mod_table_register_static(struct static_mod_table* me, const char* uri, int(*pfn)(uint32 sc, remote_arg* pra)) { return static_mod_add(me, &me->staticMods, uri, pfn, 0); } static int static_mod_table_register_static1(struct static_mod_table* me, const char* uri, int(*pfn)(remote_handle64,uint32 sc, remote_arg* pra)) { return static_mod_add(me, &me->staticMods, uri, 0, pfn); } static int static_mod_table_register_const_handle(struct static_mod_table* me, remote_handle local, remote_handle64 remote, const char* uri, int(*invoke)(uint32 sc, remote_arg* pra), int(*handle_invoke)(remote_handle64, uint32 sc, remote_arg* pra) ) { int nErr = AEE_SUCCESS; int len = std_strlen(uri) + 1; struct const_mod *dm = 0, *dmOld; VERIFYC(NULL != (dm = ((struct const_mod*)calloc(1, sizeof(struct open_mod) + len))), AEE_ENOMEMORY); dm->key = local; dm->invoke = invoke; dm->handle_invoke = handle_invoke; dm->h64 = remote; std_strlcpy(dm->uri, uri, len); RW_MUTEX_LOCK_WRITE(me->mut); HASH_FIND_INT(me->constMods, &local, dmOld); if(dmOld == 0) { HASH_ADD_INT(me->constMods, key, dm); } RW_MUTEX_UNLOCK_WRITE(me->mut); nErr = dmOld != 0 ? -1 : nErr; bail: if(nErr != AEE_SUCCESS) { VERIFY_EPRINTF("Error %x: failed to register const handle in modtable\n", nErr); if(dm) { free(dm); dm = NULL; } } return nErr; } static int open_mod_handle_open(struct open_mod *mod, const char* name, remote_handle64 *ph) { int nErr = AEE_SUCCESS; remote_arg args[3]; int32_t len = strlen(name) + 1; args[0].buf.pv = &len; args[0].buf.nLen = sizeof(len); args[1].buf.pv = (void*)name; args[1].buf.nLen = len; nErr = mod->handle_invoke(0,REMOTE_SCALARS_MAKEX(0,0,2,0,0,1),args); if(!nErr) { *ph = args[2].h64; } FARF(HIGH, "allocated %x", *ph); return nErr; } static int open_mod_handle_close(struct open_mod *mod, remote_handle64 h) { int nErr; remote_arg args[1]; args[0].h64 = h; FARF(HIGH, "releasing %x", h); nErr = mod->handle_invoke(0,REMOTE_SCALARS_MAKEX(0,1,0,0,1,0),args); return nErr; } static int notqmark(struct sbuf *buf) { return sbuf_notchar(buf, '?'); } static int notandoreq(struct sbuf *buf) { return sbuf_notchars(buf, "&="); } static int notand(struct sbuf *buf) { return sbuf_notchar(buf, '&'); } static int parse_uri(const char *uri, int urilen, struct parsed_uri *out) { // "file:///librhtest_skel.so?rhtest_skel_handle_invoke&_modver=1.0" int nErr = 0; char *name, *value; int nameLen, valueLen; struct sbuf buf; FARF(HIGH, "parse_uri %s %d", uri, urilen); memset(out, 0, sizeof(*out)); //initialize sbuf_parser_init(&buf, uri, urilen); //parse until question mark VERIFYC(sbuf_string(&buf, "file://"), AEE_EINVALIDFORMAT); //ignore the starting / (void)sbuf_string(&buf, "/"); out->file = sbuf_cur(&buf); VERIFY(sbuf_many1(&buf, notqmark)); out->filelen = sbuf_cur(&buf) - out->file; FARF(HIGH, "file:%.*s %d", out->filelen, out->file, out->filelen); VERIFY(sbuf_char(&buf, '?')); out->sym = sbuf_cur(&buf); VERIFY(sbuf_many1(&buf, notand)); out->symlen = sbuf_cur(&buf) - out->sym; assert(out->sym + out->symlen <= uri + urilen); FARF(HIGH, "sym:%.*s %d", out->symlen, out->sym, out->symlen); if(!sbuf_end(&buf) && sbuf_char(&buf, '&')) { //parse each query while(!sbuf_end(&buf)) { //record where the name starts name = sbuf_cur(&buf); //name is valid until '=' or '&' VERIFY(sbuf_many1(&buf, notandoreq)); nameLen = sbuf_cur(&buf) - name; value = 0; valueLen = 0; //if the next char is a '=' then we also get a value if(sbuf_char(&buf, '=')) { value = sbuf_cur(&buf); //value is until the next query that starts with '&' VERIFY(sbuf_many1(&buf, notand)); valueLen = sbuf_cur(&buf) - value; } //expect '&' or end sbuf_char(&buf, '&'); if(!std_strncmp(name, "_modver", nameLen)) { out->ver = value; out->verlen = valueLen; } } } bail: if(out->filelen) { FARF(HIGH, "parse_uri file: %.*s", out->filelen, out->file); } if(out->symlen) { FARF(HIGH, "parse_uri sym: %.*s", out->symlen, out->sym); } if(out->verlen) { FARF(HIGH, "parse_uri version: %.*s", out->verlen, out->ver); } FARF(HIGH, "parse_uri done: %s %d err:%x", uri, urilen, nErr); if(nErr != AEE_SUCCESS) { VERIFY_EPRINTF("Error %x: parseuri failed for uri %s, urilen %d\n", nErr, uri, urilen); } return nErr; } static int open_mod_table_open_dynamic(struct open_mod_table* me, const char* uri, remote_handle* handle, char* dlStr, int dlerrorLen, int* pdlErr) { int nErr = AEE_SUCCESS, dlErr = 0; struct open_mod *dm = 0, *dmOld; int len = strlen(uri); int tmplen = len*2 + sizeof("file:///lib_skel.so?_skel_handle_invoke&_modver=1.0") + 1; char *tmp = 0; FARF(HIGH, "open_mod_table_open_dynamic"); VERIFYC(NULL != (tmp = calloc(1, tmplen)), AEE_ENOMEMORY); VERIFYC(NULL != (dm = ((struct open_mod*)calloc(1, sizeof(struct open_mod) + len + 1))), AEE_ENOMEMORY); std_memmove(dm->uri, uri, len + 1); FARF(HIGH, "calling parse_uri"); (void)parse_uri(dm->uri, len, &dm->vals); FARF(HIGH, "done calling parse_uri"); FARF(HIGH, "vals %d %d %d", dm->vals.filelen, dm->vals.symlen, dm->vals.verlen); if(dm->vals.filelen) { int rv = std_snprintf(tmp, tmplen, "%.*s", dm->vals.filelen, dm->vals.file); VERIFYC(tmplen >= rv, AEE_EBADSIZE); } else { int rv; rv = std_snprintf(tmp, tmplen, "lib%s_skel.so", uri); VERIFYC(tmplen >= rv, AEE_EBADSIZE); } FARF(HIGH, "calling dlopen for %s", tmp); dm->dlhandle = DLOPEN(tmp,RTLD_NOW); FARF(HIGH, "got %p for dlopen %s", dm->dlhandle, tmp); VERIFY(!(nErr = (dlErr = dm->dlhandle == 0 ? -5 : 0))); if(dm->vals.symlen) { int rv = std_snprintf(tmp, tmplen, "%.*s", dm->vals.symlen, dm->vals.sym); VERIFYC(tmplen >= rv, AEE_EBADSIZE); } else { int rv = std_snprintf(tmp, tmplen, "%s_skel_invoke", uri); VERIFYC(tmplen >= rv, AEE_EBADSIZE); } FARF(HIGH, "calling dlsym for %s", tmp); if(dm->vals.verlen && 0 == std_strncmp(dm->vals.ver, "1.0", dm->vals.verlen)) { dm->handle_invoke = (handle_invoke_fn) DLSYM(dm->dlhandle, tmp); } else { dm->invoke = (invoke_fn) DLSYM(dm->dlhandle, tmp); } FARF(HIGH, "dlsym returned %p %p", dm->invoke, dm->handle_invoke); VERIFYC(!(dlErr = dm->invoke || dm->handle_invoke ? 0 : AEE_ENOSUCHSYMBOL), AEE_ENOSUCHSYMBOL); dm->key = (uint32)(uintptr_t)dm; dm->refs = 1; if(dm->handle_invoke) { VERIFY(AEE_SUCCESS == (nErr = open_mod_handle_open(dm, uri, &dm->h64))); } RW_MUTEX_LOCK_WRITE(me->mut); do { HASH_FIND_INT(me->openMods, &dm->key, dmOld); if(dmOld) { dm->key++; } } while(dmOld); RW_MUTEX_LOCK_WRITE(me->smt->mut); HASH_FIND_INT(me->smt->constMods, &dm->key, dmOld); RW_MUTEX_UNLOCK_WRITE(me->smt->mut); if(dmOld == 0) { HASH_ADD_INT(me->openMods, key, dm); } RW_MUTEX_UNLOCK_WRITE(me->mut); nErr = dmOld != 0 ? -1 : nErr; if(nErr == 0) { *handle = dm->key; } bail: if (nErr != AEE_SUCCESS) { if(dlErr) { const char* dlerr = DLERROR(); if(dlerr != 0){ std_strlcpy(dlStr,dlerr,dlerrorLen); } FARF(HIGH, "dlerror:%x:%s", dlErr, dlerr == 0 ? "" : dlerr); nErr = 0; } if(pdlErr) { *pdlErr = dlErr; } if(dm && dm->h64) { (void)open_mod_handle_close(dm, dm->h64); } if(dm && dm->dlhandle) { DLCLOSE(dm->dlhandle); } if(dm) { free(dm); dm = NULL; } VERIFY_EPRINTF("Error %x: open modtable dynamic failed. dlerr %x\n", nErr, dlErr); } FARF(HIGH, "done open_mod_table_open_dynamic for %s rv %x handle: %p %x", uri, nErr, *handle, dlErr); if(tmp) { free(tmp); tmp = NULL; } return nErr; } static int open_mod_table_open_from_static(struct open_mod_table* me, struct static_mod** tbl, const char* uri, remote_handle* handle) { int nErr = AEE_SUCCESS; struct static_mod *sm = 0; struct open_mod *dm = 0, *dmOld = 0; int len = std_strlen(uri); int sz = len*2 + sizeof("file:///lib_skel.so?_skel_handle_invoke&_modver=1.0") + 1; char *tmp = 0; VERIFYC(NULL != (dm = ((struct open_mod*)calloc(1, sizeof(*dm) + sz))), AEE_ENOMEMORY); RW_MUTEX_LOCK_READ(me->mut); HASH_FIND_STR(*tbl, uri, sm); RW_MUTEX_UNLOCK_READ(me->mut); std_memmove(dm->uri, uri, len); if(sm == 0) { VERIFY(AEE_SUCCESS == (nErr = parse_uri(uri, len, &dm->vals))); FARF(HIGH, "file %.*s %d", dm->vals.filelen, dm->vals.file, dm->vals.filelen); FARF(HIGH, "sym %.*s %d", dm->vals.symlen, dm->vals.sym, dm->vals.symlen); FARF(HIGH, "version %.*s %d", dm->vals.verlen, dm->vals.ver, dm->vals.verlen); if(dm->vals.verlen) { int rv = std_snprintf(dm->uri, sz, "file:///%.*s?%.*s&_modver=%.*s", dm->vals.filelen, dm->vals.file, dm->vals.symlen, dm->vals.sym, dm->vals.verlen, dm->vals.ver); VERIFYC(sz >= rv, AEE_EBADSIZE); } else { int rv = std_snprintf(dm->uri, sz, "file://%.*s?%.*s", dm->vals.filelen, dm->vals.file, dm->vals.symlen, dm->vals.sym); VERIFYC(sz >= rv, AEE_EBADSIZE); } FARF(HIGH, "dm->uri:%s", dm->uri); RW_MUTEX_LOCK_READ(me->mut); HASH_FIND_STR(*tbl, dm->uri, sm); RW_MUTEX_UNLOCK_READ(me->mut); } VERIFYC(0 != sm, AEE_ENOTINITIALIZED); assert(sm->handle_invoke || sm->invoke); dm->handle_invoke = sm->handle_invoke; dm->invoke = sm->invoke; dm->key = (uint32)(uintptr_t)dm; dm->refs = 1; if(dm->handle_invoke) { VERIFY(AEE_SUCCESS == (nErr = open_mod_handle_open(dm, uri, &dm->h64))); } RW_MUTEX_LOCK_WRITE(me->mut); do { HASH_FIND_INT(me->openMods, &dm->key, dmOld); if(dmOld) { dm->key++; } } while(dmOld); HASH_ADD_INT(me->openMods, key, dm); RW_MUTEX_UNLOCK_WRITE(me->mut); *handle = dm->key; bail: if(tmp) { free(tmp); tmp = NULL; } if(nErr != AEE_SUCCESS) { VERIFY_EPRINTF("Error %x: modtable open from static failed.\n", nErr); } if(nErr && dm) { if(dm->h64) { (void)open_mod_handle_close(dm, dm->h64); } free(dm); dm = NULL; } return nErr; } static int open_mod_table_open(struct open_mod_table* me, const char* uri, remote_handle* handle, char* dlerr, int dlerrorLen, int* pdlErr) { int nErr = AEE_SUCCESS, dlErr = 0; if(pdlErr) { *pdlErr = 0; } if(0 != open_mod_table_open_static_override(me, uri, handle)) { VERIFY(AEE_SUCCESS == (nErr = open_mod_table_open_dynamic(me, uri, handle, dlerr, dlerrorLen, &dlErr))); if(dlErr != 0) { FARF(HIGH, "dynammic open failed, trying static"); if(0 != open_mod_table_open_static(me, uri, handle)) { if(pdlErr) { *pdlErr = dlErr; } } } } bail: FARF(HIGH, "done open for %s rv %d handle: %p", uri, nErr, *handle); if(nErr != AEE_SUCCESS) { VERIFY_EPRINTF("Error %x: open modtable failed\n", nErr); } return nErr; } static void open_mod_close(struct open_mod_table *me, struct open_mod* dm) { RW_MUTEX_LOCK_WRITE(me->mut); dm->refs--; if(dm->refs <= 0) { HASH_DEL(me->openMods,dm); } else { dm = 0; } RW_MUTEX_UNLOCK_WRITE(me->mut); if(dm) { if(dm->h64) { (void)open_mod_handle_close(dm, dm->h64); } if(dm->dlhandle) { DLCLOSE(dm->dlhandle); } free(dm); dm = NULL; } } static int open_mod_table_close(struct open_mod_table* me, remote_handle64 handle, char* errStr, int errStrLen, int* pdlErr) { int nErr = AEE_SUCCESS; struct open_mod *dm, *del = 0;; int dlErr = 0; // First ensure that the handle is valid RW_MUTEX_LOCK_WRITE(me->mut); HASH_FIND_INT(me->openMods, &handle, dm); if(dm) { dm->refs--; if(dm->refs <= 0) { del = dm; FARF(HIGH, "deleting %s %p", del->uri, del); HASH_DEL(me->openMods,dm); } else { FARF(HIGH, "leaked %s", dm->uri); dm = 0; } } RW_MUTEX_UNLOCK_WRITE(me->mut); if(del) { if(del->h64) { (void)open_mod_handle_close(dm, dm->h64); } if(del->dlhandle) { dlErr = DLCLOSE(del->dlhandle); } FARF(HIGH, "free %s %p", del->uri, del); free(del); del = NULL; } VERIFY(del); bail: if(dlErr) { const char* error = DLERROR(); nErr = dlErr; if(error != 0){ std_strlcpy(errStr,error,errStrLen); } VERIFY_EPRINTF("Error %x: open modtable close failed. dlerr %s\n", nErr, error); } if(pdlErr) { *pdlErr = dlErr; } return nErr; } static struct open_mod* open_mod_table_get_open(struct open_mod_table* me, remote_handle handle) { struct open_mod* om = 0; RW_MUTEX_LOCK_READ(me->mut); HASH_FIND_INT(me->openMods, &handle, om); if(0 != om) { om->refs++; } RW_MUTEX_UNLOCK_READ(me->mut); return om; } static struct const_mod* open_mod_table_get_const(struct open_mod_table* me, remote_handle handle) { struct const_mod* cm = 0; RW_MUTEX_LOCK_READ(me->smt->mut); HASH_FIND_INT(me->smt->constMods, &handle, cm); RW_MUTEX_UNLOCK_READ(me->smt->mut); return cm; } static int open_mod_table_handle_invoke(struct open_mod_table* me, remote_handle handle, uint32 sc, remote_arg* pra) { int nErr = AEE_SUCCESS; struct open_mod* om = 0; struct const_mod* cm = 0; remote_handle64 h = 0; invoke_fn invoke = 0; handle_invoke_fn handle_invoke = 0; cm = open_mod_table_get_const(me, handle); if(cm) { invoke = cm->invoke; handle_invoke = cm->handle_invoke; h = cm->h64; } else { VERIFYC(0 != (om = open_mod_table_get_open(me, handle)), AEE_ENOSUCHMOD); invoke = om->invoke; handle_invoke = om->handle_invoke; h = om->h64; } if(invoke) { VERIFY(AEE_SUCCESS == (nErr = invoke(sc, pra))); } else { VERIFY(AEE_SUCCESS == (nErr = handle_invoke(h, sc, pra))); } bail: if(om) { open_mod_close(me, om); } FARF(HIGH, "invoke rv %p %x %x", handle, sc, nErr); return nErr; } struct mod_table { struct static_mod_table smt; struct open_mod_table omt; }; // mod_table object static struct static_mod_table static_mod_table_obj; /** * register a static component for invocations * this can be called at any time including from a static constructor * * overrides will be tried first, then dynamic modules, then regular * static modules. * * name, name of the interface to register * pfn, function pointer to the skel invoke function * * for example: * __attribute__((constructor)) static void my_module_ctor(void) { * mod_table_register_static("my_module", my_module_skel_invoke); * } * */ int mod_table_register_static_override(const char* name, int(*pfn)(uint32 sc, remote_arg* pra)) { if(0 == static_mod_table_ctor(&static_mod_table_obj)) { return static_mod_table_register_static_override(&static_mod_table_obj, name, pfn); } return AEE_EUNKNOWN; } int mod_table_register_static_override1(const char* name, int(*pfn)(remote_handle64, uint32 sc, remote_arg* pra)) { if(0 == static_mod_table_ctor(&static_mod_table_obj)) { return static_mod_table_register_static_override1(&static_mod_table_obj, name, pfn); } return AEE_EUNKNOWN; } /** * register a static component for invocations * this can be called at any time including from a static constructor * * name, name of the interface to register * pfn, function pointer to the skel invoke function * * for example: * __attribute__((constructor)) static void my_module_ctor(void) { * mod_table_register_static("my_module", my_module_skel_invoke); * } * */ int mod_table_register_static(const char* name, int(*pfn)(uint32 sc, remote_arg* pra)) { if(0 == static_mod_table_ctor(&static_mod_table_obj)) { return static_mod_table_register_static(&static_mod_table_obj, name, pfn); } return AEE_EUNKNOWN; } int mod_table_register_static1(const char* name, int(*pfn)(remote_handle64, uint32 sc, remote_arg* pra)) { if(0 == static_mod_table_ctor(&static_mod_table_obj)) { return static_mod_table_register_static1(&static_mod_table_obj, name, pfn); } return AEE_EUNKNOWN; } /** * Open a module and get a handle to it * * uri, name of module to open * handle, Output handle * dlerr, Error String (if an error occurs) * dlerrorLen, Length of error String (if an error occurs) * pdlErr, Error identifier */ int mod_table_open(const char* uri, remote_handle* handle, char* dlerr, int dlerrorLen, int* pdlErr) { int nErr = AEE_SUCCESS; struct open_mod_table* pomt = 0; FARF(HIGH, "mod_table_open for %s", uri); VERIFY(AEE_SUCCESS == (nErr = HAP_pls_add_lookup((uintptr_t)open_mod_table_ctor_imp, 0, sizeof(*pomt), open_mod_table_ctor_imp, (void*)&static_mod_table_obj, open_mod_table_dtor_imp, (void**)&pomt))); VERIFY(AEE_SUCCESS == (nErr = open_mod_table_open(pomt,uri,handle,dlerr,dlerrorLen,pdlErr))); bail: FARF(HIGH, "mod_table_open for %s nErr: %x", uri, nErr); if(nErr != AEE_SUCCESS) { VERIFY_EPRINTF("Error %x: modtable open failed\n", nErr); } return nErr; } /** * invoke a handle in the mod table * * handle, handle to invoke * sc, scalars, see remote.h for documentation. * pra, args, see remote.h for documentation. */ int mod_table_invoke(remote_handle handle, uint32 sc, remote_arg* pra) { int nErr = AEE_SUCCESS; struct open_mod_table* pomt = 0; VERIFY(AEE_SUCCESS == (nErr = HAP_pls_add_lookup((uintptr_t)open_mod_table_ctor_imp, 0, sizeof(*pomt), open_mod_table_ctor_imp, (void*)&static_mod_table_obj, open_mod_table_dtor_imp, (void**)&pomt))); VERIFY(AEE_SUCCESS == (nErr = open_mod_table_handle_invoke(pomt, handle, sc, pra))); bail: return nErr; } /** * Closes a handle in the mod table * * handle, handle to close * errStr, Error String (if an error occurs) * errStrLen, Length of error String (if an error occurs) * pdlErr, Error identifier */ int mod_table_close(remote_handle handle, char* errStr, int errStrLen, int* pdlErr) { int nErr = AEE_SUCCESS; struct open_mod_table* pomt = 0; VERIFY(AEE_SUCCESS == (nErr = HAP_pls_lookup((uintptr_t)open_mod_table_ctor_imp, 0, (void**)&pomt))); VERIFY(AEE_SUCCESS == (nErr = open_mod_table_close(pomt, handle, errStr,errStrLen,pdlErr))); bail: if(nErr != AEE_SUCCESS) { VERIFY_EPRINTF("Error %x: modtable close failed\n", nErr); } return nErr; } /** * internal use only */ int mod_table_register_const_handle(remote_handle remote, const char* uri, int(*pfn)(uint32 sc, remote_arg* pra)) { if(0 == static_mod_table_ctor(&static_mod_table_obj)) { return static_mod_table_register_const_handle(&static_mod_table_obj, remote, 0, uri, pfn, 0); } return AEE_EUNKNOWN; } int mod_table_register_const_handle1(remote_handle remote, remote_handle64 local, const char* uri, int(*pfn)(remote_handle64, uint32 sc, remote_arg* pra)) { if(0 == static_mod_table_ctor(&static_mod_table_obj)) { return static_mod_table_register_const_handle(&static_mod_table_obj, remote, local, uri, 0, pfn); } return AEE_EUNKNOWN; } // Constructor and destructor static int mod_table_ctor(void) { return static_mod_table_ctor(&static_mod_table_obj); } static void mod_table_dtor(void) { static_mod_table_dtor_imp(&static_mod_table_obj); return; } PL_DEFINE(mod_table, mod_table_ctor, mod_table_dtor);