Subversion Repositories HelenOS

Rev

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