source: mainline/uspace/app/trace/trace.c@ 5462a30

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

Remove accidentally commited debugging messages.

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