source: mainline/uspace/app/trace/trace.c@ 48974d6

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 48974d6 was eadaeae8, checked in by Jakub Jermar <jakub@…>, 8 years ago

Make capability handles type-safe

Define distinct pointer types for the handles of the supported
capability types and use them instead of integer handles. This makes it
virtually impossible to pass a non-handle or a handle of different type
instead of the proper handle. Also turn cap_handle_t into an "untyped"
capability handle that can be assigned to and from the "typed" handles.

This commit also fixes a bug in msim-con driver, which wrongly used the
IRQ number instead of the IRQ capability handle to unregister the IRQ.

This commit also fixes the wrong use of the capability handle instead
of error code in libusbhost.

  • Property mode set to 100644
File size: 18.4 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 <stdbool.h>
38#include <stdint.h>
39#include <stddef.h>
40#include <str_error.h>
41#include <inttypes.h>
42#include <fibril.h>
43#include <errno.h>
44#include <udebug.h>
45#include <async.h>
46#include <task.h>
47#include <mem.h>
48#include <str.h>
49#include <loader/loader.h>
50#include <io/console.h>
51#include <io/keycode.h>
52#include <fibril_synch.h>
53#include <vfs/vfs.h>
54
55#include <libc.h>
56
57/* Temporary: service and method names */
58#include "proto.h"
59#include <ipc/services.h>
60#include <ipc/vfs.h>
61#include <ipc/console.h>
62
63#include "syscalls.h"
64#include "ipcp.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 errno_t program_run_fibril(void *arg);
96static errno_t 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 errno_t program_run_fibril(void *arg)
125{
126 errno_t 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 != EOK) {
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 errno_t 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 ") -> %s ", task_id, str_error_name(errno));
160 return errno;
161 }
162
163 errno_t rc = udebug_begin(ksess);
164 if (rc != EOK) {
165 printf("udebug_begin() -> %s\n", str_error_name(rc));
166 return rc;
167 }
168
169 rc = udebug_set_evmask(ksess, UDEBUG_EM_ALL);
170 if (rc != EOK) {
171 printf("udebug_set_evmask(0x%x) -> %s\n ", UDEBUG_EM_ALL, str_error_name(rc));
172 return rc;
173 }
174
175 sess = ksess;
176 return 0;
177}
178
179static errno_t get_thread_list(void)
180{
181 errno_t 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 != EOK) {
189 printf("udebug_thread_read() -> %s\n", str_error_name(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 str_error_name((errno_t) sval),
228 str_error((errno_t) sval));
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 str_error_name((errno_t) sval),
237 str_error((errno_t) sval));
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, errno_t sc_rc)
282{
283 ipc_call_t call;
284 cap_phone_handle_t phandle;
285
286 if (sc_rc != EOK)
287 return;
288
289 phandle = (cap_phone_handle_t) 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(phandle, &call, 0);
299}
300
301static void sc_ipc_call_async_slow(sysarg_t *sc_args, errno_t sc_rc)
302{
303 ipc_call_t call;
304 errno_t rc;
305
306 if (sc_rc != EOK)
307 return;
308
309 memset(&call, 0, sizeof(call));
310 rc = udebug_mem_read(sess, &call.args, sc_args[1], sizeof(call.args));
311
312 if (rc == EOK) {
313 ipcp_call_out((cap_phone_handle_t) sc_args[0], &call, 0);
314 }
315}
316
317static void sc_ipc_wait(sysarg_t *sc_args, cap_call_handle_t sc_rc)
318{
319 ipc_call_t call;
320 errno_t rc;
321
322 if (sc_rc == 0) return;
323
324 memset(&call, 0, sizeof(call));
325 rc = udebug_mem_read(sess, &call, sc_args[0], sizeof(call));
326
327 if (rc == EOK)
328 ipcp_call_in(&call, sc_rc);
329}
330
331static void event_syscall_b(unsigned thread_id, uintptr_t thread_hash,
332 unsigned sc_id, sysarg_t sc_rc)
333{
334 sysarg_t sc_args[6];
335 errno_t rc;
336
337 /* Read syscall arguments */
338 rc = udebug_args_read(sess, thread_hash, sc_args);
339
340 if (rc != EOK) {
341 printf("error\n");
342 return;
343 }
344
345 if ((display_mask & DM_SYSCALL) != 0) {
346 /* Print syscall name and arguments */
347 if (syscall_desc_defined(sc_id)) {
348 printf("%s", syscall_desc[sc_id].name);
349 print_sc_args(sc_args, syscall_desc[sc_id].n_args);
350 }
351 else {
352 printf("unknown_syscall<%d>", sc_id);
353 print_sc_args(sc_args, 6);
354 }
355 }
356}
357
358static void event_syscall_e(unsigned thread_id, uintptr_t thread_hash,
359 unsigned sc_id, sysarg_t sc_rc)
360{
361 sysarg_t sc_args[6];
362 int rv_type;
363 errno_t rc;
364
365 /* Read syscall arguments */
366 rc = udebug_args_read(sess, thread_hash, sc_args);
367
368// printf("[%d] ", thread_id);
369
370 if (rc != EOK) {
371 printf("error\n");
372 return;
373 }
374
375 if ((display_mask & DM_SYSCALL) != 0) {
376 /* Print syscall return value */
377 if (syscall_desc_defined(sc_id))
378 rv_type = syscall_desc[sc_id].rv_type;
379 else
380 rv_type = V_PTR;
381 print_sc_retval(sc_rc, rv_type);
382 }
383
384 switch (sc_id) {
385 case SYS_IPC_CALL_ASYNC_FAST:
386 sc_ipc_call_async_fast(sc_args, (errno_t) sc_rc);
387 break;
388 case SYS_IPC_CALL_ASYNC_SLOW:
389 sc_ipc_call_async_slow(sc_args, (errno_t) sc_rc);
390 break;
391 case SYS_IPC_WAIT:
392 sc_ipc_wait(sc_args, (cap_call_handle_t) sc_rc);
393 break;
394 default:
395 break;
396 }
397}
398
399static void event_thread_b(uintptr_t hash)
400{
401 printf("New thread, hash %p\n", (void *) hash);
402 thread_trace_start(hash);
403}
404
405static errno_t trace_loop(void *thread_hash_arg)
406{
407 errno_t rc;
408 unsigned ev_type;
409 uintptr_t thread_hash;
410 unsigned thread_id;
411 sysarg_t val0, val1;
412
413 thread_hash = (uintptr_t)thread_hash_arg;
414 thread_id = next_thread_id++;
415 if (thread_id >= THBUF_SIZE) {
416 printf("Too many threads.\n");
417 return ELIMIT;
418 }
419
420 printf("Start tracing thread [%u] (hash %p).\n",
421 thread_id, (void *) thread_hash);
422
423 while (!abort_trace) {
424
425 fibril_mutex_lock(&state_lock);
426 if (paused) {
427 printf("Thread [%u] paused. Press R to resume.\n",
428 thread_id);
429
430 while (paused)
431 fibril_condvar_wait(&state_cv, &state_lock);
432
433 printf("Thread [%u] resumed.\n", thread_id);
434 }
435 fibril_mutex_unlock(&state_lock);
436
437 /* Run thread until an event occurs */
438 rc = udebug_go(sess, thread_hash,
439 &ev_type, &val0, &val1);
440
441// printf("rc = %d, ev_type=%d\n", rc, ev_type);
442 if (ev_type == UDEBUG_EVENT_FINISHED) {
443 /* Done tracing this thread */
444 break;
445 }
446
447 if (rc == EOK) {
448 switch (ev_type) {
449 case UDEBUG_EVENT_SYSCALL_B:
450 event_syscall_b(thread_id, thread_hash, val0, (int)val1);
451 break;
452 case UDEBUG_EVENT_SYSCALL_E:
453 event_syscall_e(thread_id, thread_hash, val0, (int)val1);
454 break;
455 case UDEBUG_EVENT_STOP:
456 printf("Stop event\n");
457 fibril_mutex_lock(&state_lock);
458 paused = true;
459 fibril_mutex_unlock(&state_lock);
460 break;
461 case UDEBUG_EVENT_THREAD_B:
462 event_thread_b(val0);
463 break;
464 case UDEBUG_EVENT_THREAD_E:
465 printf("Thread %" PRIun " exited.\n", val0);
466 fibril_mutex_lock(&state_lock);
467 abort_trace = true;
468 fibril_condvar_broadcast(&state_cv);
469 fibril_mutex_unlock(&state_lock);
470 break;
471 default:
472 printf("Unknown event type %d.\n", ev_type);
473 break;
474 }
475 }
476
477 }
478
479 printf("Finished tracing thread [%d].\n", thread_id);
480 return 0;
481}
482
483void thread_trace_start(uintptr_t thread_hash)
484{
485 fid_t fid;
486
487 thash = thread_hash;
488
489 fid = fibril_create(trace_loop, (void *)thread_hash);
490 if (fid == 0) {
491 printf("Warning: Failed creating fibril\n");
492 }
493 fibril_add_ready(fid);
494}
495
496static loader_t *preload_task(const char *path, char **argv,
497 task_id_t *task_id)
498{
499 loader_t *ldr;
500 errno_t rc;
501
502 /* Spawn a program loader */
503 ldr = loader_connect();
504 if (ldr == NULL)
505 return NULL;
506
507 /* Get task ID. */
508 rc = loader_get_task_id(ldr, task_id);
509 if (rc != EOK)
510 goto error;
511
512 /* Send program. */
513 rc = loader_set_program_path(ldr, path);
514 if (rc != EOK)
515 goto error;
516
517 /* Send arguments */
518 rc = loader_set_args(ldr, (const char **) argv);
519 if (rc != EOK)
520 goto error;
521
522 /* Send default files */
523 int fd_root;
524 int fd_stdin;
525 int fd_stdout;
526 int fd_stderr;
527
528 fd_root = vfs_root();
529 if (fd_root >= 0) {
530 rc = loader_add_inbox(ldr, "root", fd_root);
531 vfs_put(fd_root);
532 if (rc != EOK)
533 goto error;
534 }
535
536 if ((stdin != NULL) && (vfs_fhandle(stdin, &fd_stdin) == EOK)) {
537 rc = loader_add_inbox(ldr, "stdin", fd_stdin);
538 if (rc != EOK)
539 goto error;
540 }
541
542 if ((stdout != NULL) && (vfs_fhandle(stdout, &fd_stdout) == EOK)) {
543 rc = loader_add_inbox(ldr, "stdout", fd_stdout);
544 if (rc != EOK)
545 goto error;
546 }
547
548 if ((stderr != NULL) && (vfs_fhandle(stderr, &fd_stderr) == EOK)) {
549 rc = loader_add_inbox(ldr, "stderr", fd_stderr);
550 if (rc != EOK)
551 goto error;
552 }
553
554 /* Load the program. */
555 rc = loader_load_program(ldr);
556 if (rc != EOK)
557 goto error;
558
559 /* Success */
560 return ldr;
561
562 /* Error exit */
563error:
564 loader_abort(ldr);
565 return NULL;
566}
567
568static errno_t cev_fibril(void *arg)
569{
570 cons_event_t event;
571
572 (void) arg;
573
574 console_ctrl_t *console = console_init(stdin, stdout);
575
576 while (true) {
577 fibril_mutex_lock(&state_lock);
578 while (cev_valid)
579 fibril_condvar_wait(&state_cv, &state_lock);
580 fibril_mutex_unlock(&state_lock);
581
582 if (!console_get_event(console, &event))
583 return EINVAL;
584
585 if (event.type == CEV_KEY) {
586 fibril_mutex_lock(&state_lock);
587 cev = event.ev.key;
588 cev_valid = true;
589 fibril_condvar_broadcast(&state_cv);
590 fibril_mutex_unlock(&state_lock);
591 }
592 }
593}
594
595static void trace_task(task_id_t task_id)
596{
597 kbd_event_t ev;
598 bool done;
599 int i;
600 errno_t rc;
601
602 ipcp_init();
603
604 rc = get_thread_list();
605 if (rc != EOK) {
606 printf("Failed to get thread list (%s)\n", str_error(rc));
607 return;
608 }
609
610 abort_trace = false;
611
612 for (i = 0; i < n_threads; i++) {
613 thread_trace_start(thread_hash_buf[i]);
614 }
615
616 done = false;
617
618 while (!done) {
619 fibril_mutex_lock(&state_lock);
620 while (!cev_valid && !abort_trace)
621 fibril_condvar_wait(&state_cv, &state_lock);
622 fibril_mutex_unlock(&state_lock);
623
624 ev = cev;
625
626 fibril_mutex_lock(&state_lock);
627 cev_valid = false;
628 fibril_condvar_broadcast(&state_cv);
629 fibril_mutex_unlock(&state_lock);
630
631 if (abort_trace)
632 break;
633
634 if (ev.type != KEY_PRESS)
635 continue;
636
637 switch (ev.key) {
638 case KC_Q:
639 done = true;
640 break;
641 case KC_P:
642 printf("Pause...\n");
643 rc = udebug_stop(sess, thash);
644 if (rc != EOK)
645 printf("Error: stop -> %s\n", str_error_name(rc));
646 break;
647 case KC_R:
648 fibril_mutex_lock(&state_lock);
649 paused = false;
650 fibril_condvar_broadcast(&state_cv);
651 fibril_mutex_unlock(&state_lock);
652 printf("Resume...\n");
653 break;
654 default:
655 break;
656 }
657 }
658
659 printf("\nTerminate debugging session...\n");
660 abort_trace = true;
661 udebug_end(sess);
662 async_hangup(sess);
663
664 ipcp_cleanup();
665
666 printf("Done\n");
667 return;
668}
669
670static void main_init(void)
671{
672 proto_t *p;
673 oper_t *o;
674
675 val_type_t arg_def[OPER_MAX_ARGS] = {
676 V_INTEGER,
677 V_INTEGER,
678 V_INTEGER,
679 V_INTEGER,
680 V_INTEGER
681 };
682
683 val_type_t resp_def[OPER_MAX_ARGS] = {
684 V_INTEGER,
685 V_INTEGER,
686 V_INTEGER,
687 V_INTEGER,
688 V_INTEGER
689 };
690
691 next_thread_id = 1;
692 paused = false;
693 cev_valid = false;
694
695 fibril_mutex_initialize(&state_lock);
696 fibril_condvar_initialize(&state_cv);
697
698 proto_init();
699
700 p = proto_new("vfs");
701 o = oper_new("read", 3, arg_def, V_ERRNO, 1, resp_def);
702 proto_add_oper(p, VFS_IN_READ, o);
703 o = oper_new("write", 3, arg_def, V_ERRNO, 1, resp_def);
704 proto_add_oper(p, VFS_IN_WRITE, o);
705 o = oper_new("vfs_resize", 5, arg_def, V_ERRNO, 0, resp_def);
706 proto_add_oper(p, VFS_IN_RESIZE, o);
707 o = oper_new("vfs_stat", 1, arg_def, V_ERRNO, 0, resp_def);
708 proto_add_oper(p, VFS_IN_STAT, o);
709 o = oper_new("vfs_put", 1, arg_def, V_ERRNO, 0, resp_def);
710 proto_add_oper(p, VFS_IN_PUT, o);
711 o = oper_new("vfs_mount", 2, arg_def, V_ERRNO, 0, resp_def);
712 proto_add_oper(p, VFS_IN_MOUNT, o);
713/* o = oper_new("unmount", 0, arg_def);
714 proto_add_oper(p, VFS_IN_UNMOUNT, o);*/
715 o = oper_new("vfs_sync", 1, arg_def, V_ERRNO, 0, resp_def);
716 proto_add_oper(p, VFS_IN_SYNC, o);
717 o = oper_new("rename", 0, arg_def, V_ERRNO, 0, resp_def);
718 proto_add_oper(p, VFS_IN_RENAME, o);
719 o = oper_new("vfs_statfs", 0, arg_def, V_ERRNO, 0, resp_def);
720 proto_add_oper(p, VFS_IN_STATFS, o);
721 o = oper_new("vfs_walk", 2, arg_def, V_INT_ERRNO, 0, resp_def);
722 proto_add_oper(p, VFS_IN_WALK, o);
723 o = oper_new("vfs_open", 2, arg_def, V_ERRNO, 0, resp_def);
724 proto_add_oper(p, VFS_IN_OPEN, o);
725 o = oper_new("vfs_unlink", 3, arg_def, V_ERRNO, 0, resp_def);
726 proto_add_oper(p, VFS_IN_UNLINK, o);
727
728 proto_register(SERVICE_VFS, p);
729}
730
731static void print_syntax(void)
732{
733 printf("Syntax:\n");
734 printf("\ttrace [+<events>] <executable> [<arg1> [...]]\n");
735 printf("or\ttrace [+<events>] -t <task_id>\n");
736 printf("Events: (default is +tp)\n");
737 printf("\n");
738 printf("\tt ... Thread creation and termination\n");
739 printf("\ts ... System calls\n");
740 printf("\ti ... Low-level IPC\n");
741 printf("\tp ... Protocol level\n");
742 printf("\n");
743 printf("Examples:\n");
744 printf("\ttrace +s /app/tetris\n");
745 printf("\ttrace +tsip -t 12\n");
746}
747
748static display_mask_t parse_display_mask(const char *text)
749{
750 display_mask_t dm = 0;
751 const char *c = text;
752
753 while (*c) {
754 switch (*c) {
755 case 't':
756 dm = dm | DM_THREAD;
757 break;
758 case 's':
759 dm = dm | DM_SYSCALL;
760 break;
761 case 'i':
762 dm = dm | DM_IPC;
763 break;
764 case 'p':
765 dm = dm | DM_SYSTEM | DM_USER;
766 break;
767 default:
768 printf("Unexpected event type '%c'.\n", *c);
769 exit(1);
770 }
771
772 ++c;
773 }
774
775 return dm;
776}
777
778static int parse_args(int argc, char *argv[])
779{
780 char *err_p;
781
782 task_id = 0;
783
784 --argc;
785 ++argv;
786
787 while (argc > 0) {
788 char *arg = *argv;
789 if (arg[0] == '+') {
790 display_mask = parse_display_mask(&arg[1]);
791 } else if (arg[0] == '-') {
792 if (arg[1] == 't') {
793 /* Trace an already running task */
794 --argc;
795 ++argv;
796 task_id = strtol(*argv, &err_p, 10);
797 task_ldr = NULL;
798 task_wait_for = false;
799 if (*err_p) {
800 printf("Task ID syntax error\n");
801 print_syntax();
802 return -1;
803 }
804 } else {
805 printf("Uknown option '%c'\n", arg[0]);
806 print_syntax();
807 return -1;
808 }
809 } else {
810 break;
811 }
812
813 --argc;
814 ++argv;
815 }
816
817 if (task_id != 0) {
818 if (argc == 0)
819 return 0;
820 printf("Extra arguments\n");
821 print_syntax();
822 return -1;
823 }
824
825 if (argc < 1) {
826 printf("Missing argument\n");
827 print_syntax();
828 return -1;
829 }
830
831 /* Preload the specified program file. */
832 printf("Spawning '%s' with arguments:\n", *argv);
833
834 char **cp = argv;
835 while (*cp)
836 printf("'%s'\n", *cp++);
837
838 task_ldr = preload_task(*argv, argv, &task_id);
839 task_wait_for = true;
840
841 return 0;
842}
843
844int main(int argc, char *argv[])
845{
846 errno_t rc;
847 task_exit_t texit;
848 int retval;
849
850 printf("System Call / IPC Tracer\n");
851 printf("Controls: Q - Quit, P - Pause, R - Resume\n");
852
853 display_mask = DM_THREAD | DM_SYSTEM | DM_USER;
854
855 if (parse_args(argc, argv) < 0)
856 return 1;
857
858 main_init();
859
860 rc = connect_task(task_id);
861 if (rc != EOK) {
862 printf("Failed connecting to task %" PRIu64 ".\n", task_id);
863 return 1;
864 }
865
866 printf("Connected to task %" PRIu64 ".\n", task_id);
867
868 if (task_ldr != NULL)
869 program_run();
870
871 cev_fibril_start();
872 trace_task(task_id);
873
874 if (task_wait_for) {
875 printf("Waiting for task to exit.\n");
876
877 rc = task_wait_task_id(task_id, &texit, &retval);
878 if (rc != EOK) {
879 printf("Failed waiting for task.\n");
880 return -1;
881 }
882
883 if (texit == TASK_EXIT_NORMAL) {
884 printf("Task exited normally, return value %d.\n",
885 retval);
886 } else {
887 printf("Task exited unexpectedly.\n");
888 }
889 }
890
891 return 0;
892}
893
894/** @}
895 */
Note: See TracBrowser for help on using the repository browser.