Subversion Repositories HelenOS

Rev

Rev 4584 | Rev 4654 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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