source: mainline/uspace/app/trace/trace.c@ b8dbe2f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b8dbe2f was b8dbe2f, checked in by Jiri Zarevucky <zarevucky.jiri@…>, 12 years ago

Remove unnecessary includes.

  • Property mode set to 100644
File size: 18.0 KB
Line 
1/*
2 * Copyright (c) 2008 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup trace
30 * @{
31 */
32/** @file
33 */
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <unistd.h>
38#include <fibril.h>
39#include <errno.h>
40#include <udebug.h>
41#include <async.h>
42#include <task.h>
43#include <mem.h>
44#include <str.h>
45#include <stdbool.h>
46#include <loader/loader.h>
47#include <io/console.h>
48#include <io/keycode.h>
49#include <fibril_synch.h>
50#include <sys/types.h>
51#include <sys/typefmt.h>
52#include <vfs/vfs.h>
53
54#include <libc.h>
55
56/* Temporary: service and method names */
57#include "proto.h"
58#include <ipc/services.h>
59#include <ipc/console.h>
60
61#include "syscalls.h"
62#include "ipcp.h"
63#include "errors.h"
64#include "trace.h"
65
66#define THBUF_SIZE 64
67uintptr_t thread_hash_buf[THBUF_SIZE];
68int n_threads;
69
70int next_thread_id;
71
72ipc_call_t thread_ipc_req[THBUF_SIZE];
73
74async_sess_t *sess;
75bool abort_trace;
76
77uintptr_t thash;
78static bool paused;
79static fibril_condvar_t state_cv;
80static fibril_mutex_t state_lock;
81
82static bool cev_valid;
83static kbd_event_t cev;
84
85void thread_trace_start(uintptr_t thread_hash);
86
87static task_id_t task_id;
88static loader_t *task_ldr;
89static bool task_wait_for;
90
91/** Combination of events/data to print. */
92display_mask_t display_mask;
93
94static int program_run_fibril(void *arg);
95static int cev_fibril(void *arg);
96
97static void program_run(void)
98{
99 fid_t fid;
100
101 fid = fibril_create(program_run_fibril, NULL);
102 if (fid == 0) {
103 printf("Error creating fibril\n");
104 exit(1);
105 }
106
107 fibril_add_ready(fid);
108}
109
110static void cev_fibril_start(void)
111{
112 fid_t fid;
113
114 fid = fibril_create(cev_fibril, NULL);
115 if (fid == 0) {
116 printf("Error creating fibril\n");
117 exit(1);
118 }
119
120 fibril_add_ready(fid);
121}
122
123static int program_run_fibril(void *arg)
124{
125 int rc;
126
127 /*
128 * This must be done in background as it will block until
129 * we let the task reply to this call.
130 */
131 rc = loader_run(task_ldr);
132 if (rc != 0) {
133 printf("Error running program\n");
134 exit(1);
135 }
136
137 task_ldr = NULL;
138
139 printf("program_run_fibril exiting\n");
140 return 0;
141}
142
143
144static int connect_task(task_id_t task_id)
145{
146 async_sess_t *ksess = async_connect_kbox(task_id);
147
148 if (!ksess) {
149 if (errno == ENOTSUP) {
150 printf("You do not have userspace debugging support "
151 "compiled in the kernel.\n");
152 printf("Compile kernel with 'Support for userspace debuggers' "
153 "(CONFIG_UDEBUG) enabled.\n");
154 return errno;
155 }
156
157 printf("Error connecting\n");
158 printf("ipc_connect_task(%" PRIu64 ") -> %d ", task_id, errno);
159 return errno;
160 }
161
162 int rc = udebug_begin(ksess);
163 if (rc < 0) {
164 printf("udebug_begin() -> %d\n", rc);
165 return rc;
166 }
167
168 rc = udebug_set_evmask(ksess, UDEBUG_EM_ALL);
169 if (rc < 0) {
170 printf("udebug_set_evmask(0x%x) -> %d\n ", UDEBUG_EM_ALL, rc);
171 return rc;
172 }
173
174 sess = ksess;
175 return 0;
176}
177
178static int get_thread_list(void)
179{
180 int rc;
181 size_t tb_copied;
182 size_t tb_needed;
183 int i;
184
185 rc = udebug_thread_read(sess, thread_hash_buf,
186 THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed);
187 if (rc < 0) {
188 printf("udebug_thread_read() -> %d\n", rc);
189 return rc;
190 }
191
192 n_threads = tb_copied / sizeof(uintptr_t);
193
194 printf("Threads:");
195 for (i = 0; i < n_threads; i++) {
196 printf(" [%d] (hash %p)", 1 + i, (void *) thread_hash_buf[i]);
197 }
198 printf("\ntotal of %zu threads\n", tb_needed / sizeof(uintptr_t));
199
200 return 0;
201}
202
203void val_print(sysarg_t val, val_type_t v_type)
204{
205 long sval;
206
207 sval = (long) val;
208
209 switch (v_type) {
210 case V_VOID:
211 printf("<void>");
212 break;
213
214 case V_INTEGER:
215 printf("%ld", sval);
216 break;
217
218 case V_HASH:
219 case V_PTR:
220 printf("%p", (void *) val);
221 break;
222
223 case V_ERRNO:
224 if (sval >= -15 && sval <= 0) {
225 printf("%ld %s (%s)", sval,
226 err_desc[-sval].name,
227 err_desc[-sval].desc);
228 } else {
229 printf("%ld", sval);
230 }
231 break;
232 case V_INT_ERRNO:
233 if (sval >= -15 && sval < 0) {
234 printf("%ld %s (%s)", sval,
235 err_desc[-sval].name,
236 err_desc[-sval].desc);
237 } else {
238 printf("%ld", sval);
239 }
240 break;
241
242 case V_CHAR:
243 if (sval >= 0x20 && sval < 0x7f) {
244 printf("'%c'", (char) sval);
245 } else {
246 switch (sval) {
247 case '\a': printf("'\\a'"); break;
248 case '\b': printf("'\\b'"); break;
249 case '\n': printf("'\\n'"); break;
250 case '\r': printf("'\\r'"); break;
251 case '\t': printf("'\\t'"); break;
252 case '\\': printf("'\\\\'"); break;
253 default: printf("'\\x%02" PRIxn "'", val); break;
254 }
255 }
256 break;
257 }
258}
259
260
261static void print_sc_retval(sysarg_t retval, val_type_t val_type)
262{
263 printf(" -> ");
264 val_print(retval, val_type);
265 putchar('\n');
266}
267
268static void print_sc_args(sysarg_t *sc_args, int n)
269{
270 int i;
271
272 putchar('(');
273 if (n > 0) printf("%" PRIun, sc_args[0]);
274 for (i = 1; i < n; i++) {
275 printf(", %" PRIun, sc_args[i]);
276 }
277 putchar(')');
278}
279
280static void sc_ipc_call_async_fast(sysarg_t *sc_args, sysarg_t sc_rc)
281{
282 ipc_call_t call;
283 sysarg_t phoneid;
284
285 if (sc_rc == (sysarg_t) IPC_CALLRET_FATAL ||
286 sc_rc == (sysarg_t) IPC_CALLRET_TEMPORARY)
287 return;
288
289 phoneid = sc_args[0];
290
291 IPC_SET_IMETHOD(call, sc_args[1]);
292 IPC_SET_ARG1(call, sc_args[2]);
293 IPC_SET_ARG2(call, sc_args[3]);
294 IPC_SET_ARG3(call, sc_args[4]);
295 IPC_SET_ARG4(call, sc_args[5]);
296 IPC_SET_ARG5(call, 0);
297
298 ipcp_call_out(phoneid, &call, sc_rc);
299}
300
301static void sc_ipc_call_async_slow(sysarg_t *sc_args, sysarg_t sc_rc)
302{
303 ipc_call_t call;
304 int rc;
305
306 if (sc_rc == (sysarg_t) IPC_CALLRET_FATAL ||
307 sc_rc == (sysarg_t) IPC_CALLRET_TEMPORARY)
308 return;
309
310 memset(&call, 0, sizeof(call));
311 rc = udebug_mem_read(sess, &call.args, sc_args[1], sizeof(call.args));
312
313 if (rc >= 0) {
314 ipcp_call_out(sc_args[0], &call, sc_rc);
315 }
316}
317
318static void sc_ipc_wait(sysarg_t *sc_args, int sc_rc)
319{
320 ipc_call_t call;
321 int rc;
322
323 if (sc_rc == 0) return;
324
325 memset(&call, 0, sizeof(call));
326 rc = udebug_mem_read(sess, &call, sc_args[0], sizeof(call));
327
328 if (rc >= 0)
329 ipcp_call_in(&call, sc_rc);
330}
331
332static void event_syscall_b(unsigned thread_id, uintptr_t thread_hash,
333 unsigned sc_id, sysarg_t sc_rc)
334{
335 sysarg_t sc_args[6];
336 int rc;
337
338 /* Read syscall arguments */
339 rc = udebug_args_read(sess, thread_hash, sc_args);
340
341 if (rc < 0) {
342 printf("error\n");
343 return;
344 }
345
346 if ((display_mask & DM_SYSCALL) != 0) {
347 /* Print syscall name and arguments */
348 if (syscall_desc_defined(sc_id)) {
349 printf("%s", syscall_desc[sc_id].name);
350 print_sc_args(sc_args, syscall_desc[sc_id].n_args);
351 }
352 else {
353 printf("unknown_syscall<%d>", sc_id);
354 print_sc_args(sc_args, 6);
355 }
356 }
357}
358
359static void event_syscall_e(unsigned thread_id, uintptr_t thread_hash,
360 unsigned sc_id, sysarg_t sc_rc)
361{
362 sysarg_t sc_args[6];
363 int rv_type;
364 int rc;
365
366 /* Read syscall arguments */
367 rc = udebug_args_read(sess, thread_hash, sc_args);
368
369// printf("[%d] ", thread_id);
370
371 if (rc < 0) {
372 printf("error\n");
373 return;
374 }
375
376 if ((display_mask & DM_SYSCALL) != 0) {
377 /* Print syscall return value */
378 if (syscall_desc_defined(sc_id))
379 rv_type = syscall_desc[sc_id].rv_type;
380 else
381 rv_type = V_PTR;
382 print_sc_retval(sc_rc, rv_type);
383 }
384
385 switch (sc_id) {
386 case SYS_IPC_CALL_ASYNC_FAST:
387 sc_ipc_call_async_fast(sc_args, sc_rc);
388 break;
389 case SYS_IPC_CALL_ASYNC_SLOW:
390 sc_ipc_call_async_slow(sc_args, sc_rc);
391 break;
392 case SYS_IPC_WAIT:
393 sc_ipc_wait(sc_args, sc_rc);
394 break;
395 default:
396 break;
397 }
398}
399
400static void event_thread_b(uintptr_t hash)
401{
402 printf("New thread, hash %p\n", (void *) hash);
403 thread_trace_start(hash);
404}
405
406static int trace_loop(void *thread_hash_arg)
407{
408 int rc;
409 unsigned ev_type;
410 uintptr_t thread_hash;
411 unsigned thread_id;
412 sysarg_t val0, val1;
413
414 thread_hash = (uintptr_t)thread_hash_arg;
415 thread_id = next_thread_id++;
416 if (thread_id >= THBUF_SIZE) {
417 printf("Too many threads.\n");
418 return ELIMIT;
419 }
420
421 printf("Start tracing thread [%u] (hash %p).\n",
422 thread_id, (void *) thread_hash);
423
424 while (!abort_trace) {
425
426 fibril_mutex_lock(&state_lock);
427 if (paused) {
428 printf("Thread [%u] paused. Press R to resume.\n",
429 thread_id);
430
431 while (paused)
432 fibril_condvar_wait(&state_cv, &state_lock);
433
434 printf("Thread [%u] resumed.\n", thread_id);
435 }
436 fibril_mutex_unlock(&state_lock);
437
438 /* Run thread until an event occurs */
439 rc = udebug_go(sess, thread_hash,
440 &ev_type, &val0, &val1);
441
442// printf("rc = %d, ev_type=%d\n", rc, ev_type);
443 if (ev_type == UDEBUG_EVENT_FINISHED) {
444 /* Done tracing this thread */
445 break;
446 }
447
448 if (rc >= 0) {
449 switch (ev_type) {
450 case UDEBUG_EVENT_SYSCALL_B:
451 event_syscall_b(thread_id, thread_hash, val0, (int)val1);
452 break;
453 case UDEBUG_EVENT_SYSCALL_E:
454 event_syscall_e(thread_id, thread_hash, val0, (int)val1);
455 break;
456 case UDEBUG_EVENT_STOP:
457 printf("Stop event\n");
458 fibril_mutex_lock(&state_lock);
459 paused = true;
460 fibril_mutex_unlock(&state_lock);
461 break;
462 case UDEBUG_EVENT_THREAD_B:
463 event_thread_b(val0);
464 break;
465 case UDEBUG_EVENT_THREAD_E:
466 printf("Thread %" PRIun " exited.\n", val0);
467 fibril_mutex_lock(&state_lock);
468 abort_trace = true;
469 fibril_condvar_broadcast(&state_cv);
470 fibril_mutex_unlock(&state_lock);
471 break;
472 default:
473 printf("Unknown event type %d.\n", ev_type);
474 break;
475 }
476 }
477
478 }
479
480 printf("Finished tracing thread [%d].\n", thread_id);
481 return 0;
482}
483
484void thread_trace_start(uintptr_t thread_hash)
485{
486 fid_t fid;
487
488 thash = thread_hash;
489
490 fid = fibril_create(trace_loop, (void *)thread_hash);
491 if (fid == 0) {
492 printf("Warning: Failed creating fibril\n");
493 }
494 fibril_add_ready(fid);
495}
496
497static loader_t *preload_task(const char *path, char **argv,
498 task_id_t *task_id)
499{
500 loader_t *ldr;
501 int rc;
502
503 /* Spawn a program loader */
504 ldr = loader_connect();
505 if (ldr == NULL)
506 return NULL;
507
508 /* Get task ID. */
509 rc = loader_get_task_id(ldr, task_id);
510 if (rc != EOK)
511 goto error;
512
513 /* Send program pathname */
514 rc = loader_set_pathname(ldr, path);
515 if (rc != EOK)
516 goto error;
517
518 /* Send arguments */
519 rc = loader_set_args(ldr, (const char **) argv);
520 if (rc != EOK)
521 goto error;
522
523 /* Send default files */
524 int *files[4];
525 int fd_stdin;
526 int fd_stdout;
527 int fd_stderr;
528
529 if ((stdin != NULL) && (fhandle(stdin, &fd_stdin) == EOK))
530 files[0] = &fd_stdin;
531 else
532 files[0] = NULL;
533
534 if ((stdout != NULL) && (fhandle(stdout, &fd_stdout) == EOK))
535 files[1] = &fd_stdout;
536 else
537 files[1] = NULL;
538
539 if ((stderr != NULL) && (fhandle(stderr, &fd_stderr) == EOK))
540 files[2] = &fd_stderr;
541 else
542 files[2] = NULL;
543
544 files[3] = NULL;
545
546 rc = loader_set_files(ldr, files);
547 if (rc != EOK)
548 goto error;
549
550 /* Load the program. */
551 rc = loader_load_program(ldr);
552 if (rc != EOK)
553 goto error;
554
555 /* Success */
556 return ldr;
557
558 /* Error exit */
559error:
560 loader_abort(ldr);
561 return NULL;
562}
563
564static int cev_fibril(void *arg)
565{
566 cons_event_t event;
567
568 (void) arg;
569
570 console_ctrl_t *console = console_init(stdin, stdout);
571
572 while (true) {
573 fibril_mutex_lock(&state_lock);
574 while (cev_valid)
575 fibril_condvar_wait(&state_cv, &state_lock);
576 fibril_mutex_unlock(&state_lock);
577
578 if (!console_get_event(console, &event))
579 return -1;
580
581 if (event.type == CEV_KEY) {
582 fibril_mutex_lock(&state_lock);
583 cev = event.ev.key;
584 cev_valid = true;
585 fibril_condvar_broadcast(&state_cv);
586 fibril_mutex_unlock(&state_lock);
587 }
588 }
589}
590
591static void trace_task(task_id_t task_id)
592{
593 kbd_event_t ev;
594 bool done;
595 int i;
596 int rc;
597
598 ipcp_init();
599
600 rc = get_thread_list();
601 if (rc < 0) {
602 printf("Failed to get thread list (error %d)\n", rc);
603 return;
604 }
605
606 abort_trace = false;
607
608 for (i = 0; i < n_threads; i++) {
609 thread_trace_start(thread_hash_buf[i]);
610 }
611
612 done = false;
613
614 while (!done) {
615 fibril_mutex_lock(&state_lock);
616 while (!cev_valid && !abort_trace)
617 fibril_condvar_wait(&state_cv, &state_lock);
618 fibril_mutex_unlock(&state_lock);
619
620 ev = cev;
621
622 fibril_mutex_lock(&state_lock);
623 cev_valid = false;
624 fibril_condvar_broadcast(&state_cv);
625 fibril_mutex_unlock(&state_lock);
626
627 if (abort_trace)
628 break;
629
630 if (ev.type != KEY_PRESS)
631 continue;
632
633 switch (ev.key) {
634 case KC_Q:
635 done = true;
636 break;
637 case KC_P:
638 printf("Pause...\n");
639 rc = udebug_stop(sess, thash);
640 if (rc != EOK)
641 printf("Error: stop -> %d\n", rc);
642 break;
643 case KC_R:
644 fibril_mutex_lock(&state_lock);
645 paused = false;
646 fibril_condvar_broadcast(&state_cv);
647 fibril_mutex_unlock(&state_lock);
648 printf("Resume...\n");
649 break;
650 default:
651 break;
652 }
653 }
654
655 printf("\nTerminate debugging session...\n");
656 abort_trace = true;
657 udebug_end(sess);
658 async_hangup(sess);
659
660 ipcp_cleanup();
661
662 printf("Done\n");
663 return;
664}
665
666static void main_init(void)
667{
668 proto_t *p;
669 oper_t *o;
670
671 val_type_t arg_def[OPER_MAX_ARGS] = {
672 V_INTEGER,
673 V_INTEGER,
674 V_INTEGER,
675 V_INTEGER,
676 V_INTEGER
677 };
678
679 val_type_t resp_def[OPER_MAX_ARGS] = {
680 V_INTEGER,
681 V_INTEGER,
682 V_INTEGER,
683 V_INTEGER,
684 V_INTEGER
685 };
686
687 next_thread_id = 1;
688 paused = false;
689 cev_valid = false;
690
691 fibril_mutex_initialize(&state_lock);
692 fibril_condvar_initialize(&state_cv);
693
694 proto_init();
695
696 p = proto_new("vfs");
697 o = oper_new("read", 1, arg_def, V_ERRNO, 1, resp_def);
698 proto_add_oper(p, VFS_IN_READ, o);
699 o = oper_new("write", 1, arg_def, V_ERRNO, 1, resp_def);
700 proto_add_oper(p, VFS_IN_WRITE, o);
701 o = oper_new("seek", 3, arg_def, V_ERRNO, 0, resp_def);
702 proto_add_oper(p, VFS_IN_SEEK, o);
703 o = oper_new("truncate", 5, arg_def, V_ERRNO, 0, resp_def);
704 proto_add_oper(p, VFS_IN_TRUNCATE, o);
705 o = oper_new("fstat", 1, arg_def, V_ERRNO, 0, resp_def);
706 proto_add_oper(p, VFS_IN_FSTAT, o);
707 o = oper_new("close", 1, arg_def, V_ERRNO, 0, resp_def);
708 proto_add_oper(p, VFS_IN_CLOSE, o);
709 o = oper_new("mount", 2, arg_def, V_ERRNO, 0, resp_def);
710 proto_add_oper(p, VFS_IN_MOUNT, o);
711/* o = oper_new("unmount", 0, arg_def);
712 proto_add_oper(p, VFS_IN_UNMOUNT, o);*/
713 o = oper_new("sync", 1, arg_def, V_ERRNO, 0, resp_def);
714 proto_add_oper(p, VFS_IN_SYNC, o);
715 o = oper_new("rename", 0, arg_def, V_ERRNO, 0, resp_def);
716 proto_add_oper(p, VFS_IN_RENAME, o);
717 o = oper_new("walk", 2, arg_def, V_INT_ERRNO, 0, resp_def);
718 proto_add_oper(p, VFS_IN_WALK, o);
719 o = oper_new("open2", 2, arg_def, V_ERRNO, 0, resp_def);
720 proto_add_oper(p, VFS_IN_OPEN2, o);
721 o = oper_new("unlink2", 3, arg_def, V_ERRNO, 0, resp_def);
722 proto_add_oper(p, VFS_IN_UNLINK2, o);
723
724 proto_register(SERVICE_VFS, p);
725}
726
727static void print_syntax()
728{
729 printf("Syntax:\n");
730 printf("\ttrace [+<events>] <executable> [<arg1> [...]]\n");
731 printf("or\ttrace [+<events>] -t <task_id>\n");
732 printf("Events: (default is +tp)\n");
733 printf("\n");
734 printf("\tt ... Thread creation and termination\n");
735 printf("\ts ... System calls\n");
736 printf("\ti ... Low-level IPC\n");
737 printf("\tp ... Protocol level\n");
738 printf("\n");
739 printf("Examples:\n");
740 printf("\ttrace +s /app/tetris\n");
741 printf("\ttrace +tsip -t 12\n");
742}
743
744static display_mask_t parse_display_mask(const char *text)
745{
746 display_mask_t dm = 0;
747 const char *c = text;
748
749 while (*c) {
750 switch (*c) {
751 case 't':
752 dm = dm | DM_THREAD;
753 break;
754 case 's':
755 dm = dm | DM_SYSCALL;
756 break;
757 case 'i':
758 dm = dm | DM_IPC;
759 break;
760 case 'p':
761 dm = dm | DM_SYSTEM | DM_USER;
762 break;
763 default:
764 printf("Unexpected event type '%c'.\n", *c);
765 exit(1);
766 }
767
768 ++c;
769 }
770
771 return dm;
772}
773
774static int parse_args(int argc, char *argv[])
775{
776 char *err_p;
777
778 task_id = 0;
779
780 --argc;
781 ++argv;
782
783 while (argc > 0) {
784 char *arg = *argv;
785 if (arg[0] == '+') {
786 display_mask = parse_display_mask(&arg[1]);
787 } else if (arg[0] == '-') {
788 if (arg[1] == 't') {
789 /* Trace an already running task */
790 --argc;
791 ++argv;
792 task_id = strtol(*argv, &err_p, 10);
793 task_ldr = NULL;
794 task_wait_for = false;
795 if (*err_p) {
796 printf("Task ID syntax error\n");
797 print_syntax();
798 return -1;
799 }
800 } else {
801 printf("Uknown option '%c'\n", arg[0]);
802 print_syntax();
803 return -1;
804 }
805 } else {
806 break;
807 }
808
809 --argc;
810 ++argv;
811 }
812
813 if (task_id != 0) {
814 if (argc == 0)
815 return 0;
816 printf("Extra arguments\n");
817 print_syntax();
818 return -1;
819 }
820
821 if (argc < 1) {
822 printf("Missing argument\n");
823 print_syntax();
824 return -1;
825 }
826
827 /* Preload the specified program file. */
828 printf("Spawning '%s' with arguments:\n", *argv);
829
830 char **cp = argv;
831 while (*cp)
832 printf("'%s'\n", *cp++);
833
834 task_ldr = preload_task(*argv, argv, &task_id);
835 task_wait_for = true;
836
837 return 0;
838}
839
840int main(int argc, char *argv[])
841{
842 int rc;
843 task_exit_t texit;
844 int retval;
845
846 printf("System Call / IPC Tracer\n");
847 printf("Controls: Q - Quit, P - Pause, R - Resume\n");
848
849 display_mask = DM_THREAD | DM_SYSTEM | DM_USER;
850
851 if (parse_args(argc, argv) < 0)
852 return 1;
853
854 main_init();
855
856 rc = connect_task(task_id);
857 if (rc < 0) {
858 printf("Failed connecting to task %" PRIu64 ".\n", task_id);
859 return 1;
860 }
861
862 printf("Connected to task %" PRIu64 ".\n", task_id);
863
864 if (task_ldr != NULL)
865 program_run();
866
867 cev_fibril_start();
868 trace_task(task_id);
869
870 if (task_wait_for) {
871 printf("Waiting for task to exit.\n");
872
873 rc = task_wait(task_id, &texit, &retval);
874 if (rc != EOK) {
875 printf("Failed waiting for task.\n");
876 return -1;
877 }
878
879 if (texit == TASK_EXIT_NORMAL) {
880 printf("Task exited normally, return value %d.\n",
881 retval);
882 } else {
883 printf("Task exited unexpectedly.\n");
884 }
885 }
886
887 return 0;
888}
889
890/** @}
891 */
Note: See TracBrowser for help on using the repository browser.