Subversion Repositories HelenOS

Rev

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