Subversion Repositories HelenOS

Rev

Rev 2899 | Rev 2902 | 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.
  36.  */
  37.  
  38. #include <synch/waitq.h>
  39. #include <console/klog.h>
  40. #include <udebug/udebug.h>
  41. #include <errno.h>
  42. #include <arch.h>
  43.  
  44. void udebug_stoppable_begin(void)
  45. {
  46.     int nsc;
  47.     call_t *db_call, *go_call;
  48.     ipl_t ipl;
  49.  
  50.     ipl = interrupts_disable();
  51.     spinlock_lock(&TASK->lock);
  52.  
  53.     nsc = --TASK->not_stoppable_count;
  54.     db_call = TASK->debug_begin_call;
  55.  
  56.     if (TASK->dt_state == UDEBUG_TS_BEGINNING) {
  57.         klog_printf("udebug_stoppable_begin");
  58.         klog_printf(" - nsc := %d", nsc);
  59.     }
  60.  
  61.     if (TASK->dt_state == UDEBUG_TS_BEGINNING && nsc == 0) {
  62.         /*
  63.          * This was the last non-stoppable thread. Reply to
  64.          * DEBUG_BEGIN call.
  65.          */
  66.  
  67.         /* Lock order OK, THREAD->debug_lock is after TASK->lock */
  68.         spinlock_lock(&THREAD->debug_lock);
  69.         THREAD->debug_stoppable = true;
  70.         spinlock_unlock(&THREAD->debug_lock);
  71.  
  72.         TASK->dt_state = UDEBUG_TS_ACTIVE;
  73.         TASK->debug_begin_call = NULL;
  74.         spinlock_unlock(&TASK->lock);
  75.         interrupts_restore(ipl);
  76.  
  77.         IPC_SET_RETVAL(db_call->data, 0);
  78.         klog_printf("udebug_stoppable_begin/ipc_answer");
  79.         ipc_answer(&TASK->answerbox, db_call);     
  80.  
  81.     } else if (TASK->dt_state == UDEBUG_TS_ACTIVE) {
  82.         /*
  83.          * Active debugging session
  84.          */
  85.  
  86.         /* Lock order OK, THREAD->debug_lock is after TASK->lock */
  87.         spinlock_lock(&THREAD->debug_lock);
  88.         THREAD->debug_stoppable = true;
  89.  
  90.         if (THREAD->debug_stop) {
  91.             /*
  92.              * Thread was requested to stop - answer go call
  93.              */
  94.  
  95.             /* Make sure nobody takes this call away from us */
  96.             go_call = THREAD->debug_go_call;
  97.             THREAD->debug_go_call = NULL;
  98.  
  99.             IPC_SET_RETVAL(go_call->data, 0);
  100.             IPC_SET_ARG1(go_call->data, UDEBUG_EVENT_STOP);
  101.  
  102.             THREAD->cur_event = UDEBUG_EVENT_STOP;
  103.             spinlock_unlock(&THREAD->debug_lock);
  104.  
  105.                 ipc_answer(&TASK->answerbox, go_call);
  106.  
  107.                 spinlock_unlock(&TASK->lock);
  108.             interrupts_restore(ipl);
  109.         } else {
  110.             /*
  111.              * No stop request - nothing happens.
  112.              */
  113.             spinlock_unlock(&THREAD->debug_lock);
  114.                 spinlock_unlock(&TASK->lock);
  115.             interrupts_restore(ipl);
  116.         }
  117.     } else {
  118.         /*
  119.          * All other cases - nothing special happens.
  120.          */
  121.  
  122.         /* Lock order OK, THREAD->debug_lock is after TASK->lock */
  123.         spinlock_lock(&THREAD->debug_lock);
  124.         THREAD->debug_stoppable = true;
  125.         spinlock_unlock(&THREAD->debug_lock);
  126.  
  127.             spinlock_unlock(&TASK->lock);
  128.         interrupts_restore(ipl);
  129.     }
  130. }
  131.  
  132. void udebug_stoppable_end(void)
  133. {
  134.     ipl_t ipl;
  135.  
  136. restart:
  137.     ipl = interrupts_disable();
  138.     spinlock_lock(&TASK->lock);
  139.  
  140.     /* Lock order OK, THREAD->debug_lock is after TASK->lock */
  141.     spinlock_lock(&THREAD->debug_lock);
  142.  
  143.     if (TASK->dt_state == UDEBUG_TS_ACTIVE) {
  144.         klog_printf("udebug_stoppable_end");
  145.         klog_printf("debug_stop=%d", THREAD->debug_stop);
  146.     }
  147.  
  148.     if ((TASK->dt_state == UDEBUG_TS_BEGINNING ||
  149.         TASK->dt_state == UDEBUG_TS_ACTIVE) &&
  150.         THREAD->debug_stop == true) {
  151.         TASK->debug_begin_call = NULL;
  152.         spinlock_unlock(&THREAD->debug_lock);
  153.         spinlock_unlock(&TASK->lock);
  154.         interrupts_restore(ipl);
  155.  
  156.         klog_printf("udebug_stoppable_end: waitq_sleep");
  157.         waitq_sleep(&THREAD->go_wq);
  158.         goto restart;
  159.         /* must try again - have to lose stoppability atomically */
  160.     } else {
  161.         ++TASK->not_stoppable_count;
  162.         THREAD->debug_stoppable = false;
  163.  
  164.         spinlock_unlock(&THREAD->debug_lock);
  165.         spinlock_unlock(&TASK->lock);
  166.         interrupts_restore(ipl);
  167.     }
  168. }
  169.  
  170. void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3,
  171.     unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc,
  172.     bool end_variant)
  173. {
  174.     call_t *call;
  175.     ipl_t ipl;
  176.     udebug_event_t etype;
  177.  
  178.     etype = end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B;
  179.  
  180.     ipl = interrupts_disable();
  181.     spinlock_lock(&THREAD->debug_lock);
  182.  
  183.     /* Must only generate events when in debugging session and have go */
  184.     if (THREAD->debug_active != true ||
  185.         THREAD->debug_stop == true ||
  186.         (TASK->debug_evmask & UDEBUG_EVMASK(etype)) == 0) {
  187.         spinlock_unlock(&THREAD->debug_lock);
  188.         interrupts_restore(ipl);
  189.         return;
  190.     }
  191.  
  192.     klog_printf("udebug_syscall_event");
  193.     call = THREAD->debug_go_call;
  194.     IPC_SET_RETVAL(call->data, 0);
  195.     IPC_SET_ARG1(call->data, etype);
  196.     IPC_SET_ARG2(call->data, id);
  197.     IPC_SET_ARG3(call->data, rc);
  198.     klog_printf("udebug_syscall_event/ipc_answer");
  199.  
  200.     THREAD->syscall_args[0] = a1;
  201.     THREAD->syscall_args[1] = a2;
  202.     THREAD->syscall_args[2] = a3;
  203.     THREAD->syscall_args[3] = a4;
  204.     THREAD->syscall_args[4] = a5;
  205.     THREAD->syscall_args[5] = a6;
  206.  
  207.     /*
  208.      * Make sure debug_stop is true when going to sleep
  209.      * in case we get woken up by DEBUG_END. (At which
  210.      * point it must be back to the initial true value).
  211.      */
  212.     THREAD->debug_stop = true;
  213.  
  214.     THREAD->cur_event = etype;
  215.     spinlock_unlock(&THREAD->debug_lock);
  216.  
  217.     spinlock_lock(&TASK->lock);
  218.     ipc_answer(&TASK->answerbox, THREAD->debug_go_call);
  219.     spinlock_unlock(&TASK->lock);
  220.  
  221.     interrupts_restore(ipl);
  222.  
  223.     waitq_sleep(&THREAD->go_wq);
  224. }
  225.  
  226. void udebug_new_thread_event(struct thread *t)
  227. {
  228.     call_t *call;
  229.     ipl_t ipl;
  230.  
  231.     ipl = interrupts_disable();
  232.     spinlock_lock(&THREAD->debug_lock);
  233.  
  234.     klog_printf("udebug_new_thread_event");
  235.     klog_printf("- check state");
  236.  
  237.     /* Must only generate events when in debugging session */
  238.     if (THREAD->debug_active != true) {
  239.         klog_printf("- debug_active: %s, debug_stop: %s",
  240.             THREAD->debug_active ? "yes(+)" : "no(-)",
  241.             THREAD->debug_stop ? "yes(-)" : "no(+)");
  242.         spinlock_unlock(&THREAD->debug_lock);
  243.         interrupts_restore(ipl);
  244.         return;
  245.     }
  246.  
  247.     klog_printf("- trigger event");
  248.  
  249.     call = THREAD->debug_go_call;
  250.     IPC_SET_RETVAL(call->data, 0);
  251.     IPC_SET_ARG1(call->data, UDEBUG_EVENT_NEW_THREAD);
  252.     IPC_SET_ARG2(call->data, (unative_t)t);
  253.  
  254.     /*
  255.      * Make sure debug_stop is true when going to sleep
  256.      * in case we get woken up by DEBUG_END. (At which
  257.      * point it must be back to the initial true value).
  258.      */
  259.     THREAD->debug_stop = true;
  260.  
  261.     THREAD->cur_event = UDEBUG_EVENT_NEW_THREAD;
  262.     spinlock_unlock(&THREAD->debug_lock);
  263.  
  264.     spinlock_lock(&TASK->lock);
  265.     ipc_answer(&TASK->answerbox, THREAD->debug_go_call);
  266.     spinlock_unlock(&TASK->lock);
  267.  
  268.     interrupts_restore(ipl);
  269.     klog_printf("- sleep");
  270.  
  271.     waitq_sleep(&THREAD->go_wq);
  272. }
  273.  
  274. /**
  275.  * Terminate task debugging session.
  276.  *
  277.  * \param ta Must be already locked and interrupts must be disabled.
  278.  * \return Zero on success or negative error code.
  279.  */
  280. int udebug_task_cleanup(struct task *ta)
  281. {
  282.     thread_t *t;
  283.     link_t *cur;
  284.     int flags;
  285.  
  286.     klog_printf("udebug_task_cleanup()");
  287.     klog_printf("task %llu", ta->taskid);
  288.  
  289.     if (ta->dt_state == UDEBUG_TS_BEGINNING &&
  290.         ta->dt_state != UDEBUG_TS_ACTIVE) {
  291.         klog_printf("udebug_task_cleanup(): task not being debugged");
  292.         return EINVAL;
  293.     }
  294.  
  295.     /* Finish debugging of all userspace threads */
  296.     for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
  297.         t = list_get_instance(cur, thread_t, th_link);
  298.  
  299.         spinlock_lock(&t->debug_lock);
  300.         spinlock_lock(&t->lock);
  301.  
  302.         flags = t->flags;
  303.  
  304.         spinlock_unlock(&t->lock);
  305.  
  306.         /* Only process userspace threads */
  307.         if ((flags & THREAD_FLAG_USPACE) != 0) {
  308.             /* Prevent any further debug activity in thread */
  309.             t->debug_active = false;
  310.             t->cur_event = 0;   /* none */
  311.  
  312.             /* Still has go? */
  313.             if (t->debug_stop == false) {
  314.                 /*
  315.                 * Yes, so clear go. As debug_active == false,
  316.                  * this doesn't affect anything.
  317.                  */
  318.                 t->debug_stop = true;  
  319.  
  320.                 /* Answer GO call */
  321.                 klog_printf("answer GO call with EVENT_FINISHED");
  322.                 IPC_SET_RETVAL(t->debug_go_call->data, 0);
  323.                 IPC_SET_ARG1(t->debug_go_call->data, UDEBUG_EVENT_FINISHED);
  324.                 ipc_answer(&ta->answerbox, t->debug_go_call);
  325.             } else {
  326.                 /*
  327.                  * Debug_stop is already at initial value.
  328.                  * Yet this means the thread needs waking up.
  329.                  */
  330.  
  331.                 /*
  332.                  * t's lock must not be held when calling
  333.                  * waitq_wakeup.
  334.                  */
  335.                 waitq_wakeup(&t->go_wq, WAKEUP_FIRST);
  336.             }
  337.         }
  338.         spinlock_unlock(&t->debug_lock);
  339.     }
  340.  
  341.     ta->dt_state = UDEBUG_TS_INACTIVE;
  342.     ta->debugger = NULL;
  343.  
  344.     return 0;
  345. }
  346.  
  347.  
  348. /** @}
  349.  */
  350.