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

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

style: Remove trailing whitespace on non-empty lines, in certain file types.

Command used: tools/srepl '\([^[:space:]]\)\s\+$' '\1' -- *.c *.h *.py *.sh *.s *.S *.ag

  • 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 sysarg_t phoneid;
285
286 if (sc_rc != EOK)
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, 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(sc_args[0], &call, 0);
314 }
315}
316
317static void sc_ipc_wait(sysarg_t *sc_args, int 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, 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.