diff --git a/binfmt/binfmt_unloadmodule.c b/binfmt/binfmt_unloadmodule.c index bc5effded8fd7..131452343f222 100644 --- a/binfmt/binfmt_unloadmodule.c +++ b/binfmt/binfmt_unloadmodule.c @@ -168,19 +168,20 @@ int unload_module(FAR struct binary_s *binp) if (up_textheap_heapmember(binp->sectalloc[i])) { up_textheap_free(binp->sectalloc[i]); - continue; } + else # endif # ifdef CONFIG_ARCH_USE_DATA_HEAP if (up_dataheap_heapmember(binp->sectalloc[i])) { up_dataheap_free(binp->sectalloc[i]); - continue; } + else # endif - - kumm_free(binp->sectalloc[i]); + { + kumm_free(binp->sectalloc[i]); + } } binp->alloc[0] = NULL; diff --git a/binfmt/libelf/libelf_load.c b/binfmt/libelf/libelf_load.c index a3d1b0d1c7e99..1ffade84e27ad 100644 --- a/binfmt/libelf/libelf_load.c +++ b/binfmt/libelf/libelf_load.c @@ -270,15 +270,6 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) { FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; - /* SHF_ALLOC indicates that the section requires memory during - * execution. - */ - - if ((shdr->sh_flags & SHF_ALLOC) == 0) - { - continue; - } - #ifdef CONFIG_ARCH_USE_SEPARATED_SECTION if (loadinfo->ehdr.e_type == ET_REL) { diff --git a/include/nuttx/lib/modlib.h b/include/nuttx/lib/modlib.h index cb6f5a178a2e8..e198b2c1c22fa 100644 --- a/include/nuttx/lib/modlib.h +++ b/include/nuttx/lib/modlib.h @@ -196,7 +196,7 @@ struct mod_loadinfo_s */ #ifdef CONFIG_ARCH_USE_SEPARATED_SECTION - uintptr_t *sectalloc; /* All sections memory allocated when ELF file was loaded */ + FAR uintptr_t *sectalloc; /* All sections memory allocated when ELF file was loaded */ #endif uintptr_t textalloc; /* .text memory allocated when module was loaded */ @@ -563,4 +563,106 @@ int modlib_registry_foreach(mod_callback_t callback, FAR void *arg); void modlib_freesymtab(FAR struct module_s *modp); +/**************************************************************************** + * Name: modlib_insert + * + * Description: + * Verify that the file is an ELF module binary and, if so, load the + * module into kernel memory and initialize it for use. + * + * NOTE: modlib_setsymtab() had to have been called in board-specific OS + * logic prior to calling this function from application logic (perhaps via + * boardctl(BOARDIOC_OS_SYMTAB). Otherwise, insmod will be unable to + * resolve symbols in the OS module. + * + * Input Parameters: + * + * filename - Full path to the module binary to be loaded + * modname - The name that can be used to refer to the module after + * it has been loaded. + * + * Returned Value: + * A non-NULL module handle that can be used on subsequent calls to other + * module interfaces is returned on success. If modlib_insert() was + * unable to load the module modlib_insert() will return a NULL handle + * and the errno variable will be set appropriately. + * + ****************************************************************************/ + +FAR void *modlib_insert(FAR const char *filename, FAR const char *modname); + +/**************************************************************************** + * Name: modlib_getsymbol + * + * Description: + * modlib_getsymbol() returns the address of a symbol defined within the + * object that was previously made accessible through a modlib_getsymbol() + * call. handle is the value returned from a call to modlib_insert() (and + * which has not since been released via a call to modlib_remove()), + * name is the symbol's name as a character string. + * + * The returned symbol address will remain valid until modlib_remove() is + * called. + * + * Input Parameters: + * handle - The opaque, non-NULL value returned by a previous successful + * call to modlib_insert(). + * 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 modlib_insert(), + * or if the named modlib_symbol cannot be found within any of the objects + * associated with handle, modlib_getsymbol() 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 *modlib_getsymbol(FAR void *handle, FAR const char *name); + +/**************************************************************************** + * Name: modlib_remove + * + * Description: + * Remove a previously installed module from memory. + * + * Input Parameters: + * handle - The module handler previously returned by modlib_insert(). + * + * Returned Value: + * Zero (OK) on success. On any failure, -1 (ERROR) is returned the + * errno value is set appropriately. + * + ****************************************************************************/ + +int modlib_remove(FAR void *handle); + +/**************************************************************************** + * Name: modlib_modhandle + * + * Description: + * modlib_modhandle() returns the module handle for the installed + * module with the provided name. A secondary use of this function is to + * determine 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 modlib_insert() is + * returned on success. If no module with that name is installed, + * modlib_modhandle() will return a NULL handle and the errno variable + * will be set appropriately. + * + ****************************************************************************/ + +#ifdef HAVE_MODLIB_NAMES +FAR void *modlib_gethandle(FAR const char *name); +#else +# define modlib_gethandle(n) NULL +#endif + #endif /* __INCLUDE_NUTTX_LIB_MODLIB_H */ diff --git a/libs/libc/dlfcn/lib_dlclose.c b/libs/libc/dlfcn/lib_dlclose.c index e50055ea71daf..aff1a7bf9a6ea 100644 --- a/libs/libc/dlfcn/lib_dlclose.c +++ b/libs/libc/dlfcn/lib_dlclose.c @@ -25,211 +25,13 @@ #include #include -#include -#include -#include -#include #include -#include "libc.h" - /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: dlremove - * - * Description: - * Remove a previously installed shared library from memory. - * - * Input Parameters: - * handle - The shared library handle previously returned by dlopen(). - * - * Returned Value: - * Zero (OK) on success. On any failure, -1 (ERROR) is returned the - * errno value is set appropriately. - * - ****************************************************************************/ - -#ifdef CONFIG_BUILD_PROTECTED -static inline int dlremove(FAR void *handle) -{ - FAR struct module_s *modp = (FAR struct module_s *)handle; - void (**array)(void); - int ret; - int i; - - DEBUGASSERT(modp != NULL); - - /* Get exclusive access to the module registry */ - - modlib_registry_lock(); - - /* Verify that the module is in the registry */ - - ret = modlib_registry_verify(modp); - if (ret < 0) - { - serr("ERROR: Failed to verify module: %d\n", ret); - goto errout_with_lock; - } - -#if CONFIG_MODLIB_MAXDEPEND > 0 - /* Refuse to remove any module that other modules may depend upon. */ - - if (modp->dependents > 0) - { - serr("ERROR: Module has dependents: %d\n", modp->dependents); - ret = -EBUSY; - goto errout_with_lock; - } -#endif - - /* Is there an uninitializer? */ - - if (modp->modinfo.uninitializer != NULL) - { - /* Try to uninitialize the module */ - - ret = modp->modinfo.uninitializer(modp->modinfo.arg); - - /* Did the module successfully uninitialize? */ - - if (ret < 0) - { - serr("ERROR: Failed to uninitialize the module: %d\n", ret); - goto errout_with_lock; - } - - /* Nullify so that the uninitializer cannot be called again */ - - modp->modinfo.uninitializer = NULL; - - /* Call any .fini_array entries in reverse order */ - - array = (void (**)(void))modp->finiarr; - for (i = (modp->nfini - 1); i >= 0; i--) - { - array[i](); - } - -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->initializer = NULL; - modp->modinfo.arg = NULL; - modp->modinfo.exports = NULL; - modp->modinfo.nexports = 0; -#endif - } - - /* Release resources held by the module */ - - /* Dynamic shared objects have text and data allocated in one - * operation to keep the relative positions between the two - * areas relative otherwise references to the GOT will fail - */ - - if (!modp->dynamic) - { -#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION - int i; - - for (i = 0; i < modp->nsect && modp->sectalloc[i] != NULL; i++) - { -# ifdef CONFIG_ARCH_USE_TEXT_HEAP - if (up_textheap_heapmember(modp->sectalloc[i])) - { - up_textheap_free(modp->sectalloc[i]); - continue; - } -# endif - -# ifdef CONFIG_ARCH_USE_DATA_HEAP - if (up_dataheap_heapmember(modp->sectalloc[i])) - { - up_dataheap_free(modp->sectalloc[i]); - continue; - } -# endif - - lib_free(modp->sectalloc[i]); - } - - lib_free(modp->sectalloc); - modp->sectalloc = NULL; - modp->nsect = 0; -#else - if (modp->textalloc != NULL) - { - /* Free the module memory */ - -#if defined(CONFIG_ARCH_USE_TEXT_HEAP) - up_textheap_free((FAR void *)modp->textalloc); -#else - lib_free((FAR void *)modp->textalloc); -#endif - } - - if (modp->dataalloc != NULL) - { - /* Free the module memory */ - -#if defined(CONFIG_ARCH_USE_DATA_HEAP) - up_dataheap_free((FAR void *)modp->dataalloc); -#else - lib_free((FAR void *)modp->dataalloc); -#endif - } -#endif - } - else - { - lib_free((FAR void *)modp->textalloc); - } - - /* Nullify so that the memory cannot be freed again */ - - modp->textalloc = NULL; - modp->dataalloc = NULL; -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->textsize = 0; - modp->datasize = 0; -#endif - - /* Free the modules exported symmbols table */ - - modlib_freesymtab(modp); - - /* Remove the module from the registry */ - - ret = modlib_registry_del(modp); - if (ret < 0) - { - serr("ERROR: Failed to remove the module from the registry: %d\n", - ret); - goto errout_with_lock; - } - -#if CONFIG_MODLIB_MAXDEPEND > 0 - /* Eliminate any dependencies that this module has on other modules */ - - modlib_undepend(modp); -#endif - modlib_registry_unlock(); - - /* And free the registry entry */ - - lib_free(modp); - return OK; - -errout_with_lock: - modlib_registry_unlock(); - set_errno(-ret); - return ERROR; -} -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -277,15 +79,11 @@ static inline int dlremove(FAR void *handle) int dlclose(FAR void *handle) { -#if defined(CONFIG_BUILD_FLAT) +#if defined(CONFIG_BUILD_FLAT) || defined(CONFIG_BUILD_PROTECTED) /* In the FLAT build, a shared library is essentially the same as a kernel * module. - */ - - return rmmod(handle); - -#elif defined(CONFIG_BUILD_PROTECTED) - /* The PROTECTED build is equivalent to the FLAT build EXCEPT that there + * + * The PROTECTED build is equivalent to the FLAT build EXCEPT that there * must be two copies of the module logic: One residing in kernel * space and using the kernel symbol table and one residing in user space * using the user space symbol table. @@ -293,7 +91,7 @@ int dlclose(FAR void *handle) * dlremove() is essentially a clone of rmmod(). */ - return dlremove(handle); + return modlib_remove(handle); #else /* if defined(CONFIG_BUILD_KERNEL) */ /* The KERNEL build is considerably more complex: In order to be shared, diff --git a/libs/libc/dlfcn/lib_dlopen.c b/libs/libc/dlfcn/lib_dlopen.c index 89e4874d6db45..b0fbc3db650f7 100644 --- a/libs/libc/dlfcn/lib_dlopen.c +++ b/libs/libc/dlfcn/lib_dlopen.c @@ -24,129 +24,17 @@ #include -#include -#include #include #include -#include -#include -#include -#include -#include #include -#include #include - -#include "libc.h" -#include "debug.h" +#include /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: dldump_loadinfo - ****************************************************************************/ - -#ifdef CONFIG_BUILD_PROTECTED -# if defined(CONFIG_DEBUG_INFO) && defined(CONFIG_DEBUG_BINFMT) -static void dldump_loadinfo(FAR struct mod_loadinfo_s *loadinfo) -{ - int i; - - binfo("LOAD_INFO:\n"); - binfo(" textalloc: %08lx\n", (long)loadinfo->textalloc); - binfo(" datastart: %08lx\n", (long)loadinfo->datastart); - binfo(" textsize: %ld\n", (long)loadinfo->textsize); - binfo(" datasize: %ld\n", (long)loadinfo->datasize); - binfo(" filelen: %ld\n", (long)loadinfo->filelen); - binfo(" filfd: %d\n", loadinfo->filfd); - binfo(" symtabidx: %d\n", loadinfo->symtabidx); - binfo(" strtabidx: %d\n", loadinfo->strtabidx); - - binfo("ELF Header:\n"); - binfo(" e_ident: %02x %02x %02x %02x\n", - loadinfo->ehdr.e_ident[0], loadinfo->ehdr.e_ident[1], - loadinfo->ehdr.e_ident[2], loadinfo->ehdr.e_ident[3]); - binfo(" e_type: %04x\n", loadinfo->ehdr.e_type); - binfo(" e_machine: %04x\n", loadinfo->ehdr.e_machine); - binfo(" e_version: %08x\n", loadinfo->ehdr.e_version); - binfo(" e_entry: %08lx\n", (long)loadinfo->ehdr.e_entry); - binfo(" e_phoff: %d\n", loadinfo->ehdr.e_phoff); - binfo(" e_shoff: %d\n", loadinfo->ehdr.e_shoff); - binfo(" e_flags: %08x\n" , loadinfo->ehdr.e_flags); - binfo(" e_ehsize: %d\n", loadinfo->ehdr.e_ehsize); - binfo(" e_phentsize: %d\n", loadinfo->ehdr.e_phentsize); - binfo(" e_phnum: %d\n", loadinfo->ehdr.e_phnum); - binfo(" e_shentsize: %d\n", loadinfo->ehdr.e_shentsize); - binfo(" e_shnum: %d\n", loadinfo->ehdr.e_shnum); - binfo(" e_shstrndx: %d\n", loadinfo->ehdr.e_shstrndx); - - if (loadinfo->shdr && loadinfo->ehdr.e_shnum > 0) - { - for (i = 0; i < loadinfo->ehdr.e_shnum; i++) - { - FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; - binfo("Sections %d:\n", i); -# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION - if (loadinfo->ehdr.e_type == ET_REL) - { - binfo(" sh_alloc: %08jx\n", - (uintmax_t)loadinfo->sectalloc[i]); - } -# endif - - binfo(" sh_name: %08x\n", shdr->sh_name); - binfo(" sh_type: %08x\n", shdr->sh_type); - binfo(" sh_flags: %08x\n", shdr->sh_flags); - binfo(" sh_addr: %08x\n", shdr->sh_addr); - binfo(" sh_offset: %d\n", shdr->sh_offset); - binfo(" sh_size: %d\n", shdr->sh_size); - binfo(" sh_link: %d\n", shdr->sh_link); - binfo(" sh_info: %d\n", shdr->sh_info); - binfo(" sh_addralign: %d\n", shdr->sh_addralign); - binfo(" sh_entsize: %d\n", shdr->sh_entsize); - } - } - - if (loadinfo->phdr && loadinfo->ehdr.e_phnum > 0) - { - for (i = 0; i < loadinfo->ehdr.e_phnum; i++) - { - FAR Elf32_Phdr *phdr = &loadinfo->phdr[i]; - binfo("Program Header %d:\n", i); - binfo(" p_type: %08x\n", phdr->p_type); - binfo(" p_offset: %08x\n", phdr->p_offset); - binfo(" p_vaddr: %08x\n", phdr->p_vaddr); - binfo(" p_paddr: %08x\n", phdr->p_paddr); - binfo(" p_filesz: %08x\n", phdr->p_filesz); - binfo(" p_memsz: %08x\n", phdr->p_memsz); - binfo(" p_flags: %08x\n", phdr->p_flags); - binfo(" p_align: %08x\n", phdr->p_align); - } - } -} -# else -# define dldump_loadinfo(i) -# endif -#endif - -/**************************************************************************** - * Name: dldump_initializer - ****************************************************************************/ - -#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MODLIB_DUMPBUFFER) -static void dldump_initializer(mod_initializer_t initializer, - FAR struct mod_loadinfo_s *loadinfo) -{ - modlib_dumpbuffer("Initializer code", (FAR const uint8_t *)initializer, - MIN(loadinfo->textsize - loadinfo->ehdr.e_entry, 512)); -} -#else -# define dldump_initializer(b,l) -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -173,148 +61,7 @@ static void dldump_initializer(mod_initializer_t initializer, * ****************************************************************************/ -#ifdef CONFIG_BUILD_PROTECTED -/* The PROTECTED build is equivalent to the FLAT build EXCEPT that there - * must be two copies of the module logic: One residing in kernel - * space and using the kernel symbol table and one residing in user space - * using the user space symbol table. - * - * dlinsert() is essentially a clone of insmod(). - */ - -static inline FAR void *dlinsert(FAR const char *filename) -{ - struct mod_loadinfo_s loadinfo; - FAR struct module_s *modp; - mod_initializer_t initializer; - void (**array)(void); - int ret; - int i; - - binfo("Loading file: %s\n", filename); - - /* Get exclusive access to the module registry */ - - modlib_registry_lock(); - - /* Initialize the ELF library to load the program binary. */ - - ret = modlib_initialize(filename, &loadinfo); - dldump_loadinfo(&loadinfo); - if (ret != 0) - { - serr("ERROR: Failed to initialize to load module: %d\n", ret); - goto errout_with_loadinfo; - } - - /* Allocate a module registry entry to hold the module data */ - - modp = (FAR struct module_s *)lib_zalloc(sizeof(struct module_s)); - if (modp == NULL) - { - ret = -ENOMEM; - binfo("Failed to initialize for load of ELF program: %d\n", ret); - goto errout_with_loadinfo; - } - - /* Load the program binary */ - - ret = modlib_load(&loadinfo); - dldump_loadinfo(&loadinfo); - if (ret != 0) - { - binfo("Failed to load ELF program binary: %d\n", ret); - goto errout_with_registry_entry; - } - - /* Bind the program to the kernel symbol table */ - - ret = modlib_bind(modp, &loadinfo); - if (ret != 0) - { - binfo("Failed to bind symbols program binary: %d\n", ret); - goto errout_with_load; - } - - /* Save the load information */ - -#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION - modp->sectalloc = (FAR void *)loadinfo.sectalloc; - modp->nsect = loadinfo.ehdr.e_shnum; -#endif - - modp->textalloc = (FAR void *)loadinfo.textalloc; - modp->dataalloc = (FAR void *)loadinfo.datastart; - modp->dynamic = (loadinfo.ehdr.e_type == ET_DYN); -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->textsize = loadinfo.textsize; - modp->datasize = loadinfo.datasize; -#endif - - /* Get the module initializer entry point */ - - initializer = (mod_initializer_t)(loadinfo.textalloc + - loadinfo.ehdr.e_entry); -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->initializer = initializer; -#endif - dldump_initializer(initializer, &loadinfo); - - /* Call the module initializer */ - - switch (loadinfo.ehdr.e_type) - { - case ET_REL : - ret = initializer(&modp->modinfo); - if (ret < 0) - { - binfo("Failed to initialize the module: %d\n", ret); - goto errout_with_load; - } - break; - case ET_DYN : - - /* Process any preinit_array entries */ - - array = (void (**)(void)) loadinfo.preiarr; - for (i = 0; i < loadinfo.nprei; i++) - { - array[i](); - } - - /* Process any init_array entries */ - - array = (void (**)(void)) loadinfo.initarr; - for (i = 0; i < loadinfo.ninit; i++) - { - array[i](); - } - - modp->finiarr = loadinfo.finiarr; - modp->nfini = loadinfo.nfini; - break; - } - - /* Add the new module entry to the registry */ - - modlib_registry_add(modp); - - modlib_uninitialize(&loadinfo); - modlib_registry_unlock(); - return modp; - -errout_with_load: - modlib_unload(&loadinfo); - modlib_undepend(modp); -errout_with_registry_entry: - lib_free(modp); -errout_with_loadinfo: - modlib_uninitialize(&loadinfo); - modlib_registry_unlock(); - set_errno(-ret); - return NULL; -} -#elif defined(CONFIG_BUILD_FLAT) +#if defined(CONFIG_BUILD_FLAT) || defined(CONFIG_BUILD_PROTECTED) /* In the FLAT build, a shared library is essentially the same as a kernel * module. * @@ -322,6 +69,13 @@ static inline FAR void *dlinsert(FAR const char *filename) * - No automatic binding of symbols * - No dependencies * - mode is ignored. + * + * The PROTECTED build is equivalent to the FLAT build EXCEPT that there + * must be two copies of the module logic: One residing in kernel + * space and using the kernel symbol table and one residing in user space + * using the user space symbol table. + * + * dlinsert() is essentially a clone of insmod(). */ static inline FAR void *dlinsert(FAR const char *filename) @@ -341,7 +95,7 @@ static inline FAR void *dlinsert(FAR const char *filename) * name. */ - handle = insmod(filename, basename(name)); + handle = modlib_insert(filename, basename(name)); lib_free(name); return handle; } diff --git a/libs/libc/dlfcn/lib_dlsym.c b/libs/libc/dlfcn/lib_dlsym.c index 66fa6af077ebc..5308e6c699cf8 100644 --- a/libs/libc/dlfcn/lib_dlsym.c +++ b/libs/libc/dlfcn/lib_dlsym.c @@ -25,87 +25,13 @@ #include #include -#include -#include -#include -#include -#include #include /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: dlgetsym - * - * Description: - * dlgetsym() implements dlsym() for the PROTECTED build. - * - * 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: - * See dlsym(). - * - ****************************************************************************/ - -#ifdef CONFIG_BUILD_PROTECTED -static inline FAR const void *dlgetsym(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 */ - - modlib_registry_lock(); - ret = modlib_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 associated with the symbol */ - - modlib_registry_unlock(); - DEBUGASSERT(symbol->sym_value != NULL); - return symbol->sym_value; - -errout_with_lock: - modlib_registry_unlock(); - set_errno(err); - return NULL; -} -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -143,15 +69,11 @@ static inline FAR const void *dlgetsym(FAR void *handle, FAR void *dlsym(FAR void *handle, FAR const char *name) { -#if defined(CONFIG_BUILD_FLAT) +#if defined(CONFIG_BUILD_FLAT) || defined(CONFIG_BUILD_PROTECTED) /* In the FLAT build, a shared library is essentially the same as a kernel * module. - */ - - return (FAR void *)modsym(handle, name); - -#elif defined(CONFIG_BUILD_PROTECTED) - /* The PROTECTED build is equivalent to the FLAT build EXCEPT that there + * + * The PROTECTED build is equivalent to the FLAT build EXCEPT that there * must be two copies of the module logic: One residing in kernel * space and using the kernel symbol table and one residing in user space * using the user space symbol table. @@ -159,7 +81,7 @@ FAR void *dlsym(FAR void *handle, FAR const char *name) * dlgetsem() is essentially a clone of modsym(). */ - return (FAR void *)dlgetsym(handle, name); + return (FAR void *)modlib_getsymbol(handle, name); #else /* if defined(CONFIG_BUILD_KERNEL) */ /* The KERNEL build is considerably more complex: In order to be shared, diff --git a/libs/libc/modlib/CMakeLists.txt b/libs/libc/modlib/CMakeLists.txt index 741f37abf94d3..e1606b6772c0a 100644 --- a/libs/libc/modlib/CMakeLists.txt +++ b/libs/libc/modlib/CMakeLists.txt @@ -36,7 +36,11 @@ if(CONFIG_LIBC_MODLIB) modlib_symtab.c modlib_uninit.c modlib_unload.c - modlib_verify.c) + modlib_verify.c + modlib_gethandle.c + modlib_getsymbol.c + modlib_insert.c + modlib_remove.c) list(APPEND SRCS modlib_globals.S) diff --git a/libs/libc/modlib/Make.defs b/libs/libc/modlib/Make.defs index f9cd0a3e335fa..8b6f1d010090b 100644 --- a/libs/libc/modlib/Make.defs +++ b/libs/libc/modlib/Make.defs @@ -26,6 +26,8 @@ CSRCS += modlib_bind.c modlib_depend.c modlib_init.c modlib_iobuffer.c CSRCS += modlib_load.c modlib_loadhdrs.c modlib_verify.c CSRCS += modlib_read.c modlib_registry.c modlib_sections.c CSRCS += modlib_symbols.c modlib_symtab.c modlib_uninit.c modlib_unload.c +CSRCS += modlib_gethandle.c modlib_getsymbol.c modlib_insert.c +CSRCS += modlib_remove.c # Add the modlib directory to the build diff --git a/libs/libc/modlib/modlib_gethandle.c b/libs/libc/modlib/modlib_gethandle.c new file mode 100644 index 0000000000000..ddd7303df35e4 --- /dev/null +++ b/libs/libc/modlib/modlib_gethandle.c @@ -0,0 +1,80 @@ +/**************************************************************************** + * libs/libc/modlib/modlib_gethandle.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modlib_modhandle + * + * Description: + * modlib_modhandle() returns the module handle for the installed + * module with the provided name. A secondary use of this function is to + * determine 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 modlib_insert() is + * returned on success. If no module with that name is installed, + * modlib_modhandle() will return a NULL handle and the errno variable + * will be set appropriately. + * + ****************************************************************************/ + +#ifdef HAVE_MODLIB_NAMES + +FAR void *modlib_gethandle(FAR const char *name) +{ + FAR struct module_s *modp; + + DEBUGASSERT(name != NULL); + + /* Get exclusive access to the module registry */ + + modlib_registry_lock(); + + /* Find the module entry for this name in the registry */ + + modp = modlib_registry_find(name); + if (modp == NULL) + { + berr("ERROR: Failed to find module %s\n", name); + set_errno(ENOENT); + } + + modlib_registry_unlock(); + return modp; +} + +#endif /* HAVE_MODLIB_NAMES */ diff --git a/libs/libc/modlib/modlib_getsymbol.c b/libs/libc/modlib/modlib_getsymbol.c new file mode 100644 index 0000000000000..c73a454a109ba --- /dev/null +++ b/libs/libc/modlib/modlib_getsymbol.c @@ -0,0 +1,116 @@ +/**************************************************************************** + * libs/libc/modlib/modlib_getsymbol.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modlib_getsymbol + * + * Description: + * modlib_getsymbol() returns the address of a symbol defined within the + * object that was previously made accessible through a modlib_getsymbol() + * call. handle is the value returned from a call to modlib_insert() (and + * which has not since been released via a call to modlib_remove()), + * name is the symbol's name as a character string. + * + * The returned symbol address will remain valid until modlib_remove() is + * called. + * + * Input Parameters: + * handle - The opaque, non-NULL value returned by a previous successful + * call to modlib_insert(). + * 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 modlib_insert(), + * or if the named modlib_symbol cannot be found within any of the objects + * associated with handle, modlib_getsymbol() 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 *modlib_getsymbol(FAR void *handle, FAR const char *name) +{ + FAR struct module_s *modp = handle; + FAR const struct symtab_s *symbol; + int err; + int ret; + + /* Verify that the module is in the registry */ + + modlib_registry_lock(); + ret = modlib_registry_verify(modp); + if (ret < 0) + { + berr("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) + { + berr("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); + + modlib_registry_unlock(); + if (symbol == NULL) + { + berr("ERROR: Failed to find symbol in symbol \"%s\" in table\n", name); + set_errno(ENOENT); + return NULL; + } + + /* Return the address within the module associated with the symbol */ + + DEBUGASSERT(symbol->sym_value != NULL); + return symbol->sym_value; + +errout_with_lock: + modlib_registry_unlock(); + set_errno(err); + return NULL; +} diff --git a/libs/libc/modlib/modlib_insert.c b/libs/libc/modlib/modlib_insert.c new file mode 100644 index 0000000000000..ec3098db440c2 --- /dev/null +++ b/libs/libc/modlib/modlib_insert.c @@ -0,0 +1,299 @@ +/**************************************************************************** + * libs/libc/modlib/modlib_insert.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modlib_dumploadinfo + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_BINFMT_INFO +static void modlib_dumploadinfo(FAR struct mod_loadinfo_s *loadinfo) +{ + int i; + + binfo("LOAD_INFO:\n"); + binfo(" textalloc: %08lx\n", (long)loadinfo->textalloc); + binfo(" datastart: %08lx\n", (long)loadinfo->datastart); + binfo(" textsize: %ld\n", (long)loadinfo->textsize); + binfo(" datasize: %ld\n", (long)loadinfo->datasize); + binfo(" textalign: %zu\n", loadinfo->textalign); + binfo(" dataalign: %zu\n", loadinfo->dataalign); + binfo(" filelen: %ld\n", (long)loadinfo->filelen); + binfo(" filfd: %d\n", loadinfo->filfd); + binfo(" symtabidx: %d\n", loadinfo->symtabidx); + binfo(" strtabidx: %d\n", loadinfo->strtabidx); + + binfo("ELF Header:\n"); + binfo(" e_ident: %02x %02x %02x %02x\n", + loadinfo->ehdr.e_ident[0], loadinfo->ehdr.e_ident[1], + loadinfo->ehdr.e_ident[2], loadinfo->ehdr.e_ident[3]); + binfo(" e_type: %04x\n", loadinfo->ehdr.e_type); + binfo(" e_machine: %04x\n", loadinfo->ehdr.e_machine); + binfo(" e_version: %08x\n", loadinfo->ehdr.e_version); + binfo(" e_entry: %08lx\n", (long)loadinfo->ehdr.e_entry); + binfo(" e_phoff: %ju\n", (uintmax_t)loadinfo->ehdr.e_phoff); + binfo(" e_shoff: %ju\n", (uintmax_t)loadinfo->ehdr.e_shoff); + binfo(" e_flags: %08x\n", loadinfo->ehdr.e_flags); + binfo(" e_ehsize: %d\n", loadinfo->ehdr.e_ehsize); + binfo(" e_phentsize: %d\n", loadinfo->ehdr.e_phentsize); + binfo(" e_phnum: %d\n", loadinfo->ehdr.e_phnum); + binfo(" e_shentsize: %d\n", loadinfo->ehdr.e_shentsize); + binfo(" e_shnum: %d\n", loadinfo->ehdr.e_shnum); + binfo(" e_shstrndx: %d\n", loadinfo->ehdr.e_shstrndx); + + if (loadinfo->shdr && loadinfo->ehdr.e_shnum > 0) + { + for (i = 0; i < loadinfo->ehdr.e_shnum; i++) + { + FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; + binfo("Sections %d:\n", i); +# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type == ET_REL) + { + binfo(" sh_alloc: %08jx\n", + (uintmax_t)loadinfo->sectalloc[i]); + } +# endif + + binfo(" sh_name: %08x\n", shdr->sh_name); + binfo(" sh_type: %08x\n", shdr->sh_type); + binfo(" sh_flags: %08jx\n", (uintmax_t)shdr->sh_flags); + binfo(" sh_addr: %08jx\n", (uintmax_t)shdr->sh_addr); + binfo(" sh_offset: %ju\n", (uintmax_t)shdr->sh_offset); + binfo(" sh_size: %ju\n", (uintmax_t)shdr->sh_size); + binfo(" sh_link: %d\n", shdr->sh_link); + binfo(" sh_info: %d\n", shdr->sh_info); + binfo(" sh_addralign: %ju\n", (uintmax_t)shdr->sh_addralign); + binfo(" sh_entsize: %ju\n", (uintmax_t)shdr->sh_entsize); + } + } +} +#else +# define modlib_dumploadinfo(i) +#endif + +/**************************************************************************** + * Name: modlib_dumpinitializer + ****************************************************************************/ + +#ifdef CONFIG_MODLIB_DUMPBUFFER +static void modlib_dumpinitializer(mod_initializer_t initializer, + FAR struct mod_loadinfo_s *loadinfo) +{ + modlib_dumpbuffer("Initializer code", (FAR const uint8_t *)initializer, + MIN(loadinfo->textsize - loadinfo->ehdr.e_entry, 512)); +} +#else +# define modlib_dumpinitializer(b,l) +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modlib_insert + * + * Description: + * Verify that the file is an ELF module binary and, if so, load the + * module into kernel memory and initialize it for use. + * + * NOTE: modlib_setsymtab() had to have been called in board-specific OS + * logic prior to calling this function from application logic (perhaps via + * boardctl(BOARDIOC_OS_SYMTAB). Otherwise, insmod will be unable to + * resolve symbols in the OS module. + * + * Input Parameters: + * + * filename - Full path to the module binary to be loaded + * modname - The name that can be used to refer to the module after + * it has been loaded. + * + * Returned Value: + * A non-NULL module handle that can be used on subsequent calls to other + * module interfaces is returned on success. If modlib_insert() was + * unable to load the module modlib_insert() will return a NULL handle + * and the errno variable will be set appropriately. + * + ****************************************************************************/ + +FAR void *modlib_insert(FAR const char *filename, FAR const char *modname) +{ + struct mod_loadinfo_s loadinfo; + FAR struct module_s *modp; + mod_initializer_t initializer; + FAR void (**array)(void); + int ret; + int i; + + DEBUGASSERT(filename != NULL && modname != NULL); + binfo("Loading file: %s\n", filename); + + /* Get exclusive access to the module registry */ + + modlib_registry_lock(); + + /* Check if this module is already installed */ + +#ifdef HAVE_MODLIB_NAMES + if (modlib_registry_find(modname) != NULL) + { + modlib_registry_unlock(); + set_errno(EEXIST); + return NULL; + } +#endif + + /* Initialize the ELF library to load the program binary. */ + + ret = modlib_initialize(filename, &loadinfo); + modlib_dumploadinfo(&loadinfo); + if (ret != 0) + { + berr("ERROR: Failed to initialize to load module: %d\n", ret); + goto errout_with_loadinfo; + } + + /* Allocate a module registry entry to hold the module data */ + + modp = lib_zalloc(sizeof(struct module_s)); + if (modp == NULL) + { + berr("Failed to allocate struct module_s\n"); + ret = -ENOMEM; + goto errout_with_loadinfo; + } + +#ifdef HAVE_MODLIB_NAMES + /* Save the module name in the registry entry */ + + strlcpy(modp->modname, modname, sizeof(modp->modname)); +#endif + + /* Load the program binary */ + + ret = modlib_load(&loadinfo); + modlib_dumploadinfo(&loadinfo); + if (ret != 0) + { + binfo("Failed to load ELF program binary: %d\n", ret); + goto errout_with_registry_entry; + } + + /* Bind the program to the kernel symbol table */ + + ret = modlib_bind(modp, &loadinfo); + if (ret != 0) + { + binfo("Failed to bind symbols program binary: %d\n", ret); + goto errout_with_load; + } + + /* Save the load information */ + + modp->textalloc = (FAR void *)loadinfo.textalloc; + modp->dataalloc = (FAR void *)loadinfo.datastart; +#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) + modp->textsize = loadinfo.textsize; + modp->datasize = loadinfo.datasize; +#endif + + /* Get the module initializer entry point */ + + initializer = (mod_initializer_t)(loadinfo.textalloc + + loadinfo.ehdr.e_entry); +#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) + modp->initializer = initializer; +#endif + modlib_dumpinitializer(initializer, &loadinfo); + + /* Call the module initializer */ + + switch (loadinfo.ehdr.e_type) + { + case ET_REL : + ret = initializer(&modp->modinfo); + if (ret < 0) + { + binfo("Failed to initialize the module: %d\n", ret); + goto errout_with_load; + } + break; + case ET_DYN : + + /* Process any preinit_array entries */ + + array = (FAR void (**)(void))loadinfo.preiarr; + for (i = 0; i < loadinfo.nprei; i++) + { + array[i](); + } + + /* Process any init_array entries */ + + array = (FAR void (**)(void))loadinfo.initarr; + for (i = 0; i < loadinfo.ninit; i++) + { + array[i](); + } + + modp->finiarr = loadinfo.finiarr; + modp->nfini = loadinfo.nfini; + break; + } + + /* Add the new module entry to the registry */ + + modlib_registry_add(modp); + + modlib_uninitialize(&loadinfo); + modlib_registry_unlock(); + return modp; + +errout_with_load: + modlib_unload(&loadinfo); +#if CONFIG_MODLIB_MAXDEPEND > 0 + modlib_undepend(modp); +#endif +errout_with_registry_entry: + lib_free(modp); +errout_with_loadinfo: + modlib_uninitialize(&loadinfo); + modlib_registry_unlock(); + set_errno(-ret); + return NULL; +} + diff --git a/libs/libc/modlib/modlib_load.c b/libs/libc/modlib/modlib_load.c index 26748ed2ae188..4aaae3a1b9384 100644 --- a/libs/libc/modlib/modlib_load.c +++ b/libs/libc/modlib/modlib_load.c @@ -70,7 +70,7 @@ static int modlib_section_alloc(FAR struct mod_loadinfo_s *loadinfo, /* Allocate memory info for all sections */ loadinfo->sectalloc = lib_zalloc(sizeof(uintptr_t) * - loadinfo->ehdr.e_shnum); + loadinfo->ehdr.e_shnum); if (loadinfo->sectalloc == NULL) { return -ENOMEM; diff --git a/libs/libc/modlib/modlib_remove.c b/libs/libc/modlib/modlib_remove.c new file mode 100644 index 0000000000000..a645c689866de --- /dev/null +++ b/libs/libc/modlib/modlib_remove.c @@ -0,0 +1,203 @@ +/**************************************************************************** + * libs/libc/modlib/modlib_remove.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modlib_remove + * + * Description: + * Remove a previously installed module from memory. + * + * Input Parameters: + * handle - The module handler previously returned by modlib_insert(). + * + * Returned Value: + * Zero (OK) on success. On any failure, -1 (ERROR) is returned the + * errno value is set appropriately. + * + ****************************************************************************/ + +int modlib_remove(FAR void *handle) +{ + FAR struct module_s *modp = (FAR struct module_s *)handle; + int ret; + + DEBUGASSERT(modp != NULL); + + /* Get exclusive access to the module registry */ + + modlib_registry_lock(); + + /* Verify that the module is in the registry */ + + ret = modlib_registry_verify(modp); + if (ret < 0) + { + berr("ERROR: Failed to verify module: %d\n", ret); + goto errout_with_lock; + } + +#if CONFIG_MODLIB_MAXDEPEND > 0 + /* Refuse to remove any module that other modules may depend upon. */ + + if (modp->dependents > 0) + { + berr("ERROR: Module has dependents: %d\n", modp->dependents); + ret = -EBUSY; + goto errout_with_lock; + } +#endif + + /* Is there an uninitializer? */ + + if (modp->modinfo.uninitializer != NULL) + { + /* Try to uninitialize the module */ + + ret = modp->modinfo.uninitializer(modp->modinfo.arg); + + /* Did the module successfully uninitialize? */ + + if (ret < 0) + { + berr("ERROR: Failed to uninitialize the module: %d\n", ret); + goto errout_with_lock; + } + + /* Nullify so that the uninitializer cannot be called again */ + + modp->modinfo.uninitializer = NULL; +#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) + modp->initializer = NULL; + modp->modinfo.arg = NULL; + modp->modinfo.exports = NULL; + modp->modinfo.nexports = 0; +#endif + } + + /* Release resources held by the module */ + + if (modp->textalloc != NULL || modp->dataalloc != NULL) + { + /* Free the module memory and nullify so that the memory cannot + * be freed again + * + * NOTE: For dynamic shared objects there is only a single + * allocation: the text/data were allocated in one operation + */ + + if (!modp->dynamic) + { +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + int i; + + for (i = 0; i < modp->nsect && modp->sectalloc[i] != NULL; i++) + { +# ifdef CONFIG_ARCH_USE_TEXT_HEAP + if (up_textheap_heapmember(modp->sectalloc[i])) + { + up_textheap_free(modp->sectalloc[i]); + continue; + } +# endif + +# ifdef CONFIG_ARCH_USE_DATA_HEAP + if (up_dataheap_heapmember(modp->sectalloc[i])) + { + up_dataheap_free(modp->sectalloc[i]); + continue; + } +# endif + + lib_free(modp->sectalloc[i]); + } + + lib_free(modp->sectalloc); + modp->sectalloc = NULL; + modp->nsect = 0; +#else +# if defined(CONFIG_ARCH_USE_TEXT_HEAP) + up_textheap_free((FAR void *)modp->textalloc); +# else + lib_free((FAR void *)modp->textalloc); +# endif +# if defined(CONFIG_ARCH_USE_DATA_HEAP) + up_dataheap_free((FAR void *)modp->dataalloc); +# else + lib_free((FAR void *)modp->dataalloc); +# endif +#endif + } + else + { + lib_free((FAR void *)modp->textalloc); + } + + modp->textalloc = NULL; + modp->dataalloc = NULL; +#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) + modp->textsize = 0; + modp->datasize = 0; +#endif + } + + /* Remove the module from the registry */ + + ret = modlib_registry_del(modp); + if (ret < 0) + { + berr("ERROR: Failed to remove the module from the registry: %d\n", + ret); + goto errout_with_lock; + } + +#if CONFIG_MODLIB_MAXDEPEND > 0 + /* Eliminate any dependencies that this module has on other modules */ + + modlib_undepend(modp); +#endif + modlib_registry_unlock(); + + /* And free the registry entry */ + + lib_free(modp); + return OK; + +errout_with_lock: + modlib_registry_unlock(); + set_errno(-ret); + return ERROR; +} diff --git a/libs/libc/modlib/modlib_unload.c b/libs/libc/modlib/modlib_unload.c index 12cdb813f4cf2..981e2a8fd1e79 100644 --- a/libs/libc/modlib/modlib_unload.c +++ b/libs/libc/modlib/modlib_unload.c @@ -72,39 +72,40 @@ int modlib_unload(FAR struct mod_loadinfo_s *loadinfo) if (up_textheap_heapmember((FAR void *)loadinfo->sectalloc[i])) { up_textheap_free((FAR void *)loadinfo->sectalloc[i]); - continue; } + else # endif # ifdef CONFIG_ARCH_USE_DATA_HEAP if (up_dataheap_heapmember((FAR void *)loadinfo->sectalloc[i])) { up_dataheap_free((FAR void *)loadinfo->sectalloc[i]); - continue; } + else # endif - - lib_free((FAR void *)loadinfo->sectalloc[i]); + { + lib_free((FAR void *)loadinfo->sectalloc[i]); + } } lib_free(loadinfo->sectalloc); #else if (loadinfo->textalloc != 0) { -#if defined(CONFIG_ARCH_USE_TEXT_HEAP) +# if defined(CONFIG_ARCH_USE_TEXT_HEAP) up_textheap_free((FAR void *)loadinfo->textalloc); -#else +# else lib_free((FAR void *)loadinfo->textalloc); -#endif +# endif } if (loadinfo->datastart != 0) { -#if defined(CONFIG_ARCH_USE_DATA_HEAP) +# if defined(CONFIG_ARCH_USE_DATA_HEAP) up_dataheap_free((FAR void *)loadinfo->datastart); -#else +# else lib_free((FAR void *)loadinfo->datastart); -#endif +# endif } #endif } diff --git a/sched/module/mod_insmod.c b/sched/module/mod_insmod.c index a020089450172..ab17c38ba88d9 100644 --- a/sched/module/mod_insmod.c +++ b/sched/module/mod_insmod.c @@ -26,110 +26,11 @@ #include -#include -#include -#include -#include -#include -#include -#include - -#include -#include #include #include #ifdef CONFIG_MODULE -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: mod_dumploadinfo - ****************************************************************************/ - -#ifdef CONFIG_DEBUG_BINFMT_INFO -static void mod_dumploadinfo(FAR struct mod_loadinfo_s *loadinfo) -{ - int i; - - binfo("LOAD_INFO:\n"); - binfo(" textalloc: %08lx\n", (long)loadinfo->textalloc); - binfo(" datastart: %08lx\n", (long)loadinfo->datastart); - binfo(" textsize: %ld\n", (long)loadinfo->textsize); - binfo(" datasize: %ld\n", (long)loadinfo->datasize); - binfo(" textalign: %zu\n", loadinfo->textalign); - binfo(" dataalign: %zu\n", loadinfo->dataalign); - binfo(" filelen: %ld\n", (long)loadinfo->filelen); - binfo(" filfd: %d\n", loadinfo->filfd); - binfo(" symtabidx: %d\n", loadinfo->symtabidx); - binfo(" strtabidx: %d\n", loadinfo->strtabidx); - - binfo("ELF Header:\n"); - binfo(" e_ident: %02x %02x %02x %02x\n", - loadinfo->ehdr.e_ident[0], loadinfo->ehdr.e_ident[1], - loadinfo->ehdr.e_ident[2], loadinfo->ehdr.e_ident[3]); - binfo(" e_type: %04x\n", loadinfo->ehdr.e_type); - binfo(" e_machine: %04x\n", loadinfo->ehdr.e_machine); - binfo(" e_version: %08x\n", loadinfo->ehdr.e_version); - binfo(" e_entry: %08lx\n", (long)loadinfo->ehdr.e_entry); - binfo(" e_phoff: %ju\n", (uintmax_t)loadinfo->ehdr.e_phoff); - binfo(" e_shoff: %ju\n", (uintmax_t)loadinfo->ehdr.e_shoff); - binfo(" e_flags: %08x\n", loadinfo->ehdr.e_flags); - binfo(" e_ehsize: %d\n", loadinfo->ehdr.e_ehsize); - binfo(" e_phentsize: %d\n", loadinfo->ehdr.e_phentsize); - binfo(" e_phnum: %d\n", loadinfo->ehdr.e_phnum); - binfo(" e_shentsize: %d\n", loadinfo->ehdr.e_shentsize); - binfo(" e_shnum: %d\n", loadinfo->ehdr.e_shnum); - binfo(" e_shstrndx: %d\n", loadinfo->ehdr.e_shstrndx); - - if (loadinfo->shdr && loadinfo->ehdr.e_shnum > 0) - { - for (i = 0; i < loadinfo->ehdr.e_shnum; i++) - { - FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; - binfo("Sections %d:\n", i); -# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION - if (loadinfo->ehdr.e_type == ET_REL) - { - binfo(" sh_alloc: %08jx\n", - (uintmax_t)loadinfo->sectalloc[i]); - } -# endif - - binfo(" sh_name: %08x\n", shdr->sh_name); - binfo(" sh_type: %08x\n", shdr->sh_type); - binfo(" sh_flags: %08jx\n", (uintmax_t)shdr->sh_flags); - binfo(" sh_addr: %08jx\n", (uintmax_t)shdr->sh_addr); - binfo(" sh_offset: %ju\n", (uintmax_t)shdr->sh_offset); - binfo(" sh_size: %ju\n", (uintmax_t)shdr->sh_size); - binfo(" sh_link: %d\n", shdr->sh_link); - binfo(" sh_info: %d\n", shdr->sh_info); - binfo(" sh_addralign: %ju\n", (uintmax_t)shdr->sh_addralign); - binfo(" sh_entsize: %ju\n", (uintmax_t)shdr->sh_entsize); - } - } -} -#else -# define mod_dumploadinfo(i) -#endif - -/**************************************************************************** - * Name: mod_dumpinitializer - ****************************************************************************/ - -#ifdef CONFIG_MODLIB_DUMPBUFFER -static void mod_dumpinitializer(mod_initializer_t initializer, - FAR struct mod_loadinfo_s *loadinfo) -{ - modlib_dumpbuffer("Initializer code", (FAR const uint8_t *)initializer, - MIN(loadinfo->textsize - loadinfo->ehdr.e_entry, 512)); -} -#else -# define mod_dumpinitializer(b,l) -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -162,147 +63,7 @@ static void mod_dumpinitializer(mod_initializer_t initializer, FAR void *insmod(FAR const char *filename, FAR const char *modname) { - struct mod_loadinfo_s loadinfo; - FAR struct module_s *modp; - mod_initializer_t initializer; - FAR void (**array)(void); - int ret; - int i; - - DEBUGASSERT(filename != NULL && modname != NULL); - binfo("Loading file: %s\n", filename); - - /* Get exclusive access to the module registry */ - - modlib_registry_lock(); - - /* Check if this module is already installed */ - - if (modlib_registry_find(modname) != NULL) - { - ret = -EEXIST; - goto errout_with_lock; - } - - /* Initialize the ELF library to load the program binary. */ - - ret = modlib_initialize(filename, &loadinfo); - mod_dumploadinfo(&loadinfo); - if (ret != 0) - { - berr("ERROR: Failed to initialize to load module: %d\n", ret); - goto errout_with_loadinfo; - } - - /* Allocate a module registry entry to hold the module data */ - - modp = kmm_zalloc(sizeof(struct module_s)); - if (modp == NULL) - { - berr("Failed to allocate struct module_s\n"); - ret = -ENOMEM; - goto errout_with_loadinfo; - } - -#ifdef HAVE_MODLIB_NAMES - /* Save the module name in the registry entry */ - - strlcpy(modp->modname, modname, sizeof(modp->modname)); -#endif - - /* Load the program binary */ - - ret = modlib_load(&loadinfo); - mod_dumploadinfo(&loadinfo); - if (ret != 0) - { - binfo("Failed to load ELF program binary: %d\n", ret); - goto errout_with_registry_entry; - } - - /* Bind the program to the kernel symbol table */ - - ret = modlib_bind(modp, &loadinfo); - if (ret != 0) - { - binfo("Failed to bind symbols program binary: %d\n", ret); - goto errout_with_load; - } - - /* Save the load information */ - - modp->textalloc = (FAR void *)loadinfo.textalloc; - modp->dataalloc = (FAR void *)loadinfo.datastart; -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->textsize = loadinfo.textsize; - modp->datasize = loadinfo.datasize; -#endif - - /* Get the module initializer entry point */ - - initializer = (mod_initializer_t)(loadinfo.textalloc + - loadinfo.ehdr.e_entry); -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->initializer = initializer; -#endif - mod_dumpinitializer(initializer, &loadinfo); - - /* Call the module initializer */ - - switch (loadinfo.ehdr.e_type) - { - case ET_REL : - ret = initializer(&modp->modinfo); - if (ret < 0) - { - binfo("Failed to initialize the module: %d\n", ret); - goto errout_with_load; - } - break; - case ET_DYN : - - /* Process any preinit_array entries */ - - array = (FAR void (**)(void))loadinfo.preiarr; - for (i = 0; i < loadinfo.nprei; i++) - { - array[i](); - } - - /* Process any init_array entries */ - - array = (FAR void (**)(void))loadinfo.initarr; - for (i = 0; i < loadinfo.ninit; i++) - { - array[i](); - } - - modp->finiarr = loadinfo.finiarr; - modp->nfini = loadinfo.nfini; - break; - } - - /* Add the new module entry to the registry */ - - modlib_registry_add(modp); - - modlib_uninitialize(&loadinfo); - modlib_registry_unlock(); - return modp; - -errout_with_load: - modlib_unload(&loadinfo); -#if CONFIG_MODLIB_MAXDEPEND > 0 - modlib_undepend(modp); -#endif -errout_with_registry_entry: - kmm_free(modp); -errout_with_loadinfo: - modlib_uninitialize(&loadinfo); -errout_with_lock: - modlib_registry_unlock(); - set_errno(-ret); - return NULL; + return modlib_insert(filename, modname); } #endif /* CONFIG_MODULE */ diff --git a/sched/module/mod_modhandle.c b/sched/module/mod_modhandle.c index 13e7c55133cb8..006593feacd9d 100644 --- a/sched/module/mod_modhandle.c +++ b/sched/module/mod_modhandle.c @@ -26,11 +26,6 @@ #include -#include -#include -#include -#include - #include #include @@ -60,25 +55,7 @@ FAR void *modhandle(FAR const char *name) { - FAR struct module_s *modp; - - DEBUGASSERT(name != NULL); - - /* Get exclusive access to the module registry */ - - modlib_registry_lock(); - - /* Find the module entry for this name in the registry */ - - modp = modlib_registry_find(name); - if (modp == NULL) - { - berr("ERROR: Failed to find module %s\n", name); - set_errno(ENOENT); - } - - modlib_registry_unlock(); - return modp; + return modlib_gethandle(name); } #endif /* CONFIG_MODULE */ diff --git a/sched/module/mod_modsym.c b/sched/module/mod_modsym.c index f5afc7e9dcdd1..3a839a2615329 100644 --- a/sched/module/mod_modsym.c +++ b/sched/module/mod_modsym.c @@ -26,11 +26,6 @@ #include -#include -#include -#include - -#include #include #include @@ -69,50 +64,5 @@ 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 */ - - modlib_registry_lock(); - ret = modlib_registry_verify(modp); - if (ret < 0) - { - berr("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) - { - berr("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) - { - berr("ERROR: Failed to find symbol in symbol \"%s\" in table\n", name); - err = ENOENT; - goto errout_with_lock; - } - - /* Return the address within the module associated with the symbol */ - - modlib_registry_unlock(); - DEBUGASSERT(symbol->sym_value != NULL); - return symbol->sym_value; - -errout_with_lock: - modlib_registry_unlock(); - set_errno(err); - return NULL; + return modlib_getsymbol(handle, name); } diff --git a/sched/module/mod_rmmod.c b/sched/module/mod_rmmod.c index bc1470d456b7f..933ac1a15c11b 100644 --- a/sched/module/mod_rmmod.c +++ b/sched/module/mod_rmmod.c @@ -26,12 +26,6 @@ #include -#include -#include -#include -#include - -#include #include #include @@ -58,154 +52,7 @@ int rmmod(FAR void *handle) { - FAR struct module_s *modp = (FAR struct module_s *)handle; - int ret; - - DEBUGASSERT(modp != NULL); - - /* Get exclusive access to the module registry */ - - modlib_registry_lock(); - - /* Verify that the module is in the registry */ - - ret = modlib_registry_verify(modp); - if (ret < 0) - { - berr("ERROR: Failed to verify module: %d\n", ret); - goto errout_with_lock; - } - -#if CONFIG_MODLIB_MAXDEPEND > 0 - /* Refuse to remove any module that other modules may depend upon. */ - - if (modp->dependents > 0) - { - berr("ERROR: Module has dependents: %d\n", modp->dependents); - ret = -EBUSY; - goto errout_with_lock; - } -#endif - - /* Is there an uninitializer? */ - - if (modp->modinfo.uninitializer != NULL) - { - /* Try to uninitialize the module */ - - ret = modp->modinfo.uninitializer(modp->modinfo.arg); - - /* Did the module successfully uninitialize? */ - - if (ret < 0) - { - berr("ERROR: Failed to uninitialize the module: %d\n", ret); - goto errout_with_lock; - } - - /* Nullify so that the uninitializer cannot be called again */ - - modp->modinfo.uninitializer = NULL; -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->initializer = NULL; - modp->modinfo.arg = NULL; - modp->modinfo.exports = NULL; - modp->modinfo.nexports = 0; -#endif - } - - /* Release resources held by the module */ - - if (modp->textalloc != NULL || modp->dataalloc != NULL) - { - /* Free the module memory and nullify so that the memory cannot - * be freed again - * - * NOTE: For dynamic shared objects there is only a single - * allocation: the text/data were allocated in one operation - */ - - if (!modp->dynamic) - { -#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION - int i; - - for (i = 0; i < modp->nsect && modp->sectalloc[i] != NULL; i++) - { -# ifdef CONFIG_ARCH_USE_TEXT_HEAP - if (up_textheap_heapmember(modp->sectalloc[i])) - { - up_textheap_free(modp->sectalloc[i]); - continue; - } -# endif - -# ifdef CONFIG_ARCH_USE_DATA_HEAP - if (up_dataheap_heapmember(modp->sectalloc[i])) - { - up_dataheap_free(modp->sectalloc[i]); - continue; - } -# endif - - kmm_free(modp->sectalloc[i]); - } - - kmm_free(modp->sectalloc); - modp->sectalloc = NULL; - modp->nsect = 0; -#else -# if defined(CONFIG_ARCH_USE_TEXT_HEAP) - up_textheap_free((FAR void *)modp->textalloc); -# else - kmm_free((FAR void *)modp->textalloc); -# endif -# if defined(CONFIG_ARCH_USE_DATA_HEAP) - up_dataheap_free((FAR void *)modp->dataalloc); -# else - kmm_free((FAR void *)modp->dataalloc); -# endif -#endif - } - else - { - kmm_free((FAR void *)modp->textalloc); - } - - modp->textalloc = NULL; - modp->dataalloc = NULL; -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->textsize = 0; - modp->datasize = 0; -#endif - } - - /* Remove the module from the registry */ - - ret = modlib_registry_del(modp); - if (ret < 0) - { - berr("ERROR: Failed to remove the module from the registry: %d\n", - ret); - goto errout_with_lock; - } - -#if CONFIG_MODLIB_MAXDEPEND > 0 - /* Eliminate any dependencies that this module has on other modules */ - - modlib_undepend(modp); -#endif - modlib_registry_unlock(); - - /* And free the registry entry */ - - kmm_free(modp); - return OK; - -errout_with_lock: - modlib_registry_unlock(); - set_errno(-ret); - return ERROR; + return modlib_remove(handle); } #endif /* CONFIG_MODULE */