modlib/dlfcn:unify same code
Signed-off-by: anjiahao <anjiahao@xiaomi.com>
This commit is contained in:
parent
fc1aefbeb3
commit
29e4e71167
18 changed files with 860 additions and 1052 deletions
|
|
@ -162,29 +162,30 @@ int unload_module(FAR struct binary_s *binp)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION
|
||||
for (i = 0; binp->sectalloc[i] != NULL && i < binp->nsect; i++)
|
||||
{
|
||||
# ifdef CONFIG_ARCH_USE_TEXT_HEAP
|
||||
if (up_textheap_heapmember(binp->sectalloc[i]))
|
||||
for (i = 0; binp->sectalloc[i] != NULL && i < binp->nsect; i++)
|
||||
{
|
||||
up_textheap_free(binp->sectalloc[i]);
|
||||
continue;
|
||||
}
|
||||
# ifdef CONFIG_ARCH_USE_TEXT_HEAP
|
||||
if (up_textheap_heapmember(binp->sectalloc[i]))
|
||||
{
|
||||
up_textheap_free(binp->sectalloc[i]);
|
||||
}
|
||||
else
|
||||
# endif
|
||||
|
||||
# ifdef CONFIG_ARCH_USE_DATA_HEAP
|
||||
if (up_dataheap_heapmember(binp->sectalloc[i]))
|
||||
{
|
||||
up_dataheap_free(binp->sectalloc[i]);
|
||||
continue;
|
||||
}
|
||||
if (up_dataheap_heapmember(binp->sectalloc[i]))
|
||||
{
|
||||
up_dataheap_free(binp->sectalloc[i]);
|
||||
}
|
||||
else
|
||||
# endif
|
||||
{
|
||||
kumm_free(binp->sectalloc[i]);
|
||||
}
|
||||
}
|
||||
|
||||
kumm_free(binp->sectalloc[i]);
|
||||
}
|
||||
|
||||
binp->alloc[0] = NULL;
|
||||
binp->alloc[1] = NULL;
|
||||
binp->alloc[0] = NULL;
|
||||
binp->alloc[1] = NULL;
|
||||
#endif
|
||||
|
||||
/* Free allocated address spaces */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -25,211 +25,13 @@
|
|||
#include <nuttx/config.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/module.h>
|
||||
#include <nuttx/lib/modlib.h>
|
||||
|
||||
#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 @@ errout_with_lock:
|
|||
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -24,129 +24,17 @@
|
|||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <dlfcn.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <nuttx/envpath.h>
|
||||
#include <nuttx/module.h>
|
||||
#include <nuttx/lib/modlib.h>
|
||||
|
||||
#include "libc.h"
|
||||
#include "debug.h"
|
||||
#include <nuttx/lib/lib.h>
|
||||
|
||||
/****************************************************************************
|
||||
* 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 @@ errout_with_loadinfo:
|
|||
* - 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,87 +25,13 @@
|
|||
#include <nuttx/config.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/symtab.h>
|
||||
#include <nuttx/module.h>
|
||||
#include <nuttx/lib/modlib.h>
|
||||
|
||||
/****************************************************************************
|
||||
* 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 @@ errout_with_lock:
|
|||
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
80
libs/libc/modlib/modlib_gethandle.c
Normal file
80
libs/libc/modlib/modlib_gethandle.c
Normal file
|
|
@ -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 <nuttx/config.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/lib/modlib.h>
|
||||
|
||||
/****************************************************************************
|
||||
* 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 */
|
||||
116
libs/libc/modlib/modlib_getsymbol.c
Normal file
116
libs/libc/modlib/modlib_getsymbol.c
Normal file
|
|
@ -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 <nuttx/config.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/lib/modlib.h>
|
||||
#include <nuttx/symtab.h>
|
||||
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
||||
299
libs/libc/modlib/modlib_insert.c
Normal file
299
libs/libc/modlib/modlib_insert.c
Normal file
|
|
@ -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 <nuttx/config.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <nuttx/lib/lib.h>
|
||||
#include <nuttx/lib/modlib.h>
|
||||
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
203
libs/libc/modlib/modlib_remove.c
Normal file
203
libs/libc/modlib/modlib_remove.c
Normal file
|
|
@ -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 <nuttx/config.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/lib/lib.h>
|
||||
#include <nuttx/lib/modlib.h>
|
||||
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,110 +26,11 @@
|
|||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/module.h>
|
||||
#include <nuttx/lib/modlib.h>
|
||||
|
||||
#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 */
|
||||
|
|
|
|||
|
|
@ -26,11 +26,6 @@
|
|||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/module.h>
|
||||
#include <nuttx/lib/modlib.h>
|
||||
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -26,11 +26,6 @@
|
|||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/symtab.h>
|
||||
#include <nuttx/module.h>
|
||||
#include <nuttx/lib/modlib.h>
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,12 +26,6 @@
|
|||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/module.h>
|
||||
#include <nuttx/lib/modlib.h>
|
||||
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue