source: mainline/uspace/app/trace/trace.c@ 2aeec8ef

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

Rework the way how open files are passed from parent task to child.

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