Subversion Repositories HelenOS

Rev

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