summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c3
-rw-r--r--rap-shell.c106
-rw-r--r--rap-shell.h14
-rw-r--r--rap.c473
-rw-r--r--rap.h115
-rw-r--r--rtl-find-file.c7
-rw-r--r--rtl-obj.c4
-rw-r--r--shell-init3
-rw-r--r--wscript2
9 files changed, 720 insertions, 7 deletions
diff --git a/main.c b/main.c
index 9586502..a8f8640 100644
--- a/main.c
+++ b/main.c
@@ -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
diff --git a/rap.c b/rap.c
new file mode 100644
index 0000000..850d84a
--- /dev/null
+++ b/rap.c
@@ -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;
+}
diff --git a/rap.h b/rap.h
new file mode 100644
index 0000000..e53699f
--- /dev/null
+++ b/rap.h
@@ -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;
diff --git a/rtl-obj.c b/rtl-obj.c
index df7ec8b..ddf4a0b 100644
--- a/rtl-obj.c
+++ b/rtl-obj.c
@@ -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 ();
diff --git a/shell-init b/shell-init
index 97033d9..0155377 100644
--- a/shell-init
+++ b/shell-init
@@ -7,5 +7,4 @@
#mkdir c
#mount -t dosfs /dev/hda1 /c
#dlo c/bsdport.rap
-
-dlo bsdport.rap
+#dlo bsdport.rap
diff --git a/wscript b/wscript
index 2faba1b..9f9417a 100644
--- a/wscript
+++ b/wscript
@@ -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',