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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ccfe9c3 was 1c635d6, checked in by Martin Sucha <sucha14@…>, 11 years ago

Do not hold a task's return value after it has disconnected.

Holding the task's return value meant that if nobody waited
for task's result, it polluted NS's memory. This was apparently
done because of a race between spawning a task and waiting for it.

We solve this problem in another way: ns discards the return value
as soon as the task disconnects from it. This typically happens
when the task finishes its execution. In order to avoid the race,
we send the wait request to ns while spawning the task (i.e. when
we talk to the loader), but before we allow the loaded program
to run.

Fixes #132

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