diff --git a/include/nuttx/module.h b/include/nuttx/module.h index fe144825ca..b55eef7bd9 100644 --- a/include/nuttx/module.h +++ b/include/nuttx/module.h @@ -205,12 +205,14 @@ void mod_setsymtab(FAR const struct symtab_s *symtab, int nsymbols); * it has been loaded. * * Returned Value: - * Zero (OK) on success. On any failure, -1 (ERROR) is returned the - * errno value is set appropriately. + * A non-NULL module handle that can be used on subsequent calls to other + * module interfaces is returned on success. If insmod() was unable to + * load the module insmod() will return a NULL handle and the errno + * variable will be set appropriately. * ****************************************************************************/ -int insmod(FAR const char *filename, FAR const char *modulename); +FAR void *insmod(FAR const char *filename, FAR const char *modulename); /**************************************************************************** * Name: rmmod @@ -219,9 +221,7 @@ int insmod(FAR const char *filename, FAR const char *modulename); * Remove a previously installed module from memory. * * Input Parameters: - * - * modulename - The module name. This is the name module name that was - * provided to insmod when the module was loaded. + * handle - The module handler previously returned by insmod(). * * Returned Value: * Zero (OK) on success. On any failure, -1 (ERROR) is returned the @@ -229,7 +229,55 @@ int insmod(FAR const char *filename, FAR const char *modulename); * ****************************************************************************/ -int rmmod(FAR const char *modulename); +int rmmod(FAR void *handle); + +/**************************************************************************** + * Name: modsym + * + * Description: + * modsym() returns the address of a symbol defined within the object that + * was previously made accessible through a insmod() call. handle is the + * value returned from a call to insmod() (and which has not since been + * released via a call to rmmod()), name is the symbol's name as a + * character string. + * + * The returned symbol address will remain valid until rmmod() is called. + * + * Input Parameters: + * handle - The opaque, non-NULL value returned by a previous successful + * call to insmod(). + * name - A pointer to the symbol name string. + * + * Returned Value: + * The address associated with the symbol is returned on success. + * If handle does not refer to a valid module opened by insmod(), or if + * the named symbol cannot be found within any of the objects associated + * with handle, modsym() will return NULL and the errno variable will be + * set appropriately. + * + ****************************************************************************/ + +FAR const void *modsym(FAR void *handle, FAR const char *name); + +/**************************************************************************** + * Name: modhandle + * + * Description: + * modhandle() returns the module handle for the installed module with the + * provided name. A secondary use of this function is to determin if a + * module has been loaded or not. + * + * Input Parameters: + * name - A pointer to the module name string. + * + * Returned Value: + * The non-NULL module handle previously returned by insmod() is returned + * on success. If no module with that name is installed, modhandle() will + * return a NULL handle and the errno variable will be set appropriately. + * + ****************************************************************************/ + +FAR void *modhandle(FAR const char *name); /**************************************************************************** * Name: mod_registry_foreach diff --git a/include/sys/syscall.h b/include/sys/syscall.h index 8da2d8f968..1286bcbec9 100644 --- a/include/sys/syscall.h +++ b/include/sys/syscall.h @@ -182,7 +182,9 @@ #ifdef CONFIG_MODULE # define SYS_insmod __SYS_insmod # define SYS_rmmod (__SYS_insmod+1) -# define __SYS_posix_spawn (__SYS_insmod+2) +# define SYS_modsym (__SYS_insmod+2) +# define SYS_modhandle (__SYS_insmod+3) +# define __SYS_posix_spawn (__SYS_insmod+4) #else # define __SYS_posix_spawn __SYS_insmod #endif diff --git a/sched/module/Make.defs b/sched/module/Make.defs index 00f8467560..9aaa1a7e16 100644 --- a/sched/module/Make.defs +++ b/sched/module/Make.defs @@ -41,9 +41,9 @@ CSRCS += mod_insmod.c mod_rmmod.c # loadable module library -CSRCS += mod_bind.c mod_init.c mod_iobuffer.c mod_load.c mod_read.c -CSRCS += mod_registry.c mod_sections.c mod_symbols.c mod_symtab.c -CSRCS += mod_uninit.c mod_unload.c mod_verify.c +CSRCS += mod_bind.c mod_init.c mod_iobuffer.c mod_load.c mod_modhandle.c +CSRCS += mod_modsym.c mod_read.c mod_registry.c mod_sections.c mod_symbols.c +CSRCS += mod_symtab.c mod_uninit.c mod_unload.c mod_verify.c # procfs support diff --git a/sched/module/mod_insmod.c b/sched/module/mod_insmod.c index bda9d4dd2d..9fe5e71e28 100644 --- a/sched/module/mod_insmod.c +++ b/sched/module/mod_insmod.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/module/mod_insmod.c * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -43,8 +43,9 @@ #include #include #include -#include +#include #include +#include #include #include @@ -178,12 +179,14 @@ static void mod_dumpinitializer(mod_initializer_t initializer, * it has been loaded. * * Returned Value: - * Zero (OK) on success. On any failure, -1 (ERROR) is returned the - * errno value is set appropriately. + * A non-NULL module handle that can be used on subsequent calls to other + * module interfaces is returned on success. If insmod() was unable to + * load the module insmod() will return a NULL handle and the errno + * variable will be set appropriately. * ****************************************************************************/ -int insmod(FAR const char *filename, FAR const char *modulename) +FAR void *insmod(FAR const char *filename, FAR const char *modulename) { struct mod_loadinfo_s loadinfo; FAR struct module_s *modp; @@ -248,7 +251,7 @@ int insmod(FAR const char *filename, FAR const char *modulename) goto errout_with_load; } - /* Return the load information */ + /* Save the load information */ modp->alloc = (FAR void *)loadinfo.textalloc; #if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) @@ -279,7 +282,7 @@ int insmod(FAR const char *filename, FAR const char *modulename) mod_uninitialize(&loadinfo); mod_registry_unlock(); - return OK; + return (FAR void *)modp; errout_with_load: mod_unload(&loadinfo); @@ -290,7 +293,7 @@ errout_with_loadinfo: errout_with_lock: mod_registry_unlock(); set_errno(-ret); - return ERROR; + return NULL; } #endif /* CONFIG_MODULE */ diff --git a/sched/module/mod_modhandle.c b/sched/module/mod_modhandle.c new file mode 100644 index 0000000000..0fc27ea4b9 --- /dev/null +++ b/sched/module/mod_modhandle.c @@ -0,0 +1,97 @@ +/**************************************************************************** + * sched/module/mod_modhandle.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name NuttX 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "module/module.h" + +#ifdef CONFIG_MODULE + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modhandle + * + * Description: + * modhandle() returns the module handle for the installed module with the + * provided name. A secondary use of this function is to determin if a + * module has been loaded or not. + * + * Input Parameters: + * name - A pointer to the module name string. + * + * Returned Value: + * The non-NULL module handle previously returned by insmod() is returned + * on success. If no module with that name is installed, modhandle() will + * return a NULL handle and the errno variable will be set appropriately. + * + ****************************************************************************/ + +FAR void *modhandle(FAR const char *name) +{ + FAR struct module_s *modp; + + DEBUGASSERT(name != NULL); + + /* Get exclusive access to the module registry */ + + mod_registry_lock(); + + /* Find the module entry for this name in the registry */ + + modp = mod_registry_find(name); + if (modp == NULL) + { + serr("ERROR: Failed to find module %s: %d\n", name, ret); + set_errno(ENOENT); + } + + mod_registry_unlock(); + return (FAR void *)modp; +} + +#endif /* CONFIG_MODULE */ diff --git a/sched/module/mod_modsym.c b/sched/module/mod_modsym.c new file mode 100644 index 0000000000..fa27e21692 --- /dev/null +++ b/sched/module/mod_modsym.c @@ -0,0 +1,130 @@ +/**************************************************************************** + * sched/module/mod_modsym.c + * + * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name NuttX 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "module.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modsym + * + * Description: + * modsym() returns the address of a symbol defined within the object that + * was previously made accessible through a insmod() call. handle is the + * value returned from a call to insmod() (and which has not since been + * released via a call to rmmod()), name is the symbol's name as a + * character string. + * + * The returned symbol address will remain valid until rmmod() is called. + * + * Input Parameters: + * handle - The opaque, non-NULL value returned by a previous successful + * call to insmod(). + * name - A pointer to the symbol name string. + * + * Returned Value: + * The address associated with the symbol is returned on success. + * If handle does not refer to a valid module opened by insmod(), or if + * the named symbol cannot be found within any of the objects associated + * with handle, modsym() will return NULL and the errno variable will be + * set appropriately. + * + * NOTE: This means that the address zero can never be a valid return + * value. + * + ****************************************************************************/ + +FAR const void *modsym(FAR void *handle, FAR const char *name) +{ + FAR struct module_s *modp = (FAR struct module_s *)handle; + FAR const struct symtab_s *symbol; + int err; + int ret; + + /* Verify that the module is in the registry */ + + ret = mod_registry_verify(modp); + if (ret < 0) + { + serr("ERROR: Failed to verify module: %d\n", ret); + err = -ret; + goto errout_with_lock; + } + + /* Does the module have a symbol table? */ + + if (modp->modinfo.exports == NULL || modp->modinfo.nexports == 0) + { + serr("ERROR: Module has no symbol table\n"); + err = ENOENT; + goto errout_with_lock; + } + + /* Search the symbol table for the matching symbol */ + + symbol = symtab_findbyname(modp->modinfo.exports, name, + modp->modinfo.nexports); + if (symbol == NULL) + { + serr("ERROR: Failed to find symbol in symbol \"$s\" in table\n", name); + err = ENOENT; + goto errout_with_lock; + } + + /* Return the address within the module assoicated with the symbol */ + + mod_registry_unlock(); + DEBUGASSERT(symbol->sym_value != NULL); + return symbol->sym_value; + +errout_with_lock: + mod_registry_unlock(); + set_errno(err); + return NULL; +} diff --git a/sched/module/mod_procfs.c b/sched/module/mod_procfs.c index 68285fd5fb..8d42f8cad2 100644 --- a/sched/module/mod_procfs.c +++ b/sched/module/mod_procfs.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/module/mod_procfs.c * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without diff --git a/sched/module/mod_registry.c b/sched/module/mod_registry.c index 93a022e8bd..961addcca7 100644 --- a/sched/module/mod_registry.c +++ b/sched/module/mod_registry.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/module/mod_registry.c * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -199,6 +199,40 @@ FAR struct module_s *mod_registry_find(FAR const char *modulename) return modp; } +/**************************************************************************** + * Name: mod_registry_verify + * + * Description: + * Verify that a module handle is valid by traversing the module list and + * assuring that the module still resides in the list. If it does not, + * the handle is probably a stale pointer. + * + * Input Parameters: + * modp - The registry entry to be verified. + * + * Returned Value: + * Returns OK is the module is valid; -ENOENT otherwise. + * + * Assumptions: + * The caller holds the lock on the module registry. + * + ****************************************************************************/ + +int mod_registry_verify(FAR struct module_s *modp) +{ + FAR struct module_s *node; + + for (node = g_mod_registry; node != NULL; node = node->flink) + { + if (node == modp) + { + return OK; + } + } + + return -ENOENT; +} + /**************************************************************************** * Name: mod_registry_foreach * diff --git a/sched/module/mod_rmmod.c b/sched/module/mod_rmmod.c index e0ccad7744..561e9c82f9 100644 --- a/sched/module/mod_rmmod.c +++ b/sched/module/mod_rmmod.c @@ -1,7 +1,7 @@ /**************************************************************************** - * sched/module/module.c + * sched/module/mod_rmmod.c * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -40,8 +40,7 @@ #include #include -#include -#include +#include #include #include @@ -62,9 +61,7 @@ * Remove a previously installed module from memory. * * Input Parameters: - * - * modulename - The module name. This is the name module name that was - * provided to insmod when the module was loaded. + * handle - The module handler previously returned by insmod(). * * Returned Value: * Zero (OK) on success. On any failure, -1 (ERROR) is returned the @@ -72,24 +69,23 @@ * ****************************************************************************/ -int rmmod(FAR const char *modulename) +int rmmod(FAR void *handle) { - FAR struct module_s *modp; - int ret = OK; + FAR struct module_s *modp = (FAR struct module_s *)handle; + int ret; - DEBUGASSERT(modulename != NULL); + DEBUGASSERT(modp != NULL); /* Get exclusive access to the module registry */ mod_registry_lock(); - /* Find the module entry for this modulename in the registry */ + /* Verify that the module is in the registry */ - modp = mod_registry_find(modulename); - if (modp == NULL) + ret = mod_registry_verify(modp); + if (ret < 0) { - serr("ERROR: Failed to find module %s: %d\n", modulename, ret); - ret = -ENOENT; + serr("ERROR: Failed to verify module: %d\n", ret); goto errout_with_lock; } diff --git a/sched/module/module.h b/sched/module/module.h index b64b9b3bd7..344acbf43e 100644 --- a/sched/module/module.h +++ b/sched/module/module.h @@ -443,4 +443,25 @@ int mod_registry_del(FAR struct module_s *modp); FAR struct module_s *mod_registry_find(FAR const char *modulename); +/**************************************************************************** + * Name: mod_registry_verify + * + * Description: + * Verify that a module handle is valid by traversing the module list and + * assuring that the module still resides in the list. If it does not, + * the handle is probably a stale pointer. + * + * Input Parameters: + * modp - The registry entry to be verified. + * + * Returned Value: + * Returns OK is the module is valid; -ENOENT otherwise. + * + * Assumptions: + * The caller holds the lock on the module registry. + * + ****************************************************************************/ + +int mod_registry_verify(FAR struct module_s *modp); + #endif /* __SCHED_MODULE_MODULE_H */ diff --git a/syscall/syscall.csv b/syscall/syscall.csv index 4dbcc98227..d2d97d828d 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -29,7 +29,7 @@ "getenv","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","FAR char*","FAR const char*" "getpid","unistd.h","","pid_t" "getsockopt","sys/socket.h","CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET)","int","int","int","int","FAR void*","FAR socklen_t*" -"insmod","nuttx/module.h","defined(CONFIG_MODULE)","int","FAR const char *","FAR const char *" +"insmod","nuttx/module.h","defined(CONFIG_MODULE)","FAR void *","FAR const char *","FAR const char *" "ioctl","sys/ioctl.h","!defined(CONFIG_LIBC_IOCTL_VARIADIC) && (CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0)","int","int","int","unsigned long" "kill","signal.h","!defined(CONFIG_DISABLE_SIGNALS)","int","pid_t","int" "listen","sys/socket.h","CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET)","int","int","int" @@ -37,6 +37,8 @@ "mkdir","sys/stat.h","CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT)","int","FAR const char*","mode_t" "mkfifo2","nuttx/drivers/drivers.h","defined(CONFIG_PIPES) && CONFIG_DEV_FIFO_SIZE > 0","int","FAR const char*","mode_t","size_t" "mmap","sys/mman.h","CONFIG_NFILE_DESCRIPTORS > 0","FAR void*","FAR void*","size_t","int","int","int","off_t" +"modhandle","nuttx/module.h","defined(CONFIG_MODULE)","FAR void *","FAR const char *" +"modsym","nuttx/module.h","defined(CONFIG_MODULE)","FAR void *","FAR void *","FAR const char *" "mount","sys/mount.h","CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT) && defined(CONFIG_FS_READABLE)","int","const char*","const char*","const char*","unsigned long","const void*" "mq_close","mqueue.h","!defined(CONFIG_DISABLE_MQUEUE)","int","mqd_t" "mq_getattr","mqueue.h","!defined(CONFIG_DISABLE_MQUEUE)","int","mqd_t","struct mq_attr *" @@ -102,7 +104,7 @@ "rename","stdio.h","CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT)","int","FAR const char*","FAR const char*" "rewinddir","dirent.h","CONFIG_NFILE_DESCRIPTORS > 0","void","FAR DIR*" "rmdir","unistd.h","CONFIG_NFILE_DESCRIPTORS > 0 && !defined(CONFIG_DISABLE_MOUNTPOINT)","int","FAR const char*" -"rmmod","nuttx/module.h","defined(CONFIG_MODULE)","int","FAR const char *" +"rmmod","nuttx/module.h","defined(CONFIG_MODULE)","int","FAR void *" "sched_getparam","sched.h","","int","pid_t","struct sched_param*" "sched_getscheduler","sched.h","","int","pid_t" "sched_getstreams","nuttx/sched.h","CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_NFILE_STREAMS > 0","FAR struct streamlist*" diff --git a/syscall/syscall_lookup.h b/syscall/syscall_lookup.h index 25807590d8..d064bdd93f 100644 --- a/syscall/syscall_lookup.h +++ b/syscall/syscall_lookup.h @@ -1,7 +1,7 @@ /**************************************************************************** * syscall/syscall_lookup.h * - * Copyright (C) 2011, 2013-2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2011, 2013-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -123,6 +123,8 @@ SYSCALL_LOOKUP(up_assert, 2, STUB_up_assert) #ifdef CONFIG_MODULE SYSCALL_LOOKUP(insmod, 2, STUB_insmod) SYSCALL_LOOKUP(rmmod, 1, STUB_rmmod) + SYSCALL_LOOKUP(modsym, 2, STUB_modsym) + SYSCALL_LOOKUP(modhandle, 1, STUB_modhandle) #endif /* The following can only be defined if we are configured to execute diff --git a/syscall/syscall_stublookup.c b/syscall/syscall_stublookup.c index fda336d5aa..fcb7d2dbfb 100644 --- a/syscall/syscall_stublookup.c +++ b/syscall/syscall_stublookup.c @@ -122,6 +122,8 @@ uintptr_t STUB_waitid(int nbr, uintptr_t parm1, uintptr_t parm2, #ifdef CONFIG_MODULE uintptr_t STUB_insmod(int nbr, uintptr_t parm1, uintptr_t parm2); uintptr_t STUB_rmmod(int nbr, uintptr_t parm1); +uintptr_t STUB_modsym(int nbr, uintptr_t parm1); +uintptr_t STUB_modhandle(int nbr, uintptr_t parm1, uintptr_t parm2); #endif /* The following can only be defined if we are configured to execute