Subversion Repositories HelenOS

Rev

Rev 3471 | 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 generic
  30.  * @{
  31.  */
  32.  
  33. /**
  34.  * @file
  35.  * @brief   Udebug IPC message handling.
  36.  *
  37.  * This module handles udebug IPC messages and calls the appropriate
  38.  * functions from the udebug_ops module which implement them.
  39.  */
  40.  
  41. #include <proc/task.h>
  42. #include <proc/thread.h>
  43. #include <arch.h>
  44. #include <errno.h>
  45. #include <ipc/ipc.h>
  46. #include <syscall/copy.h>
  47. #include <udebug/udebug.h>
  48. #include <udebug/udebug_ops.h>
  49. #include <udebug/udebug_ipc.h>
  50.  
  51. static int udebug_rp_regs_write(call_t *call, phone_t *phone)
  52. {
  53.     void *uspace_data;
  54.     unative_t to_copy;
  55.     int rc;
  56.     void *buffer;
  57.  
  58.     LOG("debug_regs_write()\n");
  59.  
  60.     uspace_data = (void *)IPC_GET_ARG3(call->data);
  61.     to_copy = sizeof(istate_t);
  62.     buffer = malloc(to_copy, 0);
  63.  
  64.     rc = copy_from_uspace(buffer, uspace_data, to_copy);
  65.     if (rc != 0) {
  66.         LOG("debug_regs_write() - copy failed\n");
  67.         return rc;
  68.     }
  69.  
  70.     call->buffer = buffer;
  71.  
  72.     LOG(" - done\n");
  73.     return 0;
  74. }
  75.  
  76. static int udebug_rp_mem_write(call_t *call, phone_t *phone)
  77. {
  78.     void *uspace_data;
  79.     unative_t to_copy;
  80.     int rc;
  81.     void *buffer;
  82.  
  83.     LOG("udebug_rp_mem_write()\n");
  84.  
  85.     uspace_data = (void *)IPC_GET_ARG2(call->data);
  86.     to_copy = IPC_GET_ARG4(call->data);
  87.  
  88.     buffer = malloc(to_copy, 0);
  89.  
  90.     rc = copy_from_uspace(buffer, uspace_data, to_copy);
  91.     if (rc != 0) {
  92.         LOG(" - copy failed\n");
  93.         return rc;
  94.     }
  95.  
  96.     call->buffer = buffer;
  97.  
  98.     LOG(" - done\n");
  99.     return 0;
  100. }
  101.  
  102.  
  103. int udebug_request_preprocess(call_t *call, phone_t *phone)
  104. {
  105.     int rc;
  106.  
  107.     switch (IPC_GET_ARG1(call->data)) {
  108.     case UDEBUG_M_REGS_WRITE:
  109.         rc = udebug_rp_regs_write(call, phone);
  110.         return rc;
  111.     case UDEBUG_M_MEM_WRITE:
  112.         rc = udebug_rp_mem_write(call, phone);
  113.         return rc;
  114.     default:
  115.         break;
  116.     }
  117.  
  118.     return 0;
  119. }
  120.  
  121. /** Process a BEGIN call.
  122.  *
  123.  * Initiates a debugging session for the current task. The reply
  124.  * to this call may or may not be sent before this function returns.
  125.  *
  126.  * @param call  The call structure.
  127.  */
  128. static void udebug_receive_begin(call_t *call)
  129. {
  130.     int rc;
  131.  
  132.     rc = udebug_begin(call);
  133.     if (rc < 0) {
  134.         IPC_SET_RETVAL(call->data, rc);
  135.         ipc_answer(&TASK->kernel_box, call);
  136.         return;
  137.     }
  138.  
  139.     /*
  140.      * If the initialization of the debugging session has finished,
  141.      * send a reply.
  142.      */
  143.     if (rc != 0) {
  144.         IPC_SET_RETVAL(call->data, 0);
  145.         ipc_answer(&TASK->kernel_box, call);
  146.     }
  147. }
  148.  
  149. /** Process an END call.
  150.  *
  151.  * Terminates the debugging session for the current task.
  152.  * @param call  The call structure.
  153.  */
  154. static void udebug_receive_end(call_t *call)
  155. {
  156.     int rc;
  157.  
  158.     rc = udebug_end();
  159.  
  160.     IPC_SET_RETVAL(call->data, rc);
  161.     ipc_answer(&TASK->kernel_box, call);
  162. }
  163.  
  164. /** Process a SET_EVMASK call.
  165.  *
  166.  * Sets an event mask for the current debugging session.
  167.  * @param call  The call structure.
  168.  */
  169. static void udebug_receive_set_evmask(call_t *call)
  170. {
  171.     int rc;
  172.     udebug_evmask_t mask;
  173.  
  174.     mask = IPC_GET_ARG2(call->data);
  175.     rc = udebug_set_evmask(mask);
  176.  
  177.     IPC_SET_RETVAL(call->data, rc);
  178.     ipc_answer(&TASK->kernel_box, call);
  179. }
  180.  
  181.  
  182. /** Process a GO call.
  183.  *
  184.  * Resumes execution of the specified thread.
  185.  * @param call  The call structure.
  186.  */
  187. static void udebug_receive_go(call_t *call)
  188. {
  189.     thread_t *t;
  190.     int rc;
  191.  
  192.     t = (thread_t *)IPC_GET_ARG2(call->data);
  193.  
  194.     rc = udebug_go(t, call);
  195.     if (rc < 0) {
  196.         IPC_SET_RETVAL(call->data, rc);
  197.         ipc_answer(&TASK->kernel_box, call);
  198.         return;
  199.     }
  200. }
  201.  
  202. /** Process a STOP call.
  203.  *
  204.  * Suspends execution of the specified thread.
  205.  * @param call  The call structure.
  206.  */
  207. static void udebug_receive_stop(call_t *call)
  208. {
  209.     thread_t *t;
  210.     int rc;
  211.  
  212.     t = (thread_t *)IPC_GET_ARG2(call->data);
  213.  
  214.     rc = udebug_stop(t, call);
  215.     IPC_SET_RETVAL(call->data, rc);
  216.     ipc_answer(&TASK->kernel_box, call);
  217. }
  218.  
  219. /** Process a THREAD_READ call.
  220.  *
  221.  * Reads the list of hashes of the (userspace) threads in the current task.
  222.  * @param call  The call structure.
  223.  */
  224. static void udebug_receive_thread_read(call_t *call)
  225. {
  226.     unative_t uspace_addr;
  227.     unative_t to_copy;
  228.     unsigned total_bytes;
  229.     unsigned buf_size;
  230.     void *buffer;
  231.     size_t n;
  232.     int rc;
  233.  
  234.     uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
  235.     buf_size = IPC_GET_ARG3(call->data);    /* Dest. buffer size */
  236.  
  237.     /*
  238.      * Read thread list. Variable n will be filled with actual number
  239.      * of threads times thread-id size.
  240.      */
  241.     rc = udebug_thread_read(&buffer, buf_size, &n);
  242.     if (rc < 0) {
  243.         IPC_SET_RETVAL(call->data, rc);
  244.         ipc_answer(&TASK->kernel_box, call);
  245.         return;
  246.     }
  247.  
  248.     total_bytes = n;
  249.  
  250.     /* Copy MAX(buf_size, total_bytes) bytes */
  251.  
  252.     if (buf_size > total_bytes)
  253.         to_copy = total_bytes;
  254.     else
  255.         to_copy = buf_size;
  256.  
  257.     /*
  258.      * Make use of call->buffer to transfer data to caller's userspace
  259.      */
  260.  
  261.     IPC_SET_RETVAL(call->data, 0);
  262.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  263.        same code in process_answer() can be used
  264.        (no way to distinguish method in answer) */
  265.     IPC_SET_ARG1(call->data, uspace_addr);
  266.     IPC_SET_ARG2(call->data, to_copy);
  267.  
  268.     IPC_SET_ARG3(call->data, total_bytes);
  269.     call->buffer = buffer;
  270.  
  271.     ipc_answer(&TASK->kernel_box, call);
  272. }
  273.  
  274. /** Process an ARGS_READ call.
  275.  *
  276.  * Reads the argument of a current syscall event (SYSCALL_B or SYSCALL_E).
  277.  * @param call  The call structure.
  278.  */
  279. static void udebug_receive_args_read(call_t *call)
  280. {
  281.     thread_t *t;
  282.     unative_t uspace_addr;
  283.     int rc;
  284.     void *buffer;
  285.  
  286.     t = (thread_t *)IPC_GET_ARG2(call->data);
  287.  
  288.     rc = udebug_args_read(t, &buffer);
  289.     if (rc != EOK) {
  290.         IPC_SET_RETVAL(call->data, rc);
  291.         ipc_answer(&TASK->kernel_box, call);
  292.         return;
  293.     }
  294.  
  295.     /*
  296.      * Make use of call->buffer to transfer data to caller's userspace
  297.      */
  298.  
  299.     uspace_addr = IPC_GET_ARG3(call->data);
  300.  
  301.     IPC_SET_RETVAL(call->data, 0);
  302.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  303.        same code in process_answer() can be used
  304.        (no way to distinguish method in answer) */
  305.     IPC_SET_ARG1(call->data, uspace_addr);
  306.     IPC_SET_ARG2(call->data, 6 * sizeof(unative_t));
  307.     call->buffer = buffer;
  308.  
  309.     ipc_answer(&TASK->kernel_box, call);
  310. }
  311.  
  312. static void udebug_receive_regs_read(call_t *call)
  313. {
  314.     thread_t *t;
  315.     unative_t uspace_addr;
  316.     unative_t to_copy;
  317.     void *buffer;
  318.     int rc;
  319.  
  320.     LOG("debug_regs_read()\n");
  321.  
  322.     t = (thread_t *) IPC_GET_ARG2(call->data);
  323.     buffer = malloc(sizeof(istate_t), 0);
  324.  
  325.     rc = udebug_regs_read(t, buffer);
  326.     if (rc < 0) {
  327.         IPC_SET_RETVAL(call->data, rc);
  328.         ipc_answer(&TASK->kernel_box, call);
  329.         return;
  330.     }
  331.  
  332.     /*
  333.      * Make use of call->buffer to transfer data to caller's userspace
  334.      */
  335.  
  336.     uspace_addr = IPC_GET_ARG3(call->data);
  337.     to_copy = sizeof(istate_t);
  338.  
  339.     IPC_SET_RETVAL(call->data, 0);
  340.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  341.        same code in process_answer() can be used
  342.        (no way to distinguish method in answer) */
  343.     IPC_SET_ARG1(call->data, uspace_addr);
  344.     IPC_SET_ARG2(call->data, to_copy);
  345.  
  346.     call->buffer = buffer;
  347.  
  348.     ipc_answer(&TASK->kernel_box, call);
  349. }
  350.  
  351. static void udebug_receive_regs_write(call_t *call)
  352. {
  353.     thread_t *t;
  354.     void *uspace_data;
  355.     int rc;
  356.  
  357.     t = (thread_t *) IPC_GET_ARG2(call->data);
  358.     uspace_data = (void *)IPC_GET_ARG3(call->data);
  359.  
  360.     rc = udebug_regs_write(t, call->buffer);
  361.     if (rc < 0) {
  362.         IPC_SET_RETVAL(call->data, rc);
  363.         ipc_answer(&TASK->kernel_box, call);
  364.         return;
  365.     }
  366.  
  367.     /* Set answer values */
  368.  
  369.     IPC_SET_RETVAL(call->data, 0);
  370.     free(call->buffer);
  371.     call->buffer = NULL;
  372.  
  373.     ipc_answer(&TASK->kernel_box, call);
  374. }
  375.  
  376. /** Process an MEM_READ call.
  377.  *
  378.  * Reads memory of the current (debugged) task.
  379.  * @param call  The call structure.
  380.  */
  381. static void udebug_receive_mem_read(call_t *call)
  382. {
  383.     unative_t uspace_dst;
  384.     unative_t uspace_src;
  385.     unsigned size;
  386.     void *buffer;
  387.     int rc;
  388.  
  389.     uspace_dst = IPC_GET_ARG2(call->data);
  390.     uspace_src = IPC_GET_ARG3(call->data);
  391.     size = IPC_GET_ARG4(call->data);
  392.  
  393.     rc = udebug_mem_read(uspace_src, size, &buffer);
  394.     if (rc < 0) {
  395.         IPC_SET_RETVAL(call->data, rc);
  396.         ipc_answer(&TASK->kernel_box, call);
  397.         return;
  398.     }
  399.  
  400.     IPC_SET_RETVAL(call->data, 0);
  401.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  402.        same code in process_answer() can be used
  403.        (no way to distinguish method in answer) */
  404.     IPC_SET_ARG1(call->data, uspace_dst);
  405.     IPC_SET_ARG2(call->data, size);
  406.     call->buffer = buffer;
  407.  
  408.     ipc_answer(&TASK->kernel_box, call);
  409. }
  410.  
  411. static void udebug_receive_mem_write(call_t *call)
  412. {
  413.     unative_t uspace_dst;
  414.     unsigned size;
  415.     int rc;
  416.  
  417.     LOG("udebug_receive_mem_write()\n");
  418.  
  419.     uspace_dst = IPC_GET_ARG3(call->data);
  420.     size = IPC_GET_ARG4(call->data);
  421.  
  422.     rc = udebug_mem_write(uspace_dst, call->buffer, size);
  423.     if (rc < 0) {
  424.         IPC_SET_RETVAL(call->data, rc);
  425.         ipc_answer(&TASK->kernel_box, call);
  426.         return;
  427.     }
  428.  
  429.     IPC_SET_RETVAL(call->data, 0);
  430.     free(call->buffer);
  431.     call->buffer = NULL;
  432.  
  433.     ipc_answer(&TASK->kernel_box, call);
  434. }
  435.  
  436.  
  437. /** Handle a debug call received on the kernel answerbox.
  438.  *
  439.  * This is called by the kbox servicing thread. Verifies that the sender
  440.  * is indeed the debugger and calls the appropriate processing function.
  441.  */
  442. void udebug_call_receive(call_t *call)
  443. {
  444.     int debug_method;
  445.  
  446.     debug_method = IPC_GET_ARG1(call->data);
  447.  
  448.     if (debug_method != UDEBUG_M_BEGIN) {
  449.         /*
  450.          * Verify that the sender is this task's debugger.
  451.          * Note that this is the only thread that could change
  452.          * TASK->debugger. Therefore no locking is necessary
  453.          * and the sender can be safely considered valid until
  454.          * control exits this function.
  455.          */
  456.         if (TASK->udebug.debugger != call->sender) {
  457.             IPC_SET_RETVAL(call->data, EINVAL);
  458.             ipc_answer(&TASK->kernel_box, call);
  459.             return;
  460.         }
  461.     }
  462.  
  463.     switch (debug_method) {
  464.     case UDEBUG_M_BEGIN:
  465.         udebug_receive_begin(call);
  466.         break;
  467.     case UDEBUG_M_END:
  468.         udebug_receive_end(call);
  469.         break;
  470.     case UDEBUG_M_SET_EVMASK:
  471.         udebug_receive_set_evmask(call);
  472.         break;
  473.     case UDEBUG_M_GO:
  474.         udebug_receive_go(call);
  475.         break;
  476.     case UDEBUG_M_STOP:
  477.         udebug_receive_stop(call);
  478.         break;
  479.     case UDEBUG_M_THREAD_READ:
  480.         udebug_receive_thread_read(call);
  481.         break;
  482.     case UDEBUG_M_ARGS_READ:
  483.         udebug_receive_args_read(call);
  484.         break;
  485.     case UDEBUG_M_REGS_READ:
  486.         udebug_receive_regs_read(call);
  487.         break;
  488.     case UDEBUG_M_REGS_WRITE:
  489.         udebug_receive_regs_write(call);
  490.         break;
  491.     case UDEBUG_M_MEM_READ:
  492.         udebug_receive_mem_read(call);
  493.         break;
  494.     case UDEBUG_M_MEM_WRITE:
  495.         udebug_receive_mem_write(call);
  496.         break;
  497.     }
  498. }
  499.  
  500. /** @}
  501.  */
  502.