Subversion Repositories HelenOS

Rev

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