diff options
-rw-r--r-- | main.c | 3 | ||||
-rw-r--r-- | rap-shell.c | 106 | ||||
-rw-r--r-- | rap-shell.h | 14 | ||||
-rw-r--r-- | rap.c | 473 | ||||
-rw-r--r-- | rap.h | 115 | ||||
-rw-r--r-- | rtl-find-file.c | 7 | ||||
-rw-r--r-- | rtl-obj.c | 4 | ||||
-rw-r--r-- | shell-init | 3 | ||||
-rw-r--r-- | wscript | 2 |
9 files changed, 720 insertions, 7 deletions
@@ -47,6 +47,7 @@ int remote_debug; #endif +#include <rap-shell.h> #include <rtl-shell.h> #include <rtl-trace.h> @@ -429,6 +430,8 @@ main (int argc, char* argv[]) "fderase driver", shell_flash_erase); rtems_shell_add_cmd ("rtl", "misc", "Runtime Linker", rtems_rtl_shell_command); + rtems_shell_add_cmd ("rap", "misc", + "Application loader", shell_rap); rtems_shell_add_cmd ("dlo", "misc", "load object file", shell_dlopen); rtems_shell_add_cmd ("dlc", "misc", diff --git a/rap-shell.c b/rap-shell.c new file mode 100644 index 0000000..3d5cf2c --- /dev/null +++ b/rap-shell.c @@ -0,0 +1,106 @@ +/* + * COPYRIGHT (c) 2013 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rtld + * + * @brief RTEMS Application Loader. + * + * Shell command wrappers for the RTEMS Application loader. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <rap.h> +#include <rap-shell.h> + +static void +shell_rap_command_help (void) +{ + printf ("usage: rap [cmd] [arg]\n" \ + "Commands and options:\n" \ + "ls: List the loaded applications (also list)\n" \ + "ld: Load an application (also load)\n" \ + "un: Unload an application (also unload)\n"); +} + +static void +shell_rap_get_error (const char* what) +{ + char message[64]; + int error; + error = rtems_rap_get_error (message, sizeof (message)); + printf ("error: %s: (%d) %s\n", what, error, message); +} + +static bool +shell_rap_list_handler (void* handle) +{ + printf (" %-10p %-10p %-s\n", + handle, rtems_rap_dl_handle (handle), rtems_rap_name (handle)); + return true; +} + +static int +shell_rap_list (int argc, char* argv[]) +{ + printf (" App DL Handle Name\n"); + return rtems_rap_iterate (shell_rap_list_handler) ? 0 : 1; +} + +static int +shell_rap_load (int argc, char* argv[]) +{ + int r = 0; + if (argc == 0) + { + printf ("error: no application name\n"); + return 0; + } + if (rtems_rap_load (argv[0], 0, argc - 1, (const char**) (argv + 1))) + printf ("%s loaded\n", argv[0]); + else + { + r = 1; + shell_rap_get_error ("loading"); + } + return r; +} + +int +shell_rap (int argc, char* argv[]) +{ + if (argc == 1) + { + shell_rap_command_help (); + return 0; + } + + if ((strcmp (argv[1], "ls") == 0) || + (strcmp (argv[1], "list") == 0)) + { + return shell_rap_list (argc - 2, argv + 2); + } + else if ((strcmp (argv[1], "ld") == 0) || + (strcmp (argv[1], "load") == 0)) + { + return shell_rap_load (argc - 2, argv + 2); + } + + printf ("error: invalid command: %s\n", argv[1]); + return 0; +} + diff --git a/rap-shell.h b/rap-shell.h new file mode 100644 index 0000000..c32529d --- /dev/null +++ b/rap-shell.h @@ -0,0 +1,14 @@ +/* + * COPYRIGHT (c) 2013 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#if !defined(_RAP_SHELL_H_) +#define _RAP_SHELL_H_ + +int shell_rap (int argc, char* argv[]); + +#endif @@ -0,0 +1,473 @@ +/* + * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rap + * + * @brief RTEMS Application Loader + * + * This is the RAP implementation. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <rtems/libio_.h> + +#include <dlfcn.h> +#include <rap.h> +#include <rtl.h> + +#include "rtl-find-file.h" + +/** + * The global RAP data. This structure is allocated on the heap when the first + * call to location an application and is never released. + */ +typedef struct rtems_rap_data_s +{ + rtems_id lock; /**< The RAP lock id */ + rtems_chain_control apps; /**< List if loaded application. */ + int last_errno; /**< Last error number. */ + char last_error[64]; /**< Last error string. */ +} rtems_rap_data_t; + +/** + * The RAP file data. This structure is allocated on the heap when a file is + * loaded. + */ +typedef struct rtems_rap_app_s +{ + rtems_chain_node node; /**< The node's link in the chain. */ + const char* name; /**< The file name */ + void* handle; /**< The dlopen handle. */ +} rtems_rap_app_t; + +/** + * Semaphore configuration to create a mutex. + */ +#define RTEMS_MUTEX_ATTRIBS \ + (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \ + RTEMS_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL) + +/** + * Static RAP data is returned to the user when the loader is locked. + */ +static rtems_rap_data_t rap_; + +/** + * Verbose level for the RAP loader. + */ +static bool rap_verbose; + +/** + * RAP entry call signature. + */ +typedef int (*rtems_rap_entry_t)(int argc, const char* argv[]); + +/** + * Forward decl. + */ +static bool rtems_rap_unlock (void); + +static bool +rtems_rap_data_init (void) +{ + /* + * Lock the RAP. We only create a lock if a call is made. First we test if a + * lock is present. If one is present we lock it. If not the libio lock is + * locked and we then test the lock again. If not present we create the lock + * then release libio lock. + */ + if (!rap_.lock) + { + rtems_libio_lock (); + + if (!rap_.lock) + { + rtems_status_code sc; + rtems_id lock; + + /* + * Create the RAP lock. + */ + sc = rtems_semaphore_create (rtems_build_name ('R', 'A', 'P', '_'), + 1, RTEMS_MUTEX_ATTRIBS, + RTEMS_NO_PRIORITY, &lock); + if (sc != RTEMS_SUCCESSFUL) + return false; + + sc = rtems_semaphore_obtain (lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + { + rtems_semaphore_delete (lock); + return false; + } + + rap_.lock = lock; + + /* + * Initialise the objects list and create any required services. + */ + rtems_chain_initialize_empty (&rap_.apps); + } + + rtems_libio_unlock (); + + rtems_rap_unlock (); + } + return true; +} + +static rtems_rap_data_t* +rtems_rap_lock (void) +{ + rtems_status_code sc; + + if (!rtems_rap_data_init ()) + return NULL; + + sc = rtems_semaphore_obtain (rap_.lock, + RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + { + errno = EINVAL; + return NULL; + } + + return &rap_; +} + +static bool +rtems_rap_unlock (void) +{ + /* + * Not sure any error should be returned or an assert. + */ + rtems_status_code sc; + sc = rtems_semaphore_release (rap_.lock); + if ((sc != RTEMS_SUCCESSFUL) && (errno == 0)) + { + errno = EINVAL; + return false; + } + return true; +} + +static rtems_rap_app_t* +rtems_rap_check_handle (void* handle) +{ + rtems_rap_app_t* app; + rtems_chain_node* node; + + app = handle; + node = rtems_chain_first (&rap_.apps); + + while (!rtems_chain_is_tail (&rap_.apps, node)) + { + rtems_rap_app_t* check = (rtems_rap_app_t*) node; + if (check == app) + return app; + node = rtems_chain_next (node); + } + + return NULL; +} + +static rtems_rap_app_t* +rtems_rap_app_alloc (void) +{ + rtems_rap_app_t* app = malloc (sizeof (rtems_rap_app_t)); + memset (app, 0, sizeof (rtems_rap_app_t)); + rtems_chain_append (&rap_.apps, &app->node); + return app; +} + +static void +rtems_rap_app_free (rtems_rap_app_t* app) +{ + if (app->handle) + { + dlclose (app->handle); + app->handle = NULL; + } + + if (!rtems_chain_is_node_off_chain (&app->node)) + rtems_chain_extract (&app->node); +} + +static bool +rtems_rap_match_name (rtems_rap_app_t* app, const char* name) +{ + const char* a; + + /* + * Assume the app name is absolute, ie points to the file on disk. This means + * there is at least one delimiter in the name. + */ + + if (strncmp (app->name, name, strlen (name)) == 0) + return true; + + a = app->name + strlen (app->name) - 1; + + while (a >= app->name) + { + if (rtems_filesystem_is_delimiter (*a)) + { + const char* n = name; + + ++a; + + while (*a && *n) + { + if (*a == '.') + { + if (*n == '\0') + return true; + } + + ++a; + ++n; + } + + return false; + } + + --a; + } + + return false; +} + +static void +rtems_rap_get_rtl_error (void) +{ + rap_.last_errno = + rtems_rtl_get_error (rap_.last_error, sizeof (rap_.last_error)); +} + +static void +rtems_rap_set_error (int error, const char* format, ...) +{ + rtems_rap_data_t* rap = rtems_rap_lock (); + va_list ap; + va_start (ap, format); + rap->last_errno = error; + vsnprintf (rap->last_error, sizeof (rap->last_error), format, ap); + rtems_rap_unlock (); + va_end (ap); +} + +bool +rtems_rap_load (const char* name, int mode, int argc, const char* argv[]) +{ + rtems_rap_data_t* rap = rtems_rap_lock (); + + if (!rap) + return false; + + if (rap_verbose) + printf ("rap: loading '%s'\n", name); + + /* + * See if the app has already been loaded. + */ + if (!rtems_rap_find (name)) + { + rtems_rap_app_t* app; + rtems_rap_entry_t init; + rtems_rap_entry_t fini; + uint32_t size = 0; + int r; + + /* + * Allocate a new application descriptor and attempt to load it. + */ + app = rtems_rap_app_alloc (); + if (app == NULL) + { + rtems_rap_set_error (ENOMEM, "no memory for application"); + rtems_rap_unlock (); + return false; + } + + /* + * Find the file in the file system using the search path. + */ + if (!rtems_rtl_find_file (name, getenv ("PATH"), &app->name, &size)) + { + rtems_rap_set_error (ENOENT, "file not found"); + rtems_rap_app_free (app); + rtems_rap_unlock (); + return false; + } + + app->handle = dlopen (app->name, RTLD_NOW | mode); + if (!app->handle) + { + rtems_rap_get_rtl_error (); + rtems_rap_app_free (app); + rtems_rap_unlock (); + return false; + } + + init = dlsym (app->handle, "rtems"); + if (!init) + { + rtems_rap_get_rtl_error (); + rtems_rap_app_free (app); + rtems_rap_unlock (); + return false; + } + + fini = dlsym (app->handle, "rtems"); + if (!fini) + { + rtems_rap_get_rtl_error (); + rtems_rap_app_free (app); + rtems_rap_unlock (); + return false; + } + + r = init (argc, argv); + if (r != 0) + { + rtems_rap_set_error (r, "init call failure"); + rtems_rap_app_free (app); + rtems_rap_unlock (); + return false; + } + } + + return true; +} + +bool +rtems_rap_unload (const char* name) +{ + rtems_rap_app_t* app; + rtems_rap_entry_t fini; + int r; + + rtems_rap_lock (); + + app = rtems_rap_find (name); + + if (rap_verbose) + printf ("rap: unloading '%s'\n", name); + + if (!app) + { + rtems_rap_set_error (ENOENT, "invalid handle"); + rtems_rap_unlock (); + return false; + } + + fini = dlsym (app->handle, "rtems"); + if (!fini) + { + rtems_rap_get_rtl_error (); + rtems_rap_unlock (); + return false; + } + + r = fini (0, NULL); + if (r != 0) + { + rtems_rap_set_error (r, "fini failure"); + rtems_rap_unlock (); + return false; + } + + rtems_rap_app_free (app); + rtems_rap_unlock (); + + return true; +} + +void* +rtems_rap_find (const char* name) +{ + rtems_rap_data_t* rap = rtems_rap_lock (); + rtems_chain_node* node; + + node = rtems_chain_first (&rap->apps); + + while (!rtems_chain_is_tail (&rap->apps, node)) + { + rtems_rap_app_t* app = (rtems_rap_app_t*) node; + if (rtems_rap_match_name (app, name)) + { + rtems_rap_unlock (); + return app; + } + node = rtems_chain_next (node); + } + + rtems_rap_unlock (); + + return NULL; +} + +bool +rtems_rap_iterate (rtems_rap_iterator_t iterator) +{ + rtems_rap_data_t* rap = rtems_rap_lock (); + rtems_chain_node* node; + bool result = true; + + node = rtems_chain_first (&rap->apps); + + while (!rtems_chain_is_tail (&rap->apps, node)) + { + rtems_rap_app_t* app = (rtems_rap_app_t*) node; + result = iterator (app); + if (!result) + break; + node = rtems_chain_next (node); + } + + rtems_rap_unlock (); + + return result; +} + +const char* +rtems_rap_name (void* handle) +{ + rtems_rap_app_t* app = rtems_rap_check_handle (handle); + if (app) + return app->name; + return NULL; +} + +void* +rtems_rap_dl_handle (void* handle) +{ + rtems_rap_app_t* app = rtems_rap_check_handle (handle); + if (app) + return app->handle; + return NULL; +} + +int +rtems_rap_get_error (char* message, size_t max_message) +{ + rtems_rap_data_t* rap = rtems_rap_lock (); + int last_errno = rap->last_errno; + strncpy (message, rap->last_error, sizeof (rap->last_error)); + rtems_rap_unlock (); + return last_errno; +} @@ -0,0 +1,115 @@ +/* + * COPYRIGHT (c) 2013 Chris Johns <chrisj@rtems.org> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ +/** + * @file + * + * @ingroup rtems_rap + * + * @brief RTEMS Application Loader + * + * This is the RTEMS Application loader for files in the RAP format. + */ + +#if !defined (_RAP_H_) +#define _RAP_H_ + +#include <rtems.h> +#include <rtems/chain.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup rtems_rap RTEMS Application Loader + * + * The module implements an application loader for files in the RAP format. The + * RAP format is: + * + * <header> + * <compressed container> + * + * The compressed container is a stream of ELF relocatable object files. + * + * TBD. + */ + +/** + * The module iterator handle. + */ +typedef bool (*rtems_rap_iterator_t) (void* handle); + +/** + * Load an application. + * + * @param name The name of the application file. + * @return bool True if the module loads else an error. + */ +bool rtems_rap_load (const char* name, int mode, int argc, const char* argv[]); + +/** + * Unload an application. + * + * @param obj The application descriptor. + * @retval true The application file has been unloaded. + * @retval false The application could not be unloaded. + */ +bool rtems_rap_unload (const char* name); + +/** + * Find the application handle given a file name. + * + * @param name The name of the application file. It can be absolute or + * relative. Relative names can the basename with an extension. + * @retval NULL No application file with that name found. + * @return void* The application descriptor. + */ +void* rtems_rap_find (const char* name); + +/** + * Run an iterator over the modules calling the iterator function. + * + * @param iterator The iterator function. + * @retval true The iterator function returned did not return false. + * @retval false The iterator function returned false.. + */ +bool rtems_rap_iterate (rtems_rap_iterator_t iterator); + +/** + * Return the name of the module given a handle. + * + * @param handle The module handle. + * @return const char* The name of the module if the handle is valid else it + * is NULL. + */ +const char* rtems_rap_name (void* handle); + +/** + * Return the DL handle used to load the module given the RAP handle. + * + * @param handle The module handle. + * @return void* The DL handle returned by the dlopen call. + */ +void* rtems_rap_dl_handle (void* handle); + +/** + * Get the last error message clearing it. This call is not thread safe is + * multiple threads are loading object files at the same time. This call + * follows the model provided by the dlopen family of calls. + * + * @param message Pointer to a buffer to copy the message into. + * @param max_message The maximum message that can be copied. + * @return int The last error number. + */ +int rtems_rap_get_error (char* message, size_t max_message); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/rtl-find-file.c b/rtl-find-file.c index 87a7501..15d749e 100644 --- a/rtl-find-file.c +++ b/rtl-find-file.c @@ -47,12 +47,12 @@ rtems_rtl_find_file (const char* name, *file_name = NULL; *size = 0; - if (rtems_filesystem_is_delimiter (name[0])) + if (rtems_filesystem_is_delimiter (name[0]) || (name[0] == '.')) { if (stat (name, &sb) == 0) *file_name = rtems_rtl_strdup (name); } - else + else if (paths) { const char* start; const char* end; @@ -102,10 +102,7 @@ rtems_rtl_find_file (const char* name, } if (!*file_name) - { - rtems_rtl_set_error (ENOMEM, "file not found"); return false; - } *size = sb.st_size; @@ -367,7 +367,11 @@ rtems_rtl_obj_find_file (rtems_rtl_obj_t* obj, const char* name) rtl = rtems_rtl_lock (); if (!rtems_rtl_find_file (pname, rtl->paths, &obj->fname, &obj->fsize)) + { + rtems_rtl_set_error (ENOENT, "file not found"); + rtems_rtl_unlock (); return false; + } rtems_rtl_unlock (); @@ -7,5 +7,4 @@ #mkdir c #mount -t dosfs /dev/hda1 /c #dlo c/bsdport.rap - -dlo bsdport.rap +#dlo bsdport.rap @@ -85,6 +85,8 @@ def build(bld): source = ['dlfcn.c', 'dlfcn-shell.c', 'fastlz.c', + 'rap.c', + 'rap-shell.c', 'rtl.c', 'rtl-alloc-heap.c', 'rtl-allocator.c', |