Subversion Repositories HelenOS

Rev

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