summaryrefslogtreecommitdiff
path: root/nuttx/binfmt
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-09-14 14:10:23 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-09-14 14:10:23 -0600
commit8a1169b515470b959633c5fba69a135d7789a96f (patch)
tree8139f7e3d309f54efd53b89610417d3abc2cbd89 /nuttx/binfmt
parent60b7d076c27f4e3450d9beb7131adf787411f529 (diff)
downloadpx4-nuttx-8a1169b515470b959633c5fba69a135d7789a96f.tar.gz
px4-nuttx-8a1169b515470b959633c5fba69a135d7789a96f.tar.bz2
px4-nuttx-8a1169b515470b959633c5fba69a135d7789a96f.zip
In kernel mode, we have to duplicate the callers argv[] buffer when exec'ing new tasks. When the argv[] buffer is needed, the caller's address environment will not longer be in place
Diffstat (limited to 'nuttx/binfmt')
-rw-r--r--nuttx/binfmt/binfmt_exec.c102
-rw-r--r--nuttx/binfmt/binfmt_execmodule.c15
-rw-r--r--nuttx/binfmt/binfmt_internal.h39
-rw-r--r--nuttx/binfmt/binfmt_unloadmodule.c31
4 files changed, 173 insertions, 14 deletions
diff --git a/nuttx/binfmt/binfmt_exec.c b/nuttx/binfmt/binfmt_exec.c
index 63bac45d2..a250b2269 100644
--- a/nuttx/binfmt/binfmt_exec.c
+++ b/nuttx/binfmt/binfmt_exec.c
@@ -59,6 +59,89 @@
****************************************************************************/
/****************************************************************************
+ * Name: binfmt_copyargv
+ *
+ * Description:
+ * In the kernel build, the argv list will likely lie in the caller's
+ * address environment and, hence, by inaccessible when we swith to the
+ * address environment of the new process address environment. So we
+ * do not have any real option other than to copy the callers argv[] list.
+ *
+ * Input Parameter:
+ * bin - Load structure
+ * argv - Argument list
+ *
+ * Returned Value:
+ * Zero (OK) on sucess; a negater erro value on failure.
+ *
+ ****************************************************************************/
+
+static inline int binfmt_copyargv(FAR struct binary_s *bin, FAR char * const *argv)
+{
+#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
+ FAR char *ptr;
+ size_t argsize;
+ int i;
+
+ /* Get the size of the argument list */
+
+ bin->argbuffer = (FAR char *)NULL;
+ i = 0;
+
+ if (argv)
+ {
+ argsize = 0;
+ for (i = 0; i < CONFIG_MAX_TASK_ARGS && argv[i]; i++)
+ {
+ argsize += (strlen(argv[i]) + 1);
+ }
+
+ bvdbg("args=%d argsize=%lu\n", i, (unsigned long)argsize);
+
+ /* Allocate a temporary argument buffer */
+
+ i = 0;
+
+ if (argsize > 0)
+ {
+ bin->argbuffer = (FAR char *)kmm_malloc(argsize);
+ if (!bin->argbuffer)
+ {
+ bdbg("ERROR: Failed to allocate the argument buffer\n");
+ return -ENOMEM;
+ }
+
+ /* Copy the argv list */
+
+ ptr = bin->argbuffer;
+ for (; i < CONFIG_MAX_TASK_ARGS && argv[i]; i++)
+ {
+ bin->argv[i] = ptr;
+ argsize = strlen(argv[i]) + 1;
+ memcpy(ptr, argv[i], argsize);
+ ptr += argsize;
+ }
+ }
+ }
+
+ /* Nullify the remainder of the list */
+
+ for (; i <= CONFIG_MAX_TASK_ARGS; i++)
+ {
+ bin->argv[i] = NULL;
+ }
+
+ return OK;
+
+#else
+ /* Just save the caller's argv pointer */
+
+ bin->argv = argv;
+ return OK;
+#endif
+}
+
+/****************************************************************************
* Private Data
****************************************************************************/
@@ -115,19 +198,30 @@ int exec(FAR const char *filename, FAR char * const *argv,
goto errout;
}
- /* Load the module into memory */
+ /* Initialize the binary structure */
bin->filename = filename;
- bin->argv = argv;
bin->exports = exports;
bin->nexports = nexports;
+ /* Copy the argv[] list */
+
+ ret = binfmt_copyargv(bin, argv);
+ if (ret < 0)
+ {
+ err = -ret;
+ bdbg("ERROR: Failed to copy argv[]: %d\n", err);
+ goto errout_with_bin;
+ }
+
+ /* Load the module into memory */
+
ret = load_module(bin);
if (ret < 0)
{
err = get_errno();
bdbg("ERROR: Failed to load program '%s': %d\n", filename, err);
- goto errout_with_bin;
+ goto errout_with_argv;
}
/* Disable pre-emption so that the executed module does
@@ -164,6 +258,8 @@ int exec(FAR const char *filename, FAR char * const *argv,
errout_with_lock:
sched_unlock();
unload_module(bin);
+errout_with_argv:
+ binfmt_freeargv(bin);
errout_with_bin:
kmm_free(bin);
errout:
diff --git a/nuttx/binfmt/binfmt_execmodule.c b/nuttx/binfmt/binfmt_execmodule.c
index dae892571..f2ff5db7a 100644
--- a/nuttx/binfmt/binfmt_execmodule.c
+++ b/nuttx/binfmt/binfmt_execmodule.c
@@ -192,7 +192,7 @@ int exec_module(FAR const struct binary_s *binp)
if (!stack)
{
err = ENOMEM;
- goto errout_with_kstack;
+ goto errout_with_addrenv;
}
/* Initialize the task */
@@ -203,9 +203,13 @@ int exec_module(FAR const struct binary_s *binp)
{
err = get_errno();
bdbg("task_init() failed: %d\n", err);
- goto errout_with_kstack;
+ goto errout_with_addrenv;
}
+ /* We can free the argument buffer now */
+
+ binfmt_freeargv(binp);
+
/* Note that tcb->flags are not modified. 0=normal task */
/* tcb->flags |= TCB_FLAG_TTYPE_TASK; */
@@ -217,7 +221,7 @@ int exec_module(FAR const struct binary_s *binp)
{
bdbg("ERROR: up_addrenv_select() failed: %d\n", ret);
err = -ret;
- goto errout_with_addrenv;
+ goto errout_with_tcbinit;
}
#endif
@@ -292,12 +296,7 @@ errout_with_tcbinit:
kumm_free(stack);
goto errout;
-errout_with_kstack:
-#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
- (void)up_addrenv_kstackfree(tcb);
-
errout_with_addrenv:
-#endif
#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
(void)up_addrenv_restore(&oldenv);
diff --git a/nuttx/binfmt/binfmt_internal.h b/nuttx/binfmt/binfmt_internal.h
index fa750543a..184263183 100644
--- a/nuttx/binfmt/binfmt_internal.h
+++ b/nuttx/binfmt/binfmt_internal.h
@@ -55,7 +55,8 @@
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
-extern "C" {
+extern "C"
+{
#else
#define EXTERN extern
#endif
@@ -71,14 +72,46 @@ EXTERN FAR struct binfmt_s *g_binfmts;
* Public Function Prototypes
***********************************************************************/
-/* Dump the contents of struct binary_s */
+/****************************************************************************
+ * Name: dump_module
+ *
+ * Description:
+ * Dump the contents of struct binary_s.
+ *
+ * Input Parameter:
+ * bin - Load structure
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negater errno value on failure
+ *
+ ****************************************************************************/
#if defined(CONFIG_DEBUG) && defined(CONFIG_DEBUG_BINFMT)
-EXTERN int dump_module(FAR const struct binary_s *bin);
+int dump_module(FAR const struct binary_s *bin);
#else
# define dump_module(bin)
#endif
+/****************************************************************************
+ * Name: binfmt_freeargv
+ *
+ * Description:
+ * Release the copied argv[] list.
+ *
+ * Input Parameter:
+ * bin - Load structure
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
+void binfmt_freeargv(FAR struct binary_s *bin);
+#else
+# define binfmt_freeargv(bin)
+#endif
+
#undef EXTERN
#if defined(__cplusplus)
}
diff --git a/nuttx/binfmt/binfmt_unloadmodule.c b/nuttx/binfmt/binfmt_unloadmodule.c
index 67b957b20..ce1b0e53d 100644
--- a/nuttx/binfmt/binfmt_unloadmodule.c
+++ b/nuttx/binfmt/binfmt_unloadmodule.c
@@ -179,6 +179,10 @@ int unload_module(FAR struct binary_s *binp)
}
#endif
+ /* Free any allocated argv[] strings */
+
+ binfmt_freeargv(binp);
+
/* Unmap mapped address spaces */
if (binp->mapped)
@@ -207,5 +211,32 @@ int unload_module(FAR struct binary_s *binp)
return OK;
}
+/****************************************************************************
+ * Name: binfmt_freeargv
+ *
+ * Description:
+ * Release the copied argv[] list.
+ *
+ * Input Parameter:
+ * binp - Load structure
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
+void binfmt_freeargv(FAR struct binary_s *binp)
+{
+ if (binp->argbuffer)
+ {
+ /* Free the argument buffer */
+
+ kmm_free(binp->argbuffer);
+ binp->argbuffer = NULL;
+ }
+}
+#endif
+
#endif /* CONFIG_BINFMT_DISABLE */