Subversion Repositories HelenOS

Rev

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