Subversion Repositories HelenOS

Rev

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