Subversion Repositories HelenOS

Rev

Rev 3441 | Rev 3468 | 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->stop = true;
  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 && THREAD->udebug.stop) {
  202.             /*
  203.              * Thread was requested to stop - answer go call
  204.              */
  205.  
  206.             /* Make sure nobody takes this call away from us */
  207.             go_call = THREAD->udebug.go_call;
  208.             THREAD->udebug.go_call = NULL;
  209.             ASSERT(go_call);
  210.  
  211.             IPC_SET_RETVAL(go_call->data, 0);
  212.             IPC_SET_ARG1(go_call->data, UDEBUG_EVENT_STOP);
  213.  
  214.             THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
  215.  
  216.                 ipc_answer(&TASK->answerbox, go_call);
  217.         }
  218.     }
  219.  
  220.     mutex_unlock(&THREAD->udebug.lock);
  221.         mutex_unlock(&TASK->udebug.lock);
  222. }
  223.  
  224. /** End of a stoppable section.
  225.  *
  226.  * This is the point where the thread will block if it is stopped.
  227.  * (As, by definition, a stopped thread must not leave its stoppable section).
  228.  */
  229. void udebug_stoppable_end(void)
  230. {
  231.     /* Early check for undebugged tasks */
  232.     if (!udebug_thread_precheck()) {
  233.         udebug_int_unlock();
  234.         return;
  235.     }
  236.  
  237. restart:
  238.     mutex_lock(&TASK->udebug.lock);
  239.     mutex_lock(&THREAD->udebug.lock);
  240.  
  241.     if (THREAD->udebug.debug_active &&
  242.         THREAD->udebug.stop == true) {
  243.         TASK->udebug.begin_call = NULL;
  244.         mutex_unlock(&THREAD->udebug.lock);
  245.         mutex_unlock(&TASK->udebug.lock);
  246.  
  247.         udebug_wait_for_go(&THREAD->udebug.go_wq);
  248.  
  249.         goto restart;
  250.         /* must try again - have to lose stoppability atomically */
  251.     } else {
  252.         ++TASK->udebug.not_stoppable_count;
  253.         ASSERT(THREAD->udebug.stoppable == true);
  254.         THREAD->udebug.stoppable = false;
  255.  
  256.         mutex_unlock(&THREAD->udebug.lock);
  257.         mutex_unlock(&TASK->udebug.lock);
  258.     }
  259.  
  260.     udebug_int_unlock();
  261. }
  262.  
  263. /** Upon being scheduled to run, check if the current thread should stop.
  264.  *
  265.  * This function is called from clock(). Preemption is enabled.
  266.  * interrupts are disabled, but since this is called after
  267.  * being scheduled-in, we can enable them, if we're careful enough
  268.  * not to allow arbitrary recursion or deadlock with the thread context.
  269.  */
  270. void udebug_before_thread_runs(void)
  271. {
  272.     ipl_t ipl;
  273.  
  274.     return;
  275.     ASSERT(!PREEMPTION_DISABLED);
  276.  
  277.     /*
  278.      * Prevent agains re-entering, such as when preempted inside this
  279.      * function.
  280.      */
  281.     if (atomic_get(&THREAD->udebug.int_lock) != 0)
  282.         return;
  283.  
  284.     udebug_int_lock();
  285.  
  286.     ipl = interrupts_enable();
  287.  
  288.     /* Now we're free to do whatever we need (lock mutexes, sleep, etc.) */
  289.  
  290.     /* Check if we're supposed to stop */
  291.     udebug_stoppable_begin();
  292.     udebug_stoppable_end();
  293.  
  294.     interrupts_restore(ipl);
  295.  
  296.     udebug_int_unlock();
  297. }
  298.  
  299. /** Syscall event hook.
  300.  *
  301.  * Must be called before and after servicing a system call. This generates
  302.  * a SYSCALL_B or SYSCALL_E event, depending on the value of @a end_variant.
  303.  */
  304. void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3,
  305.     unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc,
  306.     bool end_variant)
  307. {
  308.     call_t *call;
  309.     udebug_event_t etype;
  310.  
  311.     etype = end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B;
  312.  
  313.     udebug_int_lock();
  314.  
  315.     /* Early check for undebugged tasks */
  316.     if (!udebug_thread_precheck()) {
  317.         udebug_int_unlock();
  318.         return;
  319.     }
  320.  
  321.     mutex_lock(&TASK->udebug.lock);
  322.     mutex_lock(&THREAD->udebug.lock);
  323.  
  324.     /* Must only generate events when in debugging session and have go */
  325.     if (THREAD->udebug.debug_active != true ||
  326.         THREAD->udebug.stop == true ||
  327.         (TASK->udebug.evmask & UDEBUG_EVMASK(etype)) == 0) {
  328.         mutex_unlock(&THREAD->udebug.lock);
  329.         mutex_unlock(&TASK->udebug.lock);
  330.         return;
  331.     }
  332.  
  333.     //printf("udebug_syscall_event\n");
  334.     call = THREAD->udebug.go_call;
  335.     THREAD->udebug.go_call = NULL;
  336.  
  337.     IPC_SET_RETVAL(call->data, 0);
  338.     IPC_SET_ARG1(call->data, etype);
  339.     IPC_SET_ARG2(call->data, id);
  340.     IPC_SET_ARG3(call->data, rc);
  341.     //printf("udebug_syscall_event/ipc_answer\n");
  342.  
  343.     THREAD->udebug.syscall_args[0] = a1;
  344.     THREAD->udebug.syscall_args[1] = a2;
  345.     THREAD->udebug.syscall_args[2] = a3;
  346.     THREAD->udebug.syscall_args[3] = a4;
  347.     THREAD->udebug.syscall_args[4] = a5;
  348.     THREAD->udebug.syscall_args[5] = a6;
  349.  
  350.     /*
  351.      * Make sure udebug.stop is true when going to sleep
  352.      * in case we get woken up by DEBUG_END. (At which
  353.      * point it must be back to the initial true value).
  354.      */
  355.     THREAD->udebug.stop = true;
  356.     THREAD->udebug.cur_event = etype;
  357.  
  358.     ipc_answer(&TASK->answerbox, call);
  359.  
  360.     mutex_unlock(&THREAD->udebug.lock);
  361.     mutex_unlock(&TASK->udebug.lock);
  362.  
  363.     udebug_wait_for_go(&THREAD->udebug.go_wq);
  364.  
  365.     udebug_int_unlock();
  366. }
  367.  
  368. /** Thread-creation event hook.
  369.  *
  370.  * Must be called when a new userspace thread is created in the debugged
  371.  * task. Generates a THREAD_B event.
  372.  *
  373.  * @param t Structure of the thread being created. Not locked, as the
  374.  *      thread is not executing yet.
  375.  */
  376. void udebug_thread_b_event(struct thread *t)
  377. {
  378.     call_t *call;
  379.  
  380.     udebug_int_lock();
  381.  
  382.     mutex_lock(&TASK->udebug.lock);
  383.     mutex_lock(&THREAD->udebug.lock);
  384.  
  385.     LOG("udebug_thread_b_event\n");
  386.     LOG("- check state\n");
  387.  
  388.     /* Must only generate events when in debugging session */
  389.     if (THREAD->udebug.debug_active != true) {
  390.         LOG("- debug_active: %s, udebug.stop: %s\n",
  391.             THREAD->udebug.debug_active ? "yes(+)" : "no(-)",
  392.             THREAD->udebug.stop ? "yes(-)" : "no(+)");
  393.         mutex_unlock(&THREAD->udebug.lock);
  394.         mutex_unlock(&TASK->udebug.lock);
  395.         return;
  396.     }
  397.  
  398.     LOG("- trigger event\n");
  399.  
  400.     call = THREAD->udebug.go_call;
  401.     THREAD->udebug.go_call = NULL;
  402.     IPC_SET_RETVAL(call->data, 0);
  403.     IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_B);
  404.     IPC_SET_ARG2(call->data, (unative_t)t);
  405.  
  406.     /*
  407.      * Make sure udebug.stop is true when going to sleep
  408.      * in case we get woken up by DEBUG_END. (At which
  409.      * point it must be back to the initial true value).
  410.      */
  411.     THREAD->udebug.stop = true;
  412.     THREAD->udebug.cur_event = UDEBUG_EVENT_THREAD_B;
  413.  
  414.     ipc_answer(&TASK->answerbox, call);
  415.  
  416.     mutex_unlock(&THREAD->udebug.lock);
  417.     mutex_unlock(&TASK->udebug.lock);
  418.  
  419.     LOG("- sleep\n");
  420.     udebug_wait_for_go(&THREAD->udebug.go_wq);
  421.  
  422.     udebug_int_unlock();
  423. }
  424.  
  425. /** Thread-termination event hook.
  426.  *
  427.  * Must be called when the current thread is terminating.
  428.  * Generates a THREAD_E event.
  429.  */
  430. void udebug_thread_e_event(void)
  431. {
  432.     call_t *call;
  433.  
  434.     udebug_int_lock();
  435.  
  436.     mutex_lock(&TASK->udebug.lock);
  437.     mutex_lock(&THREAD->udebug.lock);
  438.  
  439.     LOG("udebug_thread_e_event\n");
  440.     LOG("- check state\n");
  441.  
  442.     /* Must only generate events when in debugging session */
  443.     if (THREAD->udebug.debug_active != true) {
  444. /*      printf("- debug_active: %s, udebug.stop: %s\n",
  445.             THREAD->udebug.debug_active ? "yes(+)" : "no(-)",
  446.             THREAD->udebug.stop ? "yes(-)" : "no(+)");*/
  447.         mutex_unlock(&THREAD->udebug.lock);
  448.         mutex_unlock(&TASK->udebug.lock);
  449.         return;
  450.     }
  451.  
  452.     LOG("- trigger event\n");
  453.  
  454.     call = THREAD->udebug.go_call;
  455.     THREAD->udebug.go_call = NULL;
  456.     IPC_SET_RETVAL(call->data, 0);
  457.     IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_E);
  458.  
  459.     /* Prevent any further debug activity in thread */
  460.     THREAD->udebug.debug_active = false;
  461.     THREAD->udebug.cur_event = 0;       /* none */
  462.     THREAD->udebug.stop = true; /* set to initial value */
  463.  
  464.     ipc_answer(&TASK->answerbox, call);
  465.  
  466.     mutex_unlock(&THREAD->udebug.lock);
  467.     mutex_unlock(&TASK->udebug.lock);
  468.  
  469.     /* Leave int_lock enabled */
  470.     /* This event does not sleep - debugging has finished in this thread */
  471. }
  472.  
  473. /**
  474.  * Terminate task debugging session.
  475.  *
  476.  * Gracefully terminates the debugging session for a task. If the debugger
  477.  * is still waiting for events on some threads, it will receive a
  478.  * FINISHED event for each of them.
  479.  *
  480.  * @param ta    Task structure. ta->udebug.lock must be already locked.
  481.  * @return  Zero on success or negative error code.
  482.  */
  483. int udebug_task_cleanup(struct task *ta)
  484. {
  485.     thread_t *t;
  486.     link_t *cur;
  487.     int flags;
  488.     ipl_t ipl;
  489.  
  490.     LOG("udebug_task_cleanup()\n");
  491.     LOG("task %" PRIu64 "\n", ta->taskid);
  492.  
  493.     udebug_int_lock();
  494.  
  495.     if (ta->udebug.dt_state != UDEBUG_TS_BEGINNING &&
  496.         ta->udebug.dt_state != UDEBUG_TS_ACTIVE) {
  497.         LOG("udebug_task_cleanup(): task not being debugged\n");
  498.         return EINVAL;
  499.     }
  500.  
  501.     /* Finish debugging of all userspace threads */
  502.     for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
  503.         t = list_get_instance(cur, thread_t, th_link);
  504.  
  505.         mutex_lock(&t->udebug.lock);
  506.  
  507.         ipl = interrupts_disable();
  508.         spinlock_lock(&t->lock);
  509.  
  510.         flags = t->flags;
  511.  
  512.         spinlock_unlock(&t->lock);
  513.         interrupts_restore(ipl);
  514.  
  515.         /* Only process userspace threads */
  516.         if ((flags & THREAD_FLAG_USPACE) != 0) {
  517.             /* Prevent any further debug activity in thread */
  518.             t->udebug.debug_active = false;
  519.             t->udebug.cur_event = 0;    /* none */
  520.  
  521.             /* Still has go? */
  522.             if (t->udebug.stop == false) {
  523.                 /*
  524.                 * Yes, so clear go. As debug_active == false,
  525.                  * this doesn't affect anything.
  526.                  */
  527.                 t->udebug.stop = true; 
  528.  
  529.                 /* Answer GO call */
  530.                 LOG("answer GO call with EVENT_FINISHED\n");
  531.                 IPC_SET_RETVAL(t->udebug.go_call->data, 0);
  532.                 IPC_SET_ARG1(t->udebug.go_call->data, UDEBUG_EVENT_FINISHED);
  533.  
  534.                 ipc_answer(&ta->answerbox, t->udebug.go_call);
  535.                 t->udebug.go_call = NULL;
  536.             } else {
  537.                 /*
  538.                  * Debug_stop is already at initial value.
  539.                  * Yet this means the thread needs waking up.
  540.                  */
  541.  
  542.                 /*
  543.                  * t's lock must not be held when calling
  544.                  * waitq_wakeup.
  545.                  */
  546.                 waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
  547.             }
  548.         }
  549.         mutex_unlock(&t->udebug.lock);
  550.     }
  551.  
  552.     ta->udebug.dt_state = UDEBUG_TS_INACTIVE;
  553.     ta->udebug.debugger = NULL;
  554.  
  555.     udebug_int_unlock();
  556.  
  557.     return 0;
  558. }
  559.  
  560.  
  561. /** @}
  562.  */
  563.