Subversion Repositories HelenOS

Rev

Rev 3665 | 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 <arch/asm.h>
  45. #include <errno.h>
  46. #include <ipc/ipc.h>
  47. #include <syscall/copy.h>
  48. #include <udebug/udebug.h>
  49. #include <udebug/udebug_ops.h>
  50. #include <udebug/udebug_ipc.h>
  51.  
  52. int udebug_request_preprocess(call_t *call, phone_t *phone)
  53. {
  54.     switch (IPC_GET_ARG1(call->data)) {
  55.     /* future UDEBUG_M_REGS_WRITE, UDEBUG_M_MEM_WRITE: */
  56.     default:
  57.         break;
  58.     }
  59.  
  60.     return 0;
  61. }
  62.  
  63. /** Process a BEGIN call.
  64.  *
  65.  * Initiates a debugging session for the current task. The reply
  66.  * to this call may or may not be sent before this function returns.
  67.  *
  68.  * @param call  The call structure.
  69.  */
  70. static void udebug_receive_begin(call_t *call)
  71. {
  72.     int rc;
  73.  
  74.     rc = udebug_begin(call);
  75.     if (rc < 0) {
  76.         IPC_SET_RETVAL(call->data, rc);
  77.         ipc_answer(&TASK->kb.box, call);
  78.         return;
  79.     }
  80.  
  81.     /*
  82.      * If the initialization of the debugging session has finished,
  83.      * send a reply.
  84.      */
  85.     if (rc != 0) {
  86.         IPC_SET_RETVAL(call->data, 0);
  87.         ipc_answer(&TASK->kb.box, call);
  88.     }
  89. }
  90.  
  91. /** Process an END call.
  92.  *
  93.  * Terminates the debugging session for the current task.
  94.  * @param call  The call structure.
  95.  */
  96. static void udebug_receive_end(call_t *call)
  97. {
  98.     int rc;
  99.  
  100.     rc = udebug_end();
  101.  
  102.     IPC_SET_RETVAL(call->data, rc);
  103.     ipc_answer(&TASK->kb.box, call);
  104. }
  105.  
  106. /** Process a SET_EVMASK call.
  107.  *
  108.  * Sets an event mask for the current debugging session.
  109.  * @param call  The call structure.
  110.  */
  111. static void udebug_receive_set_evmask(call_t *call)
  112. {
  113.     int rc;
  114.     udebug_evmask_t mask;
  115.  
  116.     mask = IPC_GET_ARG2(call->data);
  117.     rc = udebug_set_evmask(mask);
  118.  
  119.     IPC_SET_RETVAL(call->data, rc);
  120.     ipc_answer(&TASK->kb.box, call);
  121. }
  122.  
  123.  
  124. /** Process a GO call.
  125.  *
  126.  * Resumes execution of the specified thread.
  127.  * @param call  The call structure.
  128.  */
  129. static void udebug_receive_go(call_t *call)
  130. {
  131.     thread_t *t;
  132.     int rc;
  133.  
  134.     t = (thread_t *)IPC_GET_ARG2(call->data);
  135.  
  136.     rc = udebug_go(t, call);
  137.     if (rc < 0) {
  138.         IPC_SET_RETVAL(call->data, rc);
  139.         ipc_answer(&TASK->kb.box, call);
  140.         return;
  141.     }
  142. }
  143.  
  144. /** Process a STOP call.
  145.  *
  146.  * Suspends execution of the specified thread.
  147.  * @param call  The call structure.
  148.  */
  149. static void udebug_receive_stop(call_t *call)
  150. {
  151.     thread_t *t;
  152.     int rc;
  153.  
  154.     t = (thread_t *)IPC_GET_ARG2(call->data);
  155.  
  156.     rc = udebug_stop(t, call);
  157.     IPC_SET_RETVAL(call->data, rc);
  158.     ipc_answer(&TASK->kb.box, call);
  159. }
  160.  
  161. /** Process a THREAD_READ call.
  162.  *
  163.  * Reads the list of hashes of the (userspace) threads in the current task.
  164.  * @param call  The call structure.
  165.  */
  166. static void udebug_receive_thread_read(call_t *call)
  167. {
  168.     unative_t uspace_addr;
  169.     unative_t to_copy;
  170.     unsigned total_bytes;
  171.     unsigned buf_size;
  172.     void *buffer;
  173.     size_t n;
  174.     int rc;
  175.  
  176.     uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
  177.     buf_size = IPC_GET_ARG3(call->data);    /* Dest. buffer size */
  178.  
  179.     /*
  180.      * Read thread list. Variable n will be filled with actual number
  181.      * of threads times thread-id size.
  182.      */
  183.     rc = udebug_thread_read(&buffer, buf_size, &n);
  184.     if (rc < 0) {
  185.         IPC_SET_RETVAL(call->data, rc);
  186.         ipc_answer(&TASK->kb.box, call);
  187.         return;
  188.     }
  189.  
  190.     total_bytes = n;
  191.  
  192.     /* Copy MAX(buf_size, total_bytes) bytes */
  193.  
  194.     if (buf_size > total_bytes)
  195.         to_copy = total_bytes;
  196.     else
  197.         to_copy = buf_size;
  198.  
  199.     /*
  200.      * Make use of call->buffer to transfer data to caller's userspace
  201.      */
  202.  
  203.     IPC_SET_RETVAL(call->data, 0);
  204.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  205.        same code in process_answer() can be used
  206.        (no way to distinguish method in answer) */
  207.     IPC_SET_ARG1(call->data, uspace_addr);
  208.     IPC_SET_ARG2(call->data, to_copy);
  209.  
  210.     IPC_SET_ARG3(call->data, total_bytes);
  211.     call->buffer = buffer;
  212.  
  213.     ipc_answer(&TASK->kb.box, call);
  214. }
  215.  
  216. /** Process an ARGS_READ call.
  217.  *
  218.  * Reads the argument of a current syscall event (SYSCALL_B or SYSCALL_E).
  219.  * @param call  The call structure.
  220.  */
  221. static void udebug_receive_args_read(call_t *call)
  222. {
  223.     thread_t *t;
  224.     unative_t uspace_addr;
  225.     int rc;
  226.     void *buffer;
  227.  
  228.     t = (thread_t *)IPC_GET_ARG2(call->data);
  229.  
  230.     rc = udebug_args_read(t, &buffer);
  231.     if (rc != EOK) {
  232.         IPC_SET_RETVAL(call->data, rc);
  233.         ipc_answer(&TASK->kb.box, call);
  234.         return;
  235.     }
  236.  
  237.     /*
  238.      * Make use of call->buffer to transfer data to caller's userspace
  239.      */
  240.  
  241.     uspace_addr = IPC_GET_ARG3(call->data);
  242.  
  243.     IPC_SET_RETVAL(call->data, 0);
  244.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  245.        same code in process_answer() can be used
  246.        (no way to distinguish method in answer) */
  247.     IPC_SET_ARG1(call->data, uspace_addr);
  248.     IPC_SET_ARG2(call->data, 6 * sizeof(unative_t));
  249.     call->buffer = buffer;
  250.  
  251.     ipc_answer(&TASK->kb.box, call);
  252. }
  253.  
  254. /** Process an MEM_READ call.
  255.  *
  256.  * Reads memory of the current (debugged) task.
  257.  * @param call  The call structure.
  258.  */
  259. static void udebug_receive_mem_read(call_t *call)
  260. {
  261.     unative_t uspace_dst;
  262.     unative_t uspace_src;
  263.     unsigned size;
  264.     void *buffer;
  265.     int rc;
  266.  
  267.     uspace_dst = IPC_GET_ARG2(call->data);
  268.     uspace_src = IPC_GET_ARG3(call->data);
  269.     size = IPC_GET_ARG4(call->data);
  270.  
  271.     rc = udebug_mem_read(uspace_src, size, &buffer);
  272.     if (rc < 0) {
  273.         IPC_SET_RETVAL(call->data, rc);
  274.         ipc_answer(&TASK->kb.box, call);
  275.         return;
  276.     }
  277.  
  278.     IPC_SET_RETVAL(call->data, 0);
  279.     /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  280.        same code in process_answer() can be used
  281.        (no way to distinguish method in answer) */
  282.     IPC_SET_ARG1(call->data, uspace_dst);
  283.     IPC_SET_ARG2(call->data, size);
  284.     call->buffer = buffer;
  285.  
  286.     ipc_answer(&TASK->kb.box, call);
  287. }
  288.  
  289. /** Handle a debug call received on the kernel answerbox.
  290.  *
  291.  * This is called by the kbox servicing thread. Verifies that the sender
  292.  * is indeed the debugger and calls the appropriate processing function.
  293.  */
  294. void udebug_call_receive(call_t *call)
  295. {
  296.     int debug_method;
  297.  
  298.     debug_method = IPC_GET_ARG1(call->data);
  299.  
  300.     if (debug_method != UDEBUG_M_BEGIN) {
  301.         /*
  302.          * Verify that the sender is this task's debugger.
  303.          * Note that this is the only thread that could change
  304.          * TASK->debugger. Therefore no locking is necessary
  305.          * and the sender can be safely considered valid until
  306.          * control exits this function.
  307.          */
  308.         if (TASK->udebug.debugger != call->sender) {
  309.             IPC_SET_RETVAL(call->data, EINVAL);
  310.             ipc_answer(&TASK->kb.box, call);
  311.             return;
  312.         }
  313.     }
  314.  
  315.     switch (debug_method) {
  316.     case UDEBUG_M_BEGIN:
  317.         udebug_receive_begin(call);
  318.         break;
  319.     case UDEBUG_M_END:
  320.         udebug_receive_end(call);
  321.         break;
  322.     case UDEBUG_M_SET_EVMASK:
  323.         udebug_receive_set_evmask(call);
  324.         break;
  325.     case UDEBUG_M_GO:
  326.         udebug_receive_go(call);
  327.         break;
  328.     case UDEBUG_M_STOP:
  329.         udebug_receive_stop(call);
  330.         break;
  331.     case UDEBUG_M_THREAD_READ:
  332.         udebug_receive_thread_read(call);
  333.         break;
  334.     case UDEBUG_M_ARGS_READ:
  335.         udebug_receive_args_read(call);
  336.         break;
  337.     case UDEBUG_M_MEM_READ:
  338.         udebug_receive_mem_read(call);
  339.         break;
  340.     }
  341. }
  342.  
  343. /** @}
  344.  */
  345.