Subversion Repositories HelenOS

Rev

Rev 3742 | 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 operations.
  36.  *
  37.  * Udebug operations on tasks and threads are implemented here. The
  38.  * functions defined here are called from the udebug_ipc module
  39.  * when servicing udebug IPC messages.
  40.  */
  41.  
  42. #include <debug.h>
  43. #include <proc/task.h>
  44. #include <proc/thread.h>
  45. #include <arch.h>
  46. #include <arch/asm.h>
  47. #include <errno.h>
  48. #include <syscall/copy.h>
  49. #include <ipc/ipc.h>
  50. #include <udebug/udebug.h>
  51. #include <udebug/udebug_ops.h>
  52. #include <print.h>
  53.  
  54. /**
  55.  * Prepare a thread for a debugging operation.
  56.  *
  57.  * Simply put, return thread t with t->udebug.lock held,
  58.  * but only if it verifies all conditions.
  59.  *
  60.  * Specifically, verifies that thread t exists, is a userspace thread,
  61.  * and belongs to the current task (TASK). Verifies, that the thread
  62.  * is (or is not) go according to being_go (typically false).
  63.  * It also locks t->udebug.lock, making sure that t->udebug.active
  64.  * is true - that the thread is in a valid debugging session.
  65.  *
  66.  * With this verified and the t->udebug.lock mutex held, it is ensured
  67.  * that the thread cannot leave the debugging session, let alone cease
  68.  * to exist.
  69.  *
  70.  * In this function, holding the TASK->udebug.lock mutex prevents the
  71.  * thread from leaving the debugging session, while relaxing from
  72.  * the t->lock spinlock to the t->udebug.lock mutex.
  73.  *
  74.  * @param t     Pointer, need not at all be valid.
  75.  * @param being_go  Required thread state.
  76.  *
  77.  * Returns EOK if all went well, or an error code otherwise.
  78.  */
  79. static int _thread_op_begin(thread_t *t, bool being_go)
  80. {
  81.     task_id_t taskid;
  82.     ipl_t ipl;
  83.  
  84.     taskid = TASK->taskid;
  85.  
  86.     mutex_lock(&TASK->udebug.lock);
  87.  
  88.     /* thread_exists() must be called with threads_lock held */
  89.     ipl = interrupts_disable();
  90.     spinlock_lock(&threads_lock);
  91.  
  92.     if (!thread_exists(t)) {
  93.         spinlock_unlock(&threads_lock);
  94.         interrupts_restore(ipl);
  95.         mutex_unlock(&TASK->udebug.lock);
  96.         return ENOENT;
  97.     }
  98.  
  99.     /* t->lock is enough to ensure the thread's existence */
  100.     spinlock_lock(&t->lock);
  101.     spinlock_unlock(&threads_lock);
  102.  
  103.     /* Verify that 't' is a userspace thread. */
  104.     if ((t->flags & THREAD_FLAG_USPACE) == 0) {
  105.         /* It's not, deny its existence */
  106.         spinlock_unlock(&t->lock);
  107.         interrupts_restore(ipl);
  108.         mutex_unlock(&TASK->udebug.lock);
  109.         return ENOENT;
  110.     }
  111.  
  112.     /* Verify debugging state. */
  113.     if (t->udebug.active != true) {
  114.         /* Not in debugging session or undesired GO state */
  115.         spinlock_unlock(&t->lock);
  116.         interrupts_restore(ipl);
  117.         mutex_unlock(&TASK->udebug.lock);
  118.         return ENOENT;
  119.     }
  120.  
  121.     /*
  122.      * Since the thread has active == true, TASK->udebug.lock
  123.      * is enough to ensure its existence and that active remains
  124.      * true.
  125.      */
  126.     spinlock_unlock(&t->lock);
  127.     interrupts_restore(ipl);
  128.  
  129.     /* Only mutex TASK->udebug.lock left. */
  130.    
  131.     /* Now verify that the thread belongs to the current task. */
  132.     if (t->task != TASK) {
  133.         /* No such thread belonging this task*/
  134.         mutex_unlock(&TASK->udebug.lock);
  135.         return ENOENT;
  136.     }
  137.  
  138.     /*
  139.      * Now we need to grab the thread's debug lock for synchronization
  140.      * of the threads stoppability/stop state.
  141.      */
  142.     mutex_lock(&t->udebug.lock);
  143.  
  144.     /* The big task mutex is no longer needed. */
  145.     mutex_unlock(&TASK->udebug.lock);
  146.  
  147.     if (t->udebug.go != being_go) {
  148.         /* Not in debugging session or undesired GO state. */
  149.         mutex_unlock(&t->udebug.lock);
  150.         return EINVAL;
  151.     }
  152.  
  153.     /* Only t->udebug.lock left. */
  154.  
  155.     return EOK; /* All went well. */
  156. }
  157.  
  158. /** End debugging operation on a thread. */
  159. static void _thread_op_end(thread_t *t)
  160. {
  161.     mutex_unlock(&t->udebug.lock);
  162. }
  163.  
  164. /** Begin debugging the current task.
  165.  *
  166.  * Initiates a debugging session for the current task (and its threads).
  167.  * When the debugging session has started a reply will be sent to the
  168.  * UDEBUG_BEGIN call. This may happen immediately in this function if
  169.  * all the threads in this task are stoppable at the moment and in this
  170.  * case the function returns 1.
  171.  *
  172.  * Otherwise the function returns 0 and the reply will be sent as soon as
  173.  * all the threads become stoppable (i.e. they can be considered stopped).
  174.  *
  175.  * @param call  The BEGIN call we are servicing.
  176.  * @return  0 (OK, but not done yet), 1 (done) or negative error code.
  177.  */
  178. int udebug_begin(call_t *call)
  179. {
  180.     int reply;
  181.  
  182.     thread_t *t;
  183.     link_t *cur;
  184.  
  185.     LOG("udebug_begin()\n");
  186.  
  187.     mutex_lock(&TASK->udebug.lock);
  188.     LOG("debugging task %llu\n", TASK->taskid);
  189.  
  190.     if (TASK->udebug.dt_state != UDEBUG_TS_INACTIVE) {
  191.         mutex_unlock(&TASK->udebug.lock);
  192.         LOG("udebug_begin(): busy error\n");
  193.  
  194.         return EBUSY;
  195.     }
  196.  
  197.     TASK->udebug.dt_state = UDEBUG_TS_BEGINNING;
  198.     TASK->udebug.begin_call = call;
  199.     TASK->udebug.debugger = call->sender;
  200.  
  201.     if (TASK->udebug.not_stoppable_count == 0) {
  202.         TASK->udebug.dt_state = UDEBUG_TS_ACTIVE;
  203.         TASK->udebug.begin_call = NULL;
  204.         reply = 1; /* immediate reply */
  205.     } else {
  206.         reply = 0; /* no reply */
  207.     }
  208.    
  209.     /* Set udebug.active on all of the task's userspace threads. */
  210.  
  211.     for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
  212.         t = list_get_instance(cur, thread_t, th_link);
  213.  
  214.         mutex_lock(&t->udebug.lock);
  215.         if ((t->flags & THREAD_FLAG_USPACE) != 0)
  216.             t->udebug.active = true;
  217.         mutex_unlock(&t->udebug.lock);
  218.     }
  219.  
  220.     mutex_unlock(&TASK->udebug.lock);
  221.  
  222.     LOG("udebug_begin() done (%s)\n",
  223.         reply ? "reply" : "stoppability wait");
  224.  
  225.     return reply;
  226. }
  227.  
  228. /** Finish debugging the current task.
  229.  *
  230.  * Closes the debugging session for the current task.
  231.  * @return Zero on success or negative error code.
  232.  */
  233. int udebug_end(void)
  234. {
  235.     int rc;
  236.  
  237.     LOG("udebug_end()\n");
  238.  
  239.     mutex_lock(&TASK->udebug.lock);
  240.     LOG("task %" PRIu64 "\n", TASK->taskid);
  241.  
  242.     rc = udebug_task_cleanup(TASK);
  243.  
  244.     mutex_unlock(&TASK->udebug.lock);
  245.  
  246.     return rc;
  247. }
  248.  
  249. /** Set the event mask.
  250.  *
  251.  * Sets the event mask that determines which events are enabled.
  252.  *
  253.  * @param mask  Or combination of events that should be enabled.
  254.  * @return  Zero on success or negative error code.
  255.  */
  256. int udebug_set_evmask(udebug_evmask_t mask)
  257. {
  258.     LOG("udebug_set_mask()\n");
  259.  
  260.     mutex_lock(&TASK->udebug.lock);
  261.  
  262.     if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
  263.         mutex_unlock(&TASK->udebug.lock);
  264.         LOG("udebug_set_mask(): not active debuging session\n");
  265.  
  266.         return EINVAL;
  267.     }
  268.  
  269.     TASK->udebug.evmask = mask;
  270.  
  271.     mutex_unlock(&TASK->udebug.lock);
  272.  
  273.     return 0;
  274. }
  275.  
  276. /** Give thread GO.
  277.  *
  278.  * Upon recieving a go message, the thread is given GO. Being GO
  279.  * means the thread is allowed to execute userspace code (until
  280.  * a debugging event or STOP occurs, at which point the thread loses GO.
  281.  *
  282.  * @param t The thread to operate on (unlocked and need not be valid).
  283.  * @param call  The GO call that we are servicing.
  284.  */
  285. int udebug_go(thread_t *t, call_t *call)
  286. {
  287.     int rc;
  288.  
  289.     /* On success, this will lock t->udebug.lock. */
  290.     rc = _thread_op_begin(t, false);
  291.     if (rc != EOK) {
  292.         return rc;
  293.     }
  294.  
  295.     t->udebug.go_call = call;
  296.     t->udebug.go = true;
  297.     t->udebug.cur_event = 0;    /* none */
  298.  
  299.     /*
  300.      * Neither t's lock nor threads_lock may be held during wakeup.
  301.      */
  302.     waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
  303.  
  304.     _thread_op_end(t);
  305.  
  306.     return 0;
  307. }
  308.  
  309. /** Stop a thread (i.e. take its GO away)
  310.  *
  311.  * Generates a STOP event as soon as the thread becomes stoppable (i.e.
  312.  * can be considered stopped).
  313.  *
  314.  * @param t The thread to operate on (unlocked and need not be valid).
  315.  * @param call  The GO call that we are servicing.
  316.  */
  317. int udebug_stop(thread_t *t, call_t *call)
  318. {
  319.     int rc;
  320.  
  321.     LOG("udebug_stop()\n");
  322.  
  323.     /*
  324.      * On success, this will lock t->udebug.lock. Note that this makes sure
  325.      * the thread is not stopped.
  326.      */
  327.     rc = _thread_op_begin(t, true);
  328.     if (rc != EOK) {
  329.         return rc;
  330.     }
  331.  
  332.     /* Take GO away from the thread. */
  333.     t->udebug.go = false;
  334.  
  335.     if (t->udebug.stoppable != true) {
  336.         /* Answer will be sent when the thread becomes stoppable. */
  337.         _thread_op_end(t);
  338.         return 0;
  339.     }
  340.  
  341.     /*
  342.      * Answer GO call.
  343.      */
  344.     LOG("udebug_stop - answering go call\n");
  345.  
  346.     /* Make sure nobody takes this call away from us. */
  347.     call = t->udebug.go_call;
  348.     t->udebug.go_call = NULL;
  349.  
  350.     IPC_SET_RETVAL(call->data, 0);
  351.     IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP);
  352.     LOG("udebug_stop/ipc_answer\n");
  353.  
  354.     THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
  355.  
  356.     _thread_op_end(t);
  357.  
  358.     mutex_lock(&TASK->udebug.lock);
  359.     ipc_answer(&TASK->answerbox, call);
  360.     mutex_unlock(&TASK->udebug.lock);
  361.  
  362.     LOG("udebog_stop/done\n");
  363.     return 0;
  364. }
  365.  
  366. /** Read the list of userspace threads in the current task.
  367.  *
  368.  * The list takes the form of a sequence of thread hashes (i.e. the pointers
  369.  * to thread structures). A buffer of size @a buf_size is allocated and
  370.  * a pointer to it written to @a buffer. The sequence of hashes is written
  371.  * into this buffer.
  372.  *
  373.  * If the sequence is longer than @a buf_size bytes, only as much hashes
  374.  * as can fit are copied. The number of thread hashes copied is stored
  375.  * in @a n.
  376.  *
  377.  * The rationale for having @a buf_size is that this function is only
  378.  * used for servicing the THREAD_READ message, which always specifies
  379.  * a maximum size for the userspace buffer.
  380.  *
  381.  * @param buffer    The buffer for storing thread hashes.
  382.  * @param buf_size  Buffer size in bytes.
  383.  * @param n     The actual number of hashes copied will be stored here.
  384.  */
  385. int udebug_thread_read(void **buffer, size_t buf_size, size_t *n)
  386. {
  387.     thread_t *t;
  388.     link_t *cur;
  389.     unative_t tid;
  390.     unsigned copied_ids;
  391.     ipl_t ipl;
  392.     unative_t *id_buffer;
  393.     int flags;
  394.     size_t max_ids;
  395.  
  396.     LOG("udebug_thread_read()\n");
  397.  
  398.     /* Allocate a buffer to hold thread IDs */
  399.     id_buffer = malloc(buf_size, 0);
  400.  
  401.     mutex_lock(&TASK->udebug.lock);
  402.  
  403.     /* Verify task state */
  404.     if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
  405.         mutex_unlock(&TASK->udebug.lock);
  406.         return EINVAL;
  407.     }
  408.  
  409.     ipl = interrupts_disable();
  410.     spinlock_lock(&TASK->lock);
  411.     /* Copy down the thread IDs */
  412.  
  413.     max_ids = buf_size / sizeof(unative_t);
  414.     copied_ids = 0;
  415.  
  416.     /* FIXME: make sure the thread isn't past debug shutdown... */
  417.     for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
  418.         /* Do not write past end of buffer */
  419.         if (copied_ids >= max_ids) break;
  420.  
  421.         t = list_get_instance(cur, thread_t, th_link);
  422.  
  423.         spinlock_lock(&t->lock);
  424.         flags = t->flags;
  425.         spinlock_unlock(&t->lock);
  426.  
  427.         /* Not interested in kernel threads. */
  428.         if ((flags & THREAD_FLAG_USPACE) != 0) {
  429.             /* Using thread struct pointer as identification hash */
  430.             tid = (unative_t) t;
  431.             id_buffer[copied_ids++] = tid;
  432.         }
  433.     }
  434.  
  435.     spinlock_unlock(&TASK->lock);
  436.     interrupts_restore(ipl);
  437.  
  438.     mutex_unlock(&TASK->udebug.lock);
  439.  
  440.     *buffer = id_buffer;
  441.     *n = copied_ids * sizeof(unative_t);
  442.  
  443.     return 0;
  444. }
  445.  
  446. /** Read the arguments of a system call.
  447.  *
  448.  * The arguments of the system call being being executed are copied
  449.  * to an allocated buffer and a pointer to it is written to @a buffer.
  450.  * The size of the buffer is exactly such that it can hold the maximum number
  451.  * of system-call arguments.
  452.  *
  453.  * Unless the thread is currently blocked in a SYSCALL_B or SYSCALL_E event,
  454.  * this function will fail with an EINVAL error code.
  455.  *
  456.  * @param buffer    The buffer for storing thread hashes.
  457.  */
  458. int udebug_args_read(thread_t *t, void **buffer)
  459. {
  460.     int rc;
  461.     unative_t *arg_buffer;
  462.  
  463.     /* Prepare a buffer to hold the arguments. */
  464.     arg_buffer = malloc(6 * sizeof(unative_t), 0);
  465.  
  466.     /* On success, this will lock t->udebug.lock. */
  467.     rc = _thread_op_begin(t, false);
  468.     if (rc != EOK) {
  469.         return rc;
  470.     }
  471.  
  472.     /* Additionally we need to verify that we are inside a syscall. */
  473.     if (t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_B &&
  474.         t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_E) {
  475.         _thread_op_end(t);
  476.         return EINVAL;
  477.     }
  478.  
  479.     /* Copy to a local buffer before releasing the lock. */
  480.     memcpy(arg_buffer, t->udebug.syscall_args, 6 * sizeof(unative_t));
  481.  
  482.     _thread_op_end(t);
  483.  
  484.     *buffer = arg_buffer;
  485.     return 0;
  486. }
  487.  
  488. /** Read the memory of the debugged task.
  489.  *
  490.  * Reads @a n bytes from the address space of the debugged task, starting
  491.  * from @a uspace_addr. The bytes are copied into an allocated buffer
  492.  * and a pointer to it is written into @a buffer.
  493.  *
  494.  * @param uspace_addr   Address from where to start reading.
  495.  * @param n     Number of bytes to read.
  496.  * @param buffer    For storing a pointer to the allocated buffer.
  497.  */
  498. int udebug_mem_read(unative_t uspace_addr, size_t n, void **buffer)
  499. {
  500.     void *data_buffer;
  501.     int rc;
  502.  
  503.     /* Verify task state */
  504.     mutex_lock(&TASK->udebug.lock);
  505.  
  506.     if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
  507.         mutex_unlock(&TASK->udebug.lock);
  508.         return EBUSY;
  509.     }
  510.  
  511.     data_buffer = malloc(n, 0);
  512.  
  513.     /* NOTE: this is not strictly from a syscall... but that shouldn't
  514.      * be a problem */
  515.     rc = copy_from_uspace(data_buffer, (void *)uspace_addr, n);
  516.     mutex_unlock(&TASK->udebug.lock);
  517.  
  518.     if (rc != 0) return rc;
  519.  
  520.     *buffer = data_buffer;
  521.     return 0;
  522. }
  523.  
  524. /** @}
  525.  */
  526.