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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f019cc07 was f019cc07, checked in by Jiri Svoboda <jirik.svoboda@…>, 16 years ago

More warnings.

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