Subversion Repositories HelenOS

Rev

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