Subversion Repositories HelenOS

Rev

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