Subversion Repositories HelenOS

Rev

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