Subversion Repositories HelenOS

Rev

Rev 2867 | Rev 2898 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /** @addtogroup generic
  2.  * @{
  3.  */
  4.  
  5. /**
  6.  * @file
  7.  * @brief   Tdebug.
  8.  */
  9.  
  10. #include <synch/waitq.h>
  11. #include <console/klog.h>
  12. #include <udebug/udebug.h>
  13. #include <errno.h>
  14. #include <arch.h>
  15.  
  16. void udebug_stoppable_begin(void)
  17. {
  18.     int nsc;
  19.     call_t *db_call;
  20.     ipl_t ipl;
  21.  
  22.     ipl = interrupts_disable();
  23.     spinlock_lock(&TASK->lock);
  24.  
  25.     nsc = --TASK->not_stoppable_count;
  26.     db_call = TASK->debug_begin_call;
  27.  
  28.     if (TASK->dt_state == UDEBUG_TS_BEGINNING) {
  29.         klog_printf("udebug_stoppable_begin");
  30.         klog_printf(" - nsc := %d", nsc);
  31.     }
  32.  
  33.     if (TASK->dt_state == UDEBUG_TS_BEGINNING && nsc == 0) {
  34.         TASK->dt_state = UDEBUG_TS_ACTIVE;
  35.         TASK->debug_begin_call = NULL;
  36.         spinlock_unlock(&TASK->lock);
  37.         interrupts_restore(ipl);
  38.  
  39.         IPC_SET_RETVAL(db_call->data, 0);
  40.         klog_printf("udebug_stoppable_begin/ipc_answer");
  41.         ipc_answer(&TASK->answerbox, db_call);     
  42.     } else {
  43.             spinlock_unlock(&TASK->lock);
  44.         interrupts_restore(ipl);
  45.     }
  46. }
  47.  
  48. void udebug_stoppable_end(void)
  49. {
  50.     ipl_t ipl;
  51.  
  52. restart:
  53.     ipl = interrupts_disable();
  54.     spinlock_lock(&TASK->lock);
  55.  
  56.     if ((TASK->dt_state == UDEBUG_TS_BEGINNING ||
  57.         TASK->dt_state == UDEBUG_TS_ACTIVE) &&
  58.         THREAD->debug_stop == true) {
  59.         TASK->debug_begin_call = NULL;
  60.         spinlock_unlock(&TASK->lock);
  61.         interrupts_restore(ipl);
  62.  
  63.         klog_printf("udebug_stoppable_end: waitq_sleep");
  64.         waitq_sleep(&THREAD->go_wq);
  65.         goto restart;
  66.         /* must try again - have to lose stoppability atomically */
  67.     } else {
  68.         ++TASK->not_stoppable_count;
  69.         spinlock_unlock(&TASK->lock);
  70.         interrupts_restore(ipl);
  71.     }
  72. }
  73.  
  74. void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3,
  75.     unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc)
  76. {
  77.     call_t *call;
  78.     ipl_t ipl;
  79.  
  80.     ipl = interrupts_disable();
  81.     spinlock_lock(&THREAD->debug_lock);
  82.  
  83.     /* Must only generate events when in debugging session and have go */
  84.     if (THREAD->debug_active != true ||
  85.         THREAD->debug_stop == true) {
  86.         spinlock_unlock(&THREAD->debug_lock);
  87.         interrupts_restore(ipl);
  88.         return;
  89.     }
  90.  
  91.     klog_printf("udebug_syscall_event");
  92.     call = THREAD->debug_go_call;
  93.     IPC_SET_RETVAL(call->data, 0);
  94.     IPC_SET_ARG1(call->data, UDEBUG_EVENT_SYSCALL);
  95.     IPC_SET_ARG2(call->data, id);
  96.     IPC_SET_ARG3(call->data, rc);
  97.     klog_printf("udebug_syscall_event/ipc_answer");
  98.  
  99.     THREAD->syscall_args[0] = a1;
  100.     THREAD->syscall_args[1] = a2;
  101.     THREAD->syscall_args[2] = a3;
  102.     THREAD->syscall_args[3] = a4;
  103.     THREAD->syscall_args[4] = a5;
  104.     THREAD->syscall_args[5] = a6;
  105.  
  106.     /*
  107.      * Make sure debug_stop is true when going to sleep
  108.      * in case we get woken up by DEBUG_END. (At which
  109.      * point it must be back to the initial true value).
  110.      */
  111.     THREAD->debug_stop = true;
  112.  
  113.     THREAD->cur_event = UDEBUG_EVENT_SYSCALL;
  114.     spinlock_unlock(&THREAD->debug_lock);
  115.  
  116.     spinlock_lock(&TASK->lock);
  117.     ipc_answer(&TASK->answerbox, THREAD->debug_go_call);
  118.     spinlock_unlock(&TASK->lock);
  119.  
  120.     interrupts_restore(ipl);
  121.  
  122.     waitq_sleep(&THREAD->go_wq);
  123. }
  124.  
  125. void udebug_new_thread_event(struct thread *t)
  126. {
  127.     call_t *call;
  128.     ipl_t ipl;
  129.  
  130.     ipl = interrupts_disable();
  131.     spinlock_lock(&THREAD->debug_lock);
  132.  
  133.     klog_printf("udebug_new_thread_event");
  134.     klog_printf("- check state");
  135.  
  136.     /* Must only generate events when in debugging session */
  137.     if (THREAD->debug_active != true) {
  138.         klog_printf("- debug_active: %s, debug_stop: %s",
  139.             THREAD->debug_active ? "yes(+)" : "no(-)",
  140.             THREAD->debug_stop ? "yes(-)" : "no(+)");
  141.         spinlock_unlock(&THREAD->debug_lock);
  142.         interrupts_restore(ipl);
  143.         return;
  144.     }
  145.  
  146.     klog_printf("- trigger event");
  147.  
  148.     call = THREAD->debug_go_call;
  149.     IPC_SET_RETVAL(call->data, 0);
  150.     IPC_SET_ARG1(call->data, UDEBUG_EVENT_NEW_THREAD);
  151.     IPC_SET_ARG2(call->data, (unative_t)t);
  152.  
  153.     /*
  154.      * Make sure debug_stop is true when going to sleep
  155.      * in case we get woken up by DEBUG_END. (At which
  156.      * point it must be back to the initial true value).
  157.      */
  158.     THREAD->debug_stop = true;
  159.  
  160.     THREAD->cur_event = UDEBUG_EVENT_NEW_THREAD;
  161.     spinlock_unlock(&THREAD->debug_lock);
  162.  
  163.     spinlock_lock(&TASK->lock);
  164.     ipc_answer(&TASK->answerbox, THREAD->debug_go_call);
  165.     spinlock_unlock(&TASK->lock);
  166.  
  167.     interrupts_restore(ipl);
  168.     klog_printf("- sleep");
  169.  
  170.     waitq_sleep(&THREAD->go_wq);
  171. }
  172.  
  173. /**
  174.  * Terminate task debugging session.
  175.  *
  176.  * \param ta Must be already locked and interrupts must be disabled.
  177.  * \return Zero on success or negative error code.
  178.  */
  179. int udebug_task_cleanup(struct task *ta)
  180. {
  181.     thread_t *t;
  182.     link_t *cur;
  183.     int flags;
  184.  
  185.     klog_printf("udebug_task_cleanup()");
  186.     klog_printf("task %llu", ta->taskid);
  187.  
  188.     if (ta->dt_state == UDEBUG_TS_BEGINNING &&
  189.         ta->dt_state != UDEBUG_TS_ACTIVE) {
  190.         klog_printf("udebug_task_cleanup(): task not being debugged");
  191.         return EINVAL;
  192.     }
  193.  
  194.     /* Finish debugging of all userspace threads */
  195.     for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
  196.         t = list_get_instance(cur, thread_t, th_link);
  197.  
  198.         spinlock_lock(&t->debug_lock);
  199.         spinlock_lock(&t->lock);
  200.  
  201.         flags = t->flags;
  202.  
  203.         spinlock_unlock(&t->lock);
  204.  
  205.         /* Only process userspace threads */
  206.         if ((flags & THREAD_FLAG_USPACE) != 0) {
  207.             /* Prevent any further debug activity in thread */
  208.             t->debug_active = false;
  209.             t->cur_event = 0;   /* none */
  210.  
  211.             /* Still has go? */
  212.             if (t->debug_stop == false) {
  213.                 /*
  214.                 * Yes, so clear go. As debug_active == false,
  215.                  * this doesn't affect anything.
  216.                  */
  217.                 t->debug_stop = true;  
  218.  
  219.                 /* Answer GO call */
  220.                 klog_printf("answer GO call with EVENT_FINISHED");
  221.                 IPC_SET_RETVAL(t->debug_go_call->data, 0);
  222.                 IPC_SET_ARG1(t->debug_go_call->data, UDEBUG_EVENT_FINISHED);
  223.                 ipc_answer(&ta->answerbox, t->debug_go_call);
  224.             } else {
  225.                 /*
  226.                  * Debug_stop is already at initial value.
  227.                  * Yet this means the thread needs waking up.
  228.                  */
  229.  
  230.                 /*
  231.                  * t's lock must not be held when calling
  232.                  * waitq_wakeup.
  233.                  */
  234.                 waitq_wakeup(&t->go_wq, WAKEUP_FIRST);
  235.             }
  236.         }
  237.         spinlock_unlock(&t->debug_lock);
  238.     }
  239.  
  240.     ta->dt_state = UDEBUG_TS_INACTIVE;
  241.     ta->debugger = NULL;
  242.  
  243.     return 0;
  244. }
  245.  
  246.  
  247. /** @}
  248.  */
  249.