source: mainline/uspace/app/trace/trace.c@ 1abcf1d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1abcf1d was 1433ecda, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Fix cstyle: make ccheck-fix and commit only files where all the changes are good.

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