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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fafb8e5 was fafb8e5, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 years ago

Mechanically lowercase IPC_SET_*/IPC_GET_*

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