Subversion Repositories HelenOS

Rev

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

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