Subversion Repositories HelenOS

Rev

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