Subversion Repositories HelenOS

Rev

Rev 4656 | Rev 4658 | 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. #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
  65. uintptr_t thread_hash_buf[THBUF_SIZE];
  66. int n_threads;
  67.  
  68. int next_thread_id;
  69.  
  70. int phoneid;
  71. int abort_trace;
  72.  
  73. uintptr_t thash;
  74. volatile int paused;
  75. fibril_condvar_t state_cv;
  76. fibril_mutex_t state_lock;
  77.  
  78. int cev_valid;
  79. console_event_t cev;
  80.  
  81. void thread_trace_start(uintptr_t thread_hash);
  82.  
  83. static proto_t *proto_console;
  84. static task_id_t task_id;
  85. static loader_t *task_ldr;
  86.  
  87. /** Combination of events/data to print. */
  88. display_mask_t display_mask;
  89.  
  90. static int program_run_fibril(void *arg);
  91. static int cev_fibril(void *arg);
  92.  
  93. static 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.  
  106. static 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.  
  119. static 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.  
  141. static 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.  
  178. static 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.  
  203. void 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.  
  257. static 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.  
  264. static 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.  
  276. static 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.  
  296. static 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.  
  312. static 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.  
  340. static 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.  
  358. static 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.  
  375. static 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.  
  403. static 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.  
  452. static 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.  
  461. static 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.  
  534. void 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.  
  547. static 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 */
  609. error:
  610.     loader_abort(ldr);
  611.     free(ldr);
  612.     return NULL;
  613. }
  614.  
  615. static 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.  
  635. static 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.  
  714. static 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.  
  803. static 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.  
  820. static 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.  
  844. static 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.  
  904. int 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.  */
  938.