Subversion Repositories HelenOS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /** @addtogroup tdebug
  2.  * @{
  3.  */
  4.  
  5. /**
  6.  * @file
  7.  * @brief   Task Debugging.
  8.  */
  9.  
  10. #include <arch.h>
  11. #include <atomic.h>
  12. #include <ipc/ipc.h>
  13. #include <proc/task.h>
  14. #include <synch/spinlock.h>
  15. #include <synch/waitq.h>
  16. #include <console/klog.h>
  17. #include <errno.h>
  18. //#include <arch/tdebug.h>
  19. #include <tdebug/tdebug.h>
  20.  
  21. //FIXME: need to reset tdebug_thread structure for each thread
  22. //either on monitor attach or on monitor detach
  23.  
  24. static void _tdebug_send_msg(task_t *ta, unative_t method, unative_t a1, unative_t a2,
  25.     unative_t a3, unative_t a4, unative_t a5);
  26.  
  27. void tdebug_task_init(struct task *ta)
  28. {
  29.     atomic_set(&ta->tdebug.have_monitor, 0);
  30.     ta->tdebug.monitor = NULL;
  31.     list_initialize(&ta->tdebug.targets);
  32. }
  33.  
  34. /**
  35.  * Initialize the tdebug part of a thread structure.
  36.  */
  37. void tdebug_thread_init(struct thread *t)
  38. {
  39.     t->tdebug.stopped = 0;
  40.     condvar_initialize(&t->tdebug.stopped_cv);
  41.     t->tdebug.stop_request = 0;
  42.     t->tdebug.event_mask = TDEBUG_EVMASK_SYSCALL | TDEBUG_EVMASK_EXCEPTION;
  43.  
  44.     t->tdebug.syscall_args = NULL;
  45. }
  46.  
  47. /**
  48.  * Clean-up all tdebug activities of the current task.
  49.  */
  50. void tdebug_cleanup(void)
  51. {
  52.     ipl_t ipl;
  53.     task_t *mon_task;
  54.  
  55.     klog_printf("tdebug_cleanup()");
  56.    
  57.     /*
  58.      * First detach any targets monitored by this task.
  59.      */
  60. loop_1:
  61.     ipl = interrupts_disable();
  62.     spinlock_lock(&TASK->lock);
  63.  
  64.     while (TASK->tdebug.targets.next != &TASK->tdebug.targets) {
  65.         link_t *cur = TASK->tdebug.targets.next;
  66.         task_t *ta;
  67.         DEADLOCK_PROBE_INIT(p_target_lock);
  68.  
  69.         klog_printf(" - detaching a target");
  70.  
  71.         ta = list_get_instance(cur, task_t, tdebug.targets_link);
  72.         if (!spinlock_trylock(&ta->lock)) {
  73.             /*
  74.              * Avoid deadlock by trying again.
  75.              */
  76.             spinlock_unlock(&TASK->lock);
  77.             interrupts_restore(ipl);
  78.             DEADLOCK_PROBE(p_target_lock, DEADLOCK_THRESHOLD);
  79.             goto loop_1;
  80.         }
  81.  
  82.         /* this task should be the target's monitor */
  83.         ASSERT(TASK == ta->tdebug.monitor);
  84.         ta->tdebug.monitor = NULL;
  85.  
  86.         list_remove(&ta->tdebug.targets_link);
  87.         spinlock_unlock(&ta->lock);
  88.     }
  89.  
  90.     spinlock_unlock(&TASK->lock);
  91.     interrupts_restore(ipl);
  92.  
  93.     /*
  94.      * Now if this task is being monitored, detach from the monitor.
  95.      */
  96.  
  97. loop_2:
  98.     ipl = interrupts_disable();
  99.     spinlock_lock(&TASK->lock);
  100.     if (TASK->tdebug.monitor != NULL) {
  101.         /* yes, so detach */
  102.         DEADLOCK_PROBE_INIT(p_monitor_lock);
  103.  
  104.         klog_printf(" - detaching from the monitor");
  105.  
  106.         mon_task = TASK->tdebug.monitor;
  107.  
  108.         if (!spinlock_trylock(&mon_task->lock)) {
  109.             /*
  110.              * Avoid deadlock by trying again.
  111.              */
  112.             spinlock_unlock(&TASK->lock);
  113.             interrupts_restore(ipl);
  114.             DEADLOCK_PROBE(p_monitor_lock, DEADLOCK_THRESHOLD);
  115.             goto loop_2;
  116.         }
  117.  
  118.         list_remove(&TASK->tdebug.targets_link);
  119.         TASK->tdebug.monitor = NULL;
  120.  
  121.         spinlock_unlock(&mon_task->lock);
  122.     }
  123.  
  124.     spinlock_unlock(&TASK->lock);
  125.     interrupts_restore(ipl);
  126.  
  127.     klog_printf("tdebug_cleanup done");
  128. }
  129.  
  130. static void _tdebug_clear_event_unsafe(void)
  131. {
  132.     THREAD->tdebug.stopped = 0;
  133.     THREAD->tdebug.syscall_args = NULL;
  134. }
  135.  
  136.  
  137. static void _tdebug_reset_thread_struct_unsafe(void)
  138. {
  139.     _tdebug_clear_event_unsafe();
  140.  
  141.     THREAD->tdebug.stop_request = 0;
  142.     THREAD->tdebug.event_mask = 0;
  143. }
  144.  
  145.  
  146. /**
  147.  * Sleep until the thread is no longer stopped.
  148.  *
  149.  * Go to sleep iff the thread still has stopped==1
  150.  * and sleep until it is resumed.
  151.  *
  152.  * This will also clear the debugging event.!!!!
  153.  */
  154. static void _tdebug_wait_and_clear(void)
  155. {
  156.     ipl_t ipl, ipl2;
  157.     int rc;
  158.     waitq_t *wq;
  159.  
  160.     /* wait until we are resumed */
  161.  
  162.     klog_printf("wait...");
  163.     ipl = interrupts_disable();
  164.     spinlock_lock(&THREAD->lock);
  165.  
  166.     wq = &THREAD->tdebug.stopped_cv.wq;
  167.    
  168.     /*
  169.      * Waiting for THREAD->tdebug.stopped to become 0.
  170.      *
  171.      * This is almost the same as condvar_wait, except that
  172.      * instead of a mutex, the THREAD->lock spinlock is used
  173.      * for mutual exclusion.
  174.      */
  175.  
  176.     while (THREAD->tdebug.stopped != 0) {
  177.         spinlock_unlock(&THREAD->lock);
  178.  
  179.         /* "spinvar_wait()" */
  180.         //printf("waitq_sleep_prepare...\n");
  181.         ipl2 = waitq_sleep_prepare(wq);
  182.         //printf("waitq_sleep_prepare... ok\n");
  183.  
  184.         wq->missed_wakeups = 0;
  185.         rc = waitq_sleep_timeout_unsafe(wq, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE);
  186.  
  187.         spinlock_lock(&THREAD->lock);
  188.         waitq_sleep_finish(wq, rc, ipl2);
  189.     }
  190.  
  191.     _tdebug_clear_event_unsafe();
  192.  
  193.     spinlock_unlock(&THREAD->lock);
  194.     interrupts_restore(ipl);
  195.     klog_printf("done waiting");
  196. }
  197.  
  198.  
  199. /**
  200.  * Send a notification to the monitoring task.
  201.  *
  202.  * Returns 0 on success or -1 if no debugger is present.
  203.  */
  204. static int _tdebug_notify_debugger(thread_id_t tid, unative_t a1,
  205.     unative_t a2, unative_t a3)
  206. {
  207.     unative_t tid_lo, tid_hi;
  208.     ipl_t ipl;
  209.     task_t *monitor;
  210.     DEADLOCK_PROBE_INIT(p_monitor_lock);
  211.  
  212.     tid_lo = tid & 0xffffffff;
  213.     tid_hi = tid >> 16;
  214.  
  215.     /* send notification to the monitoring task */
  216.  
  217. loop:
  218.     ipl = interrupts_disable();
  219.     spinlock_lock(&TASK->lock);
  220.     monitor = TASK->tdebug.monitor;
  221.     if (monitor == NULL) {
  222.         /* there's no monitor anymore */
  223.         spinlock_unlock(&TASK->lock);
  224.  
  225.         /*
  226.          * Reset the debugging struct
  227.          */
  228.         spinlock_lock(&THREAD->lock);
  229.         _tdebug_reset_thread_struct_unsafe();
  230.         spinlock_unlock(&THREAD->lock);
  231.  
  232.         interrupts_restore(ipl);
  233.         return -1;
  234.     }
  235.  
  236.     if (!spinlock_trylock(&monitor->lock)) {
  237.         /*
  238.          * Avoid deadlock by trying again
  239.          */
  240.         spinlock_unlock(&TASK->lock);
  241.         interrupts_restore(ipl);
  242.         DEADLOCK_PROBE(p_monitor_lock, DEADLOCK_THRESHOLD);
  243.         goto loop;
  244.     }
  245.  
  246.     _tdebug_send_msg(TASK->tdebug.monitor, TASK->tdebug.method,
  247.         tid_lo, tid_hi, a1, a2, a3);
  248.  
  249.     spinlock_unlock(&TASK->lock);
  250.     spinlock_unlock(&monitor->lock);
  251.     interrupts_restore(ipl);
  252.  
  253.     return 0;
  254. }
  255.  
  256.  
  257. /**
  258.  * Generate a syscall debug event.
  259.  *
  260.  * Called from syscall_handler() in syscall.c. The current task
  261.  * may or may not have a monitor attached.
  262.  * If a monitor is not attached or syscall events are not enabled,
  263.  * no action is taken.
  264.  */
  265. void tdebug_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 sc_rc)
  267. {
  268.     unative_t sc_args[6];
  269.     ipl_t ipl;
  270.     thread_id_t tid;
  271.  
  272.     klog_printf("TASK %llu: Syscall id %lx", TASK->taskid, id);
  273.     klog_printf("THREAD %llu", THREAD->tid);
  274.  
  275.     /* no need to lock this */
  276.     tid = THREAD->tid;
  277.  
  278.     /* copy down arguments to an array */
  279.     sc_args[0] = a1;
  280.     sc_args[1] = a2;
  281.     sc_args[2] = a3;
  282.     sc_args[3] = a4;
  283.     sc_args[4] = a5;
  284.     sc_args[5] = a6;
  285.  
  286.     ipl = interrupts_disable();
  287.     spinlock_lock(&THREAD->lock);
  288.  
  289.     if ((THREAD->tdebug.event_mask & TDEBUG_EVMASK_SYSCALL) == 0) {
  290.         /* syscall event not enabled */
  291.         spinlock_unlock(&THREAD->lock);
  292.         interrupts_restore(ipl);
  293.         return;
  294.     }
  295.  
  296.     /* record the debugging event into our thread structure */
  297.     THREAD->tdebug.syscall_args = sc_args;
  298.     THREAD->tdebug.stopped = 1;
  299.     THREAD->tdebug.current_event = TDEBUG_EV_SYSCALL;
  300.  
  301.     spinlock_unlock(&THREAD->lock);
  302.     interrupts_restore(ipl);
  303.  
  304.     /*
  305.      * Send notification to the monitoring task
  306.      * This may fail as we needn't have a monitor attached
  307.      */
  308.     if (_tdebug_notify_debugger(tid, TDEBUG_EV_SYSCALL, id, sc_rc) == 0) {
  309.         /* wait for resume */
  310.         _tdebug_wait_and_clear();
  311.     }
  312. }
  313.  
  314. /**
  315.  * Generate an exception debug event.
  316.  *
  317.  * Called from exc_dispatch() in interrupt.c. The current task
  318.  * may or may not have a monitor attached.
  319.  * If a monitor is not attached or exception events are not enabled,
  320.  * no action is taken.
  321.  */
  322. void tdebug_exception_event(int n)
  323. {
  324.     ipl_t ipl;
  325.     thread_id_t tid;
  326.  
  327.     klog_printf("TASK %llu: exception %d", TASK->taskid, n);
  328.     klog_printf("THREAD %llu", THREAD->tid);
  329.  
  330.     /* no need to lock this */
  331.     tid = THREAD->tid;
  332.  
  333.     ipl = interrupts_disable();
  334.     spinlock_lock(&THREAD->lock);
  335.  
  336.     if ((THREAD->tdebug.event_mask & TDEBUG_EVMASK_EXCEPTION) == 0) {
  337.         /* exception event not enabled */
  338.         spinlock_unlock(&THREAD->lock);
  339.         interrupts_restore(ipl);
  340.         return;
  341.     }
  342.  
  343.     /* record the debugging event into our thread structure */
  344.     THREAD->tdebug.stopped = 1;
  345.     THREAD->tdebug.current_event = TDEBUG_EV_EXCEPTION;
  346.  
  347.     spinlock_unlock(&THREAD->lock);
  348.     interrupts_restore(ipl);
  349.  
  350.     /*
  351.      * Send notification to the monitoring task
  352.      * This may fail as we needn't have a monitor attached
  353.      */
  354.     if (_tdebug_notify_debugger(tid, TDEBUG_EV_EXCEPTION, n, 0) == 0) {
  355.         /* wait for resume */
  356.         _tdebug_wait_and_clear();
  357.     }
  358. }
  359.  
  360.  
  361. /**
  362.  * Stop the thread here if a stop request is pending.
  363.  */
  364. void tdebug_stopping_point(void)
  365. {
  366.     ipl_t ipl;
  367.     thread_id_t tid;
  368.  
  369.     klog_printf("TASK %llu: stopping point", TASK->taskid);
  370.     klog_printf("THREAD %llu", THREAD->tid);
  371.  
  372.     /* no need to lock this */
  373.     tid = THREAD->tid;
  374.  
  375.     ipl = interrupts_disable();
  376.     spinlock_lock(&THREAD->lock);
  377.  
  378.     if (THREAD->tdebug.stop_request == 0) {
  379.         /* stop not requested */
  380.         spinlock_unlock(&THREAD->lock);
  381.         interrupts_restore(ipl);
  382.         return;    
  383.     }
  384.  
  385.     /* record the debugging event into our thread structure */
  386.     THREAD->tdebug.stopped = 1;
  387.     THREAD->tdebug.current_event = TDEBUG_EV_STOP;
  388.  
  389.     spinlock_unlock(&THREAD->lock);
  390.     interrupts_restore(ipl);   
  391.  
  392.     /* send notification to the monitoring task */
  393.     if (_tdebug_notify_debugger(tid, TDEBUG_EV_STOP, 0, 0) == 0) {
  394.         /* wait for resume */
  395.         _tdebug_wait_and_clear();
  396.     }
  397. }
  398.  
  399.  
  400. /**
  401.  * Send an IPC notification to a task.
  402.  *
  403.  * When calling the task's lock must be already held and interrupts
  404.  * must be disabled.
  405.  */
  406. static void _tdebug_send_msg(task_t *ta, unative_t method, unative_t a1, unative_t a2,
  407.     unative_t a3, unative_t a4, unative_t a5)
  408. {
  409.     call_t *call;
  410.     answerbox_t *answerbox;
  411.  
  412.     /* prepare an IPC notification structure */
  413.  
  414.     call = ipc_call_alloc(FRAME_ATOMIC);
  415.     if (!call) {
  416.         return;
  417.     }
  418.  
  419.     call->flags |= IPC_CALL_NOTIF;
  420.     IPC_SET_METHOD(call->data, method);
  421.     IPC_SET_ARG1(call->data, a1);
  422.     IPC_SET_ARG2(call->data, a2);
  423.     IPC_SET_ARG3(call->data, a3);
  424.     IPC_SET_ARG4(call->data, a4);
  425.     IPC_SET_ARG5(call->data, a5);
  426.  
  427.     answerbox = &ta->answerbox;
  428.  
  429.     /* analogy of send_call() from irq.c */
  430.     spinlock_lock(&answerbox->irq_lock);
  431.     list_append(&call->link, &answerbox->irq_notifs);
  432.     spinlock_unlock(&answerbox->irq_lock);
  433.  
  434.     waitq_wakeup(&answerbox->wq, WAKEUP_FIRST);
  435. }
  436.  
  437. /**
  438.  * Start debugging a task.
  439.  *
  440.  * The specified task (target) is attached to the current task (monitor).
  441.  * The monitoring task will be informed of debug events in the
  442.  * target task through IPC notifications with the specified method number.
  443.  */
  444. int tdebug_attach_task(task_id_t taskid, unative_t method)
  445. {
  446.     task_t *ta;
  447.     ipl_t ipl;
  448.     DEADLOCK_PROBE_INIT(p_target_lock);
  449.  
  450.     //FIXME: pokud bychom si podrzeli tasks_lock, nemusime pokazde
  451.     // znovu hledat ta podle id
  452. loop:
  453.     ipl = interrupts_disable();
  454.     spinlock_lock(&tasks_lock);
  455.  
  456.     spinlock_lock(&TASK->lock);
  457.  
  458.     ta = task_find_by_id(taskid);
  459.     if (!ta) {
  460.         spinlock_unlock(&tasks_lock);
  461.         spinlock_unlock(&TASK->lock);
  462.         interrupts_restore(ipl);
  463.         klog_printf("fail: no such task\n");
  464.         return ENOENT;
  465.     }
  466.  
  467.     if (!spinlock_trylock(&ta->lock)) {
  468.         /*
  469.          * Avoid deadlock by trying again.
  470.          */
  471.         spinlock_unlock(&TASK->lock);
  472.         spinlock_unlock(&tasks_lock);
  473.         interrupts_restore(ipl);
  474.         DEADLOCK_PROBE(p_target_lock, DEADLOCK_THRESHOLD);
  475.         goto loop;
  476.     }
  477.  
  478.     /* we don't need tasks_lock anymore */
  479.     spinlock_unlock(&tasks_lock);
  480.  
  481.     if (ta->tdebug.monitor != NULL) {
  482.         spinlock_unlock(&TASK->lock);
  483.         spinlock_unlock(&ta->lock);
  484.         interrupts_restore(ipl);
  485.         klog_printf("fail: already being debugged\n");
  486.         return EBUSY; /* task already being debugged */
  487.     }
  488.  
  489.     atomic_set(&ta->tdebug.have_monitor, 1);
  490.     ta->tdebug.monitor = TASK;
  491.     ta->tdebug.method = method;
  492.  
  493.     /* insert ta into this task's debug-target list */
  494.     list_append(&ta->tdebug.targets_link, &TASK->tdebug.targets);
  495.  
  496.     spinlock_unlock(&TASK->lock);
  497.     spinlock_unlock(&ta->lock);
  498.     interrupts_restore(ipl);
  499.  
  500.     return 0;
  501. }
  502.  
  503. /**
  504.  * Stop debugging a task.
  505.  */
  506. int tdebug_detach_task(task_id_t taskid)
  507. {
  508.     task_t *ta;
  509.     ipl_t ipl;
  510.     DEADLOCK_PROBE_INIT(p_target_lock);
  511.  
  512.     //FIXME: pokud bychom si podrzeli tasks_lock, nemusime pokazde
  513.     // znovu hledat ta podle id
  514. loop:
  515.     ipl = interrupts_disable();
  516.     spinlock_lock(&tasks_lock);
  517.  
  518.     spinlock_lock(&TASK->lock);
  519.  
  520.     ta = task_find_by_id(taskid);
  521.     if (!ta) {
  522.         spinlock_unlock(&tasks_lock);
  523.         spinlock_unlock(&TASK->lock);
  524.         interrupts_restore(ipl);
  525.         klog_printf("fail: no such task\n");
  526.         return ENOENT;
  527.     }
  528.  
  529.     if (!spinlock_trylock(&ta->lock)) {
  530.         /*
  531.          * Avoid deadlock by trying again.
  532.          */
  533.         spinlock_unlock(&TASK->lock);
  534.         spinlock_unlock(&tasks_lock);
  535.         interrupts_restore(ipl);
  536.         DEADLOCK_PROBE(p_target_lock, DEADLOCK_THRESHOLD);
  537.         goto loop;
  538.     }
  539.  
  540.     /* we don't need tasks_lock anymore */
  541.     spinlock_unlock(&tasks_lock);
  542.  
  543.     if (ta->tdebug.monitor == NULL) {
  544.         spinlock_unlock(&TASK->lock);
  545.         spinlock_unlock(&ta->lock);
  546.         interrupts_restore(ipl);
  547.         klog_printf("fail: not being debugged\n");
  548.         return EINVAL; /* task not being debugged */
  549.     }
  550.  
  551.     atomic_set(&ta->tdebug.have_monitor, 0);
  552.     ta->tdebug.monitor = NULL;
  553.     ta->tdebug.method = 0;
  554.  
  555.     /* remove target from this task's list */
  556.     list_remove(&ta->tdebug.targets_link);
  557.  
  558.     spinlock_unlock(&TASK->lock);
  559.     spinlock_unlock(&ta->lock);
  560.     interrupts_restore(ipl);
  561.  
  562.     return 0;
  563. }
  564.  
  565. /**
  566.  * Resume a thread stopped in a debugging event.
  567.  */
  568. int tdebug_continue_thread(thread_id_t tid)
  569. {
  570.     thread_t *t;
  571.     ipl_t ipl;
  572.    
  573.     klog_printf("sys_tdebug_continue_thread(%lld)", tid);
  574.  
  575.     //FIXME: need to verify that we are the monitor
  576.  
  577.     ipl = interrupts_disable();
  578.     spinlock_lock(&threads_lock);
  579.  
  580.     t = thread_find_by_id(tid);
  581.     if (t == NULL) {
  582.         spinlock_unlock(&threads_lock);
  583.         interrupts_restore(ipl);
  584.         klog_printf("fail: no such thread\n");
  585.         return ENOENT;
  586.     }
  587.  
  588.     /* lock the thread */
  589.     spinlock_lock(&t->lock);
  590.  
  591.     /* verify that the thread is stopped */
  592.     if (t->tdebug.stopped == 0) {
  593.         spinlock_unlock(&t->lock);
  594.         interrupts_restore(ipl);
  595.         return EINVAL;
  596.     }
  597.  
  598.     t->tdebug.stopped = 0;
  599.  
  600.     /* no thread should be unlocked when calling waitq_wakeup */
  601.     spinlock_unlock(&t->lock);
  602.  
  603.     /* "spincv_signal()" */
  604.     waitq_wakeup(&t->tdebug.stopped_cv.wq, WAKEUP_FIRST);
  605.  
  606.     spinlock_unlock(&threads_lock);
  607.     interrupts_restore(ipl);
  608.  
  609.     klog_printf("success\n");
  610.     return 0;
  611. }
  612.  
  613. /**
  614.  * Retrieve the arguments of a syscall.
  615.  *
  616.  * When a thread is stopped in a TDEBUG_EV_SYSCALL event,
  617.  * this function may be used to retrieve the arguments of the
  618.  * corresponding syscall.
  619.  */
  620. int tdebug_get_syscall_args(thread_id_t tid, unative_t *sc_args)
  621. {
  622.     thread_t *t;
  623.     ipl_t ipl;
  624.  
  625.     //FIXME: need to verify that we are the monitor
  626.  
  627.     ipl = interrupts_disable();
  628.     spinlock_lock(&threads_lock);
  629.  
  630.     t = thread_find_by_id(tid);
  631.     if (t == NULL) {
  632.         spinlock_unlock(&threads_lock);
  633.         interrupts_restore(ipl);
  634.         klog_printf("fail: no such thread\n");
  635.         return ENOENT;
  636.     }
  637.  
  638.     /* keep a lock on the thread */
  639.     spinlock_lock(&t->lock);
  640.     spinlock_unlock(&threads_lock);
  641.  
  642.     /* verify that the thread is stopped in a syscall event*/
  643.     if (t->tdebug.stopped == 0 ||
  644.         t->tdebug.current_event != TDEBUG_EV_SYSCALL) {
  645.         spinlock_unlock(&t->lock);
  646.         interrupts_restore(ipl);
  647.         return EINVAL;
  648.     }
  649.  
  650.     /* copy syscall arguments */
  651.     sc_args[0] = t->tdebug.syscall_args[0];
  652.     sc_args[1] = t->tdebug.syscall_args[1];
  653.     sc_args[2] = t->tdebug.syscall_args[2];
  654.     sc_args[3] = t->tdebug.syscall_args[3];
  655.     sc_args[4] = t->tdebug.syscall_args[4];
  656.     sc_args[5] = t->tdebug.syscall_args[5];
  657.  
  658.     spinlock_unlock(&t->lock);
  659.     interrupts_restore(ipl);
  660.  
  661.     return 0;
  662. }
  663.  
  664. /**
  665.  * Select which debug events will be generated.
  666.  */
  667. int tdebug_set_event_mask(thread_id_t tid, unative_t ev_mask)
  668. {
  669.     thread_t *t;
  670.     ipl_t ipl;
  671.     int rc;
  672.  
  673.     //FIXME: need to verify that we are the monitor
  674.  
  675.     ipl = interrupts_disable();
  676.     spinlock_lock(&threads_lock);
  677.  
  678.     t = thread_find_by_id(tid);
  679.     if (t == NULL) {
  680.         spinlock_unlock(&threads_lock);
  681.         interrupts_restore(ipl);
  682.         klog_printf("fail: no such thread\n");
  683.         return ENOENT;
  684.     }
  685.  
  686.     /* keep a lock on the thread */
  687.     spinlock_lock(&t->lock);
  688.     spinlock_unlock(&threads_lock);
  689.  
  690.     /* verify that the thread is stopped */
  691.     if (t->tdebug.stopped == 0) {
  692.         spinlock_unlock(&t->lock);
  693.         interrupts_restore(ipl);
  694.         klog_printf("fail: thread not stopped\n");
  695.         return EINVAL;
  696.     }
  697.  
  698.     t->tdebug.event_mask = ev_mask;
  699.    
  700.     /* arch-specific update for IAFTER setting */
  701.     //disable this as it would break compile for all archs except ia32
  702.     //rc = tdebug_iafter_update(t);
  703.     rc = 0;
  704.  
  705.     spinlock_unlock(&t->lock);
  706.     interrupts_restore(ipl);
  707.  
  708.     return rc;
  709. }
  710.  
  711. /**
  712.  * Ask a thread to stop (without waiting for it to happen).
  713.  */
  714. int tdebug_stop_thread(thread_id_t tid)
  715. {
  716.     thread_t *t;
  717.     ipl_t ipl;
  718.  
  719.     //FIXME: need to verify that we are the monitor
  720.  
  721.     ipl = interrupts_disable();
  722.     spinlock_lock(&threads_lock);
  723.  
  724.     t = thread_find_by_id(tid);
  725.     if (t == NULL) {
  726.         spinlock_unlock(&threads_lock);
  727.         interrupts_restore(ipl);
  728.         klog_printf("fail: no such thread\n");
  729.         return ENOENT;
  730.     }
  731.  
  732.     /* keep a lock on the thread */
  733.     spinlock_lock(&t->lock);
  734.     spinlock_unlock(&threads_lock);
  735.  
  736.     /* verify that the thread isn't stopped */
  737.     if (t->tdebug.stopped == 0) {
  738.         spinlock_unlock(&t->lock);
  739.         interrupts_restore(ipl);
  740.         return EINVAL;
  741.     }
  742.  
  743.     t->tdebug.stop_request = 1;
  744.  
  745.     spinlock_unlock(&t->lock);
  746.     interrupts_restore(ipl);
  747.  
  748.     return 0;
  749. }
  750.  
  751. /**
  752.  * Ask all threads in a task to stop (without waiting for it to happen).
  753.  */
  754. int tdebug_stop_task(task_id_t taskid)
  755. {
  756.     return 0;
  757. }
  758.