Index: uspace/app/trace/trace.c
===================================================================
--- uspace/app/trace/trace.c	(revision 6fa3a038324f471e7b8de39b911143f88f24f139)
+++ uspace/app/trace/trace.c	(revision 2443ad8f535160d516359619d12e8e3971670065)
@@ -47,5 +47,4 @@
 #include <mem.h>
 #include <str.h>
-#include <loader/loader.h>
 #include <io/console.h>
 #include <io/keycode.h>
@@ -86,6 +85,8 @@
 void thread_trace_start(uintptr_t thread_hash);
 
+static char *cmd_path;
+static char **cmd_args;
+
 static task_id_t task_id;
-static loader_t *task_ldr;
 static bool task_wait_for;
 
@@ -93,19 +94,5 @@
 display_mask_t display_mask;
 
-static errno_t program_run_fibril(void *arg);
 static errno_t cev_fibril(void *arg);
-
-static void program_run(void)
-{
-	fid_t fid;
-
-	fid = fibril_create(program_run_fibril, NULL);
-	if (fid == 0) {
-		printf("Error creating fibril\n");
-		exit(1);
-	}
-
-	fibril_add_ready(fid);
-}
 
 static void cev_fibril_start(void)
@@ -122,49 +109,49 @@
 }
 
-static errno_t program_run_fibril(void *arg)
-{
-	errno_t rc;
-
-	/*
-	 * This must be done in background as it will block until
-	 * we let the task reply to this call.
-	 */
-	rc = loader_run(task_ldr);
+static errno_t program_run(void)
+{
+	errno_t rc;
+
+	rc = task_spawnv_debug(&task_id, NULL, cmd_path,
+	    (const char *const *)cmd_args, &sess);
+
+	if (rc == ENOTSUP) {
+		printf("You do not have userspace debugging support "
+		    "compiled in the kernel.\n");
+		printf("Compile kernel with 'Support for userspace debuggers' "
+		    "(CONFIG_UDEBUG) enabled.\n");
+	}
+
 	if (rc != EOK) {
-		printf("Error running program\n");
-		exit(1);
-	}
-
-	task_ldr = NULL;
-
-	printf("program_run_fibril exiting\n");
-	return 0;
+		printf("Error running program (%s)\n", str_error_name(rc));
+		return rc;
+	}
+
+	return EOK;
 }
 
 static errno_t connect_task(task_id_t task_id)
 {
-	async_sess_t *ksess = async_connect_kbox(task_id);
-
-	if (!ksess) {
-		if (errno == ENOTSUP) {
-			printf("You do not have userspace debugging support "
-			    "compiled in the kernel.\n");
-			printf("Compile kernel with 'Support for userspace debuggers' "
-			    "(CONFIG_UDEBUG) enabled.\n");
-			return errno;
-		}
-
-		printf("Error connecting\n");
-		printf("ipc_connect_task(%" PRIu64 ") -> %s ", task_id, str_error_name(errno));
-		return errno;
-	}
-
-	errno_t rc = udebug_begin(ksess);
-	if (rc != EOK) {
-		printf("udebug_begin() -> %s\n", str_error_name(rc));
-		return rc;
-	}
-
-	rc = udebug_set_evmask(ksess, UDEBUG_EM_ALL);
+	errno_t rc;
+	bool debug_started = false;
+
+	if (sess == NULL) {
+		sess = async_connect_kbox(task_id);
+		if (sess == NULL) {
+			printf("Error connecting to task %" PRIu64 ".\n",
+			    task_id);
+			goto error;
+		}
+
+		rc = udebug_begin(sess);
+		if (rc != EOK) {
+			printf("Error starting debug session.\n");
+			goto error;
+		}
+
+		debug_started = true;
+	}
+
+	rc = udebug_set_evmask(sess, UDEBUG_EM_ALL);
 	if (rc != EOK) {
 		printf("udebug_set_evmask(0x%x) -> %s\n ", UDEBUG_EM_ALL, str_error_name(rc));
@@ -172,6 +159,11 @@
 	}
 
-	sess = ksess;
-	return 0;
+	return EOK;
+error:
+	if (debug_started)
+		udebug_end(sess);
+	if (sess != NULL)
+		async_hangup(sess);
+	return rc;
 }
 
@@ -198,5 +190,5 @@
 	printf("\ntotal of %zu threads\n", tb_needed / sizeof(uintptr_t));
 
-	return 0;
+	return EOK;
 }
 
@@ -488,5 +480,5 @@
 
 	printf("Finished tracing thread [%d].\n", thread_id);
-	return 0;
+	return EOK;
 }
 
@@ -502,76 +494,4 @@
 	}
 	fibril_add_ready(fid);
-}
-
-static loader_t *preload_task(const char *path, char **argv,
-    task_id_t *task_id)
-{
-	loader_t *ldr;
-	errno_t rc;
-
-	/* Spawn a program loader */
-	ldr = loader_connect();
-	if (ldr == NULL)
-		return NULL;
-
-	/* Get task ID. */
-	rc = loader_get_task_id(ldr, task_id);
-	if (rc != EOK)
-		goto error;
-
-	/* Send program. */
-	rc = loader_set_program_path(ldr, path);
-	if (rc != EOK)
-		goto error;
-
-	/* Send arguments */
-	rc = loader_set_args(ldr, (const char **) argv);
-	if (rc != EOK)
-		goto error;
-
-	/* Send default files */
-	int fd_root;
-	int fd_stdin;
-	int fd_stdout;
-	int fd_stderr;
-
-	fd_root = vfs_root();
-	if (fd_root >= 0) {
-		rc = loader_add_inbox(ldr, "root", fd_root);
-		vfs_put(fd_root);
-		if (rc != EOK)
-			goto error;
-	}
-
-	if ((stdin != NULL) && (vfs_fhandle(stdin, &fd_stdin) == EOK)) {
-		rc = loader_add_inbox(ldr, "stdin", fd_stdin);
-		if (rc != EOK)
-			goto error;
-	}
-
-	if ((stdout != NULL) && (vfs_fhandle(stdout, &fd_stdout) == EOK)) {
-		rc = loader_add_inbox(ldr, "stdout", fd_stdout);
-		if (rc != EOK)
-			goto error;
-	}
-
-	if ((stderr != NULL) && (vfs_fhandle(stderr, &fd_stderr) == EOK)) {
-		rc = loader_add_inbox(ldr, "stderr", fd_stderr);
-		if (rc != EOK)
-			goto error;
-	}
-
-	/* Load the program. */
-	rc = loader_load_program(ldr);
-	if (rc != EOK)
-		goto error;
-
-	/* Success */
-	return ldr;
-
-	/* Error exit */
-error:
-	loader_abort(ldr);
-	return NULL;
 }
 
@@ -807,5 +727,4 @@
 				++argv;
 				task_id = strtol(*argv, &err_p, 10);
-				task_ldr = NULL;
 				task_wait_for = false;
 				if (*err_p) {
@@ -848,5 +767,6 @@
 		printf("'%s'\n", *cp++);
 
-	task_ldr = preload_task(*argv, argv, &task_id);
+	cmd_path = *argv;
+	cmd_args = argv;
 	task_wait_for = true;
 
@@ -869,4 +789,7 @@
 
 	main_init();
+
+	if (cmd_path != NULL)
+		program_run();
 
 	rc = connect_task(task_id);
@@ -877,7 +800,4 @@
 
 	printf("Connected to task %" PRIu64 ".\n", task_id);
-
-	if (task_ldr != NULL)
-		program_run();
 
 	cev_fibril_start();
Index: uspace/lib/c/generic/loader.c
===================================================================
--- uspace/lib/c/generic/loader.c	(revision 6fa3a038324f471e7b8de39b911143f88f24f139)
+++ uspace/lib/c/generic/loader.c	(revision 2443ad8f535160d516359619d12e8e3971670065)
@@ -345,4 +345,27 @@
 }
 
+/** Instruct loader to execute the program and do not wait for reply.
+ *
+ * This function does not block even if the loaded task is stopped
+ * for debugging.
+ *
+ * After using this function, no further operations can be performed
+ * on the loader structure and it is deallocated.
+ *
+ * @param ldr Loader connection structure.
+ *
+ * @return Zero on success or an error code.
+ *
+ */
+void loader_run_nowait(loader_t *ldr)
+{
+	async_exch_t *exch = async_exchange_begin(ldr->sess);
+	async_msg_0(exch, LOADER_RUN);
+	async_exchange_end(exch);
+
+	async_hangup(ldr->sess);
+	free(ldr);
+}
+
 /** Cancel the loader session.
  *
Index: uspace/lib/c/generic/task.c
===================================================================
--- uspace/lib/c/generic/task.c	(revision 6fa3a038324f471e7b8de39b911143f88f24f139)
+++ uspace/lib/c/generic/task.c	(revision 2443ad8f535160d516359619d12e8e3971670065)
@@ -35,4 +35,5 @@
  */
 
+#include <async.h>
 #include <task.h>
 #include <loader/loader.h>
@@ -46,4 +47,5 @@
 #include <ns.h>
 #include <stdlib.h>
+#include <udebug.h>
 #include <libc.h>
 #include "private/ns.h"
@@ -94,4 +96,5 @@
  * This is really just a convenience wrapper over the more complicated
  * loader API. Arguments are passed as a null-terminated array of strings.
+ * A debug session is created optionally.
  *
  * @param id   If not NULL, the ID of the task is stored here on success.
@@ -100,10 +103,12 @@
  * @param path Pathname of the binary to execute.
  * @param argv Command-line arguments.
- *
- * @return Zero on success or an error code.
- *
- */
-errno_t task_spawnv(task_id_t *id, task_wait_t *wait, const char *path,
-    const char *const args[])
+ * @param rsess   Place to store pointer to debug session or @c NULL
+ *                not to start a debug session
+ *
+ * @return Zero on success or an error code.
+ *
+ */
+errno_t task_spawnv_debug(task_id_t *id, task_wait_t *wait, const char *path,
+    const char *const args[], async_sess_t **rsess)
 {
 	/* Send default files */
@@ -125,28 +130,54 @@
 	}
 
-	return task_spawnvf(id, wait, path, args, fd_stdin, fd_stdout,
-	    fd_stderr);
+	return task_spawnvf_debug(id, wait, path, args, fd_stdin, fd_stdout,
+	    fd_stderr, rsess);
 }
 
 /** Create a new task by running an executable from the filesystem.
+ *
+ * This is really just a convenience wrapper over the more complicated
+ * loader API. Arguments are passed as a null-terminated array of strings.
+ *
+ * @param id   If not NULL, the ID of the task is stored here on success.
+ * @param wait If not NULL, setup waiting for task's return value and store
+ *             the information necessary for waiting here on success.
+ * @param path Pathname of the binary to execute.
+ * @param argv Command-line arguments.
+ *
+ * @return Zero on success or an error code.
+ *
+ */
+errno_t task_spawnv(task_id_t *id, task_wait_t *wait, const char *path,
+    const char *const args[])
+{
+	return task_spawnv_debug(id, wait, path, args, NULL);
+}
+
+/** Create a new task by loading an executable from the filesystem.
  *
  * This is really just a convenience wrapper over the more complicated
  * loader API. Arguments are passed as a null-terminated array of strings.
  * Files are passed as null-terminated array of pointers to fdi_node_t.
+ * A debug session is created optionally.
  *
  * @param id      If not NULL, the ID of the task is stored here on success.
- * @param wait    If not NULL, setup waiting for task's return value and store
+ * @param wait    If not NULL, setup waiting for task's return value and store.
  * @param path    Pathname of the binary to execute.
- * @param argv    Command-line arguments.
- * @param std_in  File to use as stdin.
- * @param std_out File to use as stdout.
- * @param std_err File to use as stderr.
- *
- * @return Zero on success or an error code.
- *
- */
-errno_t task_spawnvf(task_id_t *id, task_wait_t *wait, const char *path,
-    const char *const args[], int fd_stdin, int fd_stdout, int fd_stderr)
-{
+ * @param argv    Command-line arguments
+ * @param std_in  File to use as stdin
+ * @param std_out File to use as stdout
+ * @param std_err File to use as stderr
+ * @param rsess   Place to store pointer to debug session or @c NULL
+ *                not to start a debug session
+ *
+ * @return Zero on success or an error code
+ *
+ */
+errno_t task_spawnvf_debug(task_id_t *id, task_wait_t *wait,
+    const char *path, const char *const args[], int fd_stdin, int fd_stdout,
+    int fd_stderr, async_sess_t **rsess)
+{
+	async_sess_t *ksess = NULL;
+
 	/* Connect to a program loader. */
 	loader_t *ldr = loader_connect();
@@ -217,16 +248,39 @@
 	}
 
-	/* Run it. */
-	rc = loader_run(ldr);
-	if (rc != EOK)
-		goto error;
+	/* Start a debug session if requested */
+	if (rsess != NULL) {
+		ksess = async_connect_kbox(task_id);
+		if (ksess == NULL) {
+			/* Most likely debugging support is not compiled in */
+			rc = ENOTSUP;
+			goto error;
+		}
+
+		rc = udebug_begin(ksess);
+		if (rc != EOK)
+			goto error;
+
+		/*
+		 * Run it, not waiting for response. It would never come
+		 * as the loader is stopped.
+		 */
+		loader_run_nowait(ldr);
+	} else {
+		/* Run it. */
+		rc = loader_run(ldr);
+		if (rc != EOK)
+			goto error;
+	}
 
 	/* Success */
 	if (id != NULL)
 		*id = task_id;
-
+	if (rsess != NULL)
+		*rsess = ksess;
 	return EOK;
 
 error:
+	if (ksess != NULL)
+		async_hangup(ksess);
 	if (wait_initialized)
 		task_cancel_wait(wait);
@@ -235,4 +289,27 @@
 	loader_abort(ldr);
 	return rc;
+}
+
+/** Create a new task by running an executable from the filesystem.
+ *
+ * Arguments are passed as a null-terminated array of strings.
+ * Files are passed as null-terminated array of pointers to fdi_node_t.
+ *
+ * @param id      If not NULL, the ID of the task is stored here on success.
+ * @param wait    If not NULL, setup waiting for task's return value and store.
+ * @param path    Pathname of the binary to execute
+ * @param argv    Command-line arguments
+ * @param std_in  File to use as stdin
+ * @param std_out File to use as stdout
+ * @param std_err File to use as stderr
+ *
+ * @return Zero on success or an error code.
+ *
+ */
+errno_t task_spawnvf(task_id_t *id, task_wait_t *wait, const char *path,
+    const char *const args[], int fd_stdin, int fd_stdout, int fd_stderr)
+{
+	return task_spawnvf_debug(id, wait, path, args, fd_stdin, fd_stdout,
+	    fd_stderr, NULL);
 }
 
Index: uspace/lib/c/include/loader/loader.h
===================================================================
--- uspace/lib/c/include/loader/loader.h	(revision 6fa3a038324f471e7b8de39b911143f88f24f139)
+++ uspace/lib/c/include/loader/loader.h	(revision 2443ad8f535160d516359619d12e8e3971670065)
@@ -53,4 +53,5 @@
 extern errno_t loader_load_program(loader_t *);
 extern errno_t loader_run(loader_t *);
+extern void loader_run_nowait(loader_t *);
 extern void loader_abort(loader_t *);
 
Index: uspace/lib/c/include/task.h
===================================================================
--- uspace/lib/c/include/task.h	(revision 6fa3a038324f471e7b8de39b911143f88f24f139)
+++ uspace/lib/c/include/task.h	(revision 2443ad8f535160d516359619d12e8e3971670065)
@@ -36,4 +36,5 @@
 #define _LIBC_TASK_H_
 
+#include <async.h>
 #include <stdint.h>
 #include <stdarg.h>
@@ -56,6 +57,10 @@
 extern errno_t task_spawnv(task_id_t *, task_wait_t *, const char *path,
     const char *const []);
+extern errno_t task_spawnv_debug(task_id_t *, task_wait_t *, const char *path,
+    const char *const [], async_sess_t **);
 extern errno_t task_spawnvf(task_id_t *, task_wait_t *, const char *path,
     const char *const [], int, int, int);
+extern errno_t task_spawnvf_debug(task_id_t *, task_wait_t *, const char *path,
+    const char *const [], int, int, int, async_sess_t **);
 extern errno_t task_spawn(task_id_t *, task_wait_t *, const char *path, int,
     va_list ap);
