Subversion Repositories HelenOS

Rev

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