Subversion Repositories HelenOS

Rev

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