Subversion Repositories HelenOS

Rev

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