Subversion Repositories HelenOS

Rev

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