Subversion Repositories HelenOS

Rev

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

  1. /** @addtogroup sctrace
  2.  * @{
  3.  */
  4. /** @file
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <unistd.h>
  10. #include <syscall.h>
  11. #include <ipc/ipc.h>
  12. #include <fibril.h>
  13. #include <errno.h>
  14. #include <udebug.h>
  15. #include <async.h>
  16.  
  17. // Temporary: service and method names
  18. #include "proto.h"
  19. #include <ipc/services.h>
  20. #include "../../srv/vfs/vfs.h"
  21.  
  22. #include "syscalls.h"
  23. #include "ipcp.h"
  24. #include "errors.h"
  25. #include "debug_api.h"
  26.  
  27. #define THBUF_SIZE 64
  28. unsigned thread_hash_buf[THBUF_SIZE];
  29. unsigned n_threads;
  30.  
  31. int next_thread_id;
  32.  
  33. int phoneid;
  34. int abort_trace;
  35.  
  36. void thread_trace_start(unsigned thread_hash);
  37.  
  38.  
  39. int task_connect(int taskid)
  40. {
  41.     int rc;
  42.  
  43.     printf("ipc_connect_task(%d)...\n", taskid);
  44.     rc = ipc_connect_kbox(taskid);
  45.     printf("-> %d\n", rc);
  46.     phoneid = rc;
  47.     if (rc < 0) return rc;
  48.  
  49.     printf("debug_begin()\n");
  50.     rc = debug_begin(phoneid);
  51.     printf("-> %d\n", rc);
  52.     if (rc < 0) return rc;
  53.  
  54.     return 0;
  55. }
  56.  
  57. int get_thread_list(void)
  58. {
  59.     int rc;
  60.     int tb_copied;
  61.     int tb_needed;
  62.     int i;
  63.  
  64.  
  65.     printf("send IPC_M_DEBUG_THREAD_READ message\n");
  66.     rc = debug_thread_read(phoneid, (unsigned)thread_hash_buf,
  67.         THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed);
  68.     printf("-> %d\n", rc);
  69.     if (rc < 0) return rc;
  70.  
  71.     n_threads = tb_copied / sizeof(unsigned);
  72.  
  73.     printf("thread IDs:");
  74.     for (i=0; i<n_threads; i++) {
  75.         printf(" %u", thread_hash_buf[i]);
  76.     }
  77.     printf("\ntotal of %u threads\n", tb_needed/sizeof(unsigned));
  78.  
  79.     return 0;
  80. }
  81.  
  82. void print_sc_retval(int retval, rv_type_t rv_type)
  83. {
  84.     printf (" -> ");
  85.     if (rv_type == RV_INTEGER) {
  86.         printf("%d", retval);
  87.     } else if (rv_type == RV_HASH) {
  88.         printf("0x%08x", retval);
  89.     } else if (rv_type == RV_ERRNO) {
  90.         if (retval >= -15 && retval <= 0) {
  91.             printf("%d %s (%s)", retval,
  92.                 err_desc[retval].name,
  93.                 err_desc[retval].desc);
  94.         } else {
  95.             printf("%d", retval);
  96.         }
  97.     } else if (rv_type == RV_INT_ERRNO) {
  98.         if (retval >= -15 && retval < 0) {
  99.             printf("%d %s (%s)", retval,
  100.                 err_desc[retval].name,
  101.                 err_desc[retval].desc);
  102.         } else {
  103.             printf("%d", retval);
  104.         }
  105.     }
  106.     putchar('\n');
  107. }
  108.  
  109. void print_sc_args(unsigned *sc_args, int n)
  110. {
  111.     int i;
  112.  
  113.     putchar('(');
  114.     if (n > 0) printf("%d", sc_args[0]);
  115.     for (i=1; i<n; i++) {
  116.         printf(", %d", sc_args[i]);
  117.     }
  118.     putchar(')');
  119. }
  120.  
  121. void sc_ipc_call_async_fast(unsigned *sc_args, int sc_rc)
  122. {
  123.     ipc_call_t call;
  124.     int phoneid;
  125.    
  126.     if (sc_rc == IPC_CALLRET_FATAL || sc_rc == IPC_CALLRET_TEMPORARY)
  127.         return;
  128.  
  129.     phoneid = sc_args[0];
  130.  
  131.     IPC_SET_METHOD(call, sc_args[1]);
  132.     IPC_SET_ARG1(call, sc_args[2]);
  133.     IPC_SET_ARG2(call, sc_args[3]);
  134.     IPC_SET_ARG3(call, sc_args[4]);
  135.     IPC_SET_ARG4(call, sc_args[5]);
  136.     IPC_SET_ARG5(call, 0);
  137.  
  138.     ipcp_call_out(phoneid, &call, sc_rc);
  139. }
  140.  
  141. void sc_ipc_call_async_slow(unsigned *sc_args, int sc_rc)
  142. {
  143.     ipc_call_t call;
  144.     int rc;
  145.  
  146.     if (sc_rc == IPC_CALLRET_FATAL || sc_rc == IPC_CALLRET_TEMPORARY)
  147.         return;
  148.  
  149.     memset(&call, 0, sizeof(call));
  150.     rc = debug_mem_read(phoneid, &call.args, sc_args[1], sizeof(call.args));
  151.  
  152.     if (rc >= 0) {
  153.         ipcp_call_out(sc_args[0], &call, sc_rc);
  154.     }
  155. }
  156.  
  157. void sc_ipc_call_sync_fast(unsigned *sc_args)
  158. {
  159.     ipc_call_t question, reply;
  160.     int rc;
  161.     int phoneidx;
  162.  
  163. //  printf("sc_ipc_call_sync_fast()\n");
  164.     phoneidx = sc_args[0];
  165.  
  166.     IPC_SET_METHOD(question, sc_args[1]);
  167.     IPC_SET_ARG1(question, sc_args[2]);
  168.     IPC_SET_ARG2(question, sc_args[3]);
  169.     IPC_SET_ARG3(question, sc_args[4]);
  170.     IPC_SET_ARG4(question, 0);
  171.     IPC_SET_ARG5(question, 0);
  172.  
  173. //  printf("memset\n");
  174.     memset(&reply, 0, sizeof(reply));
  175. //  printf("debug_mem_read(phone=%d, buffer_ptr=%u, src_addr=%d, n=%d\n",
  176. //      phoneid, &reply.args, sc_args[5], sizeof(reply.args));
  177.     rc = debug_mem_read(phoneid, &reply.args, sc_args[5], sizeof(reply.args));
  178. //  printf("dmr->%d\n", rc);
  179.     if (rc < 0) return;
  180.  
  181. //  printf("call ipc_call_sync\n");
  182.     ipcp_call_sync(phoneidx, &question, &reply);
  183. }
  184.  
  185. void sc_ipc_call_sync_slow(unsigned *sc_args)
  186. {
  187.     ipc_call_t question, reply;
  188.     int rc;
  189.  
  190.     memset(&question, 0, sizeof(question));
  191.     rc = debug_mem_read(phoneid, &question.args, sc_args[1], sizeof(question.args));
  192.     printf("dmr->%d\n", rc);
  193.     if (rc < 0) return;
  194.  
  195.     memset(&reply, 0, sizeof(reply));
  196.     rc = debug_mem_read(phoneid, &reply.args, sc_args[2], sizeof(reply.args));
  197.     printf("dmr->%d\n", rc);
  198.     if (rc < 0) return;
  199.  
  200.     ipcp_call_sync(sc_args[0], &question, &reply);
  201. }
  202.  
  203. void sc_ipc_wait(unsigned *sc_args, int sc_rc)
  204. {
  205.     ipc_call_t call;
  206.     int rc;
  207.  
  208.     if (sc_rc == 0) return 0;
  209.  
  210.     memset(&call, 0, sizeof(call));
  211.     rc = debug_mem_read(phoneid, &call, sc_args[0], sizeof(call));
  212. //  printf("debug_mem_read(phone %d, dest %d, app-mem src %d, size %d -> %d\n",
  213. //      phoneid, (int)&call, sc_args[0], sizeof(call), rc);
  214.  
  215.     if (rc >= 0) {
  216.         ipcp_call_in(&call, sc_rc);
  217.     }
  218. }
  219.  
  220. void event_syscall(unsigned thread_id, unsigned thread_hash,  unsigned sc_id, int sc_rc)
  221. {
  222.     unsigned sc_args[6];
  223.     int rv_type;
  224.     int rc;
  225.  
  226.     /* Read syscall arguments */
  227.     rc = debug_args_read(phoneid, thread_hash, sc_args);
  228.  
  229.     async_serialize_start();
  230.  
  231. //  printf("[%d] ", thread_id);
  232.  
  233.     if (rc < 0) {
  234.         printf("error\n");
  235.         async_serialize_end();
  236.         return;
  237.     }
  238.  
  239.     /* Print syscall name, id and arguments */
  240.     printf("%s", syscall_desc[sc_id].name);
  241.     print_sc_args(sc_args, syscall_desc[sc_id].n_args);
  242.     rv_type = syscall_desc[sc_id].rv_type;
  243.     print_sc_retval(sc_rc, rv_type);
  244.  
  245.     switch (sc_id) {
  246.     case SYS_IPC_CALL_ASYNC_FAST:
  247.         sc_ipc_call_async_fast(sc_args, sc_rc);
  248.         break;
  249.     case SYS_IPC_CALL_ASYNC_SLOW:
  250.         sc_ipc_call_async_slow(sc_args, sc_rc);
  251.         break;
  252.     case SYS_IPC_CALL_SYNC_FAST:
  253.         sc_ipc_call_sync_fast(sc_args);
  254.         break;
  255.     case SYS_IPC_CALL_SYNC_SLOW:
  256.         sc_ipc_call_sync_slow(sc_args);
  257.         break;
  258.     case SYS_IPC_WAIT:
  259.         sc_ipc_wait(sc_args, sc_rc);
  260.         break;
  261.     default:
  262.         break;
  263.     }
  264.  
  265.     async_serialize_end();
  266. }
  267.  
  268. void event_new_thread(unsigned hash)
  269. {
  270.     async_serialize_start();
  271.     printf("new thread, hash 0x%x\n", hash);
  272.     async_serialize_end();
  273.  
  274.     thread_trace_start(hash);
  275. }
  276.  
  277. void trace_loop(void *thread_hash_arg)
  278. {
  279.     int rc;
  280.     unsigned ev_type;
  281.     unsigned thread_hash;
  282.     unsigned thread_id;
  283.     unsigned val0, val1;
  284.  
  285.     thread_hash = (unsigned)thread_hash_arg;
  286.     thread_id = next_thread_id++;
  287.  
  288.     printf("trace_loop(%d)\n", thread_id); 
  289.  
  290.     while (!abort_trace) {
  291.  
  292.         /* Run thread until an event occurs */
  293.         rc = debug_go(phoneid, thread_hash,
  294.             &ev_type, &val0, &val1);
  295.  
  296. //      printf("rc = %d, ev_type=%d\n", rc, ev_type);
  297.         if (ev_type == UDEBUG_EVENT_FINISHED) {
  298.             printf("thread %u debugging finished\n", thread_id);
  299.             break;
  300.         }
  301.  
  302.         if (rc >= 0) {
  303.             switch (ev_type) {
  304.             case UDEBUG_EVENT_SYSCALL:
  305.                 event_syscall(thread_id, thread_hash, val0, (int)val1);
  306.                 break;
  307.             case UDEBUG_EVENT_NEW_THREAD:
  308.                 event_new_thread(val0);
  309.                 break;
  310.             default:
  311.                 printf("unknown event type %d\n", ev_type);
  312.                 break;
  313.             }
  314.         }
  315.  
  316.     }
  317.  
  318.     printf("trace_loop(%d) exiting\n", thread_id);
  319. }
  320.  
  321. void thread_trace_start(unsigned thread_hash)
  322. {
  323.     fid_t fid;
  324.  
  325.     fid = fibril_create(trace_loop, (void *)thread_hash);
  326.     if (fid == 0) {
  327.         printf("Warning: Failed creating fibril\n");
  328.     }
  329.     fibril_add_ready(fid);
  330. }
  331.  
  332. void trace_active_task(void)
  333. {
  334.     int taskid;
  335.     int i;
  336.     int rc;
  337.  
  338.     printf("Syscall Tracer\n");
  339.     printf("Press 'c' to connect\n");
  340.     while ((i = getchar()) != 'c')
  341.         putchar(i);
  342.  
  343.     taskid = 14;
  344.     rc = task_connect(taskid);
  345.     if (rc < 0) {
  346.         printf("Failed to connect to task %d\n", taskid);
  347.         return;
  348.     }
  349.  
  350.     printf("Connected to task %d\n", taskid);
  351.  
  352.     ipcp_init();
  353.  
  354.     rc = get_thread_list();
  355.     if (rc < 0) {
  356.         printf("Failed to get thread list (error %d)\n", rc);
  357.         return;
  358.     }
  359.  
  360.     abort_trace = 0;
  361.  
  362.     for (i = 0; i < n_threads; i++) {
  363.         thread_trace_start(thread_hash_buf[i]);
  364.     }
  365.  
  366.     getchar();
  367.  
  368.     printf("terminate debugging session...\n");
  369.     abort_trace = 1;
  370.     debug_end(phoneid);
  371.     ipc_hangup(phoneid);
  372.  
  373.     ipcp_cleanup();
  374.  
  375.     printf("done\n");
  376.     return;
  377. }
  378.  
  379. static void main_init(void)
  380. {
  381.     proto_t *p;
  382.     oper_t *o;
  383.  
  384.     next_thread_id = 1;
  385.  
  386.     proto_init();
  387.  
  388.     o = malloc(sizeof(oper_t));
  389.     o->name = "mount";
  390.  
  391.     p = proto_new("vfs");
  392.     proto_add_oper(p, VFS_MOUNT, o);
  393.  
  394.     proto_register(SERVICE_VFS, p);
  395. }
  396.  
  397. int main(void)
  398. {
  399.     main_init();
  400.  
  401.     while (1) {
  402.         trace_active_task();
  403.     }
  404. }
  405.  
  406. /** @}
  407.  */
  408.