Subversion Repositories HelenOS

Rev

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