Subversion Repositories HelenOS

Rev

Rev 2851 | Rev 2870 | 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 <console/klog.h>
  11. #include <proc/task.h>
  12. #include <proc/thread.h>
  13. #include <arch.h>
  14. #include <errno.h>
  15. #include <ipc/ipc.h>
  16. #include <syscall/copy.h>
  17. #include <udebug/udebug.h>
  18. #include <udebug/udebug_ipc.h>
  19.  
  20. /**
  21.  * Get a phone's callee task id.
  22.  *
  23.  * This will return the id of the task to which the phone
  24.  * is connected.
  25.  *
  26.  * Interrupts must be already disabled.
  27.  */
  28. static task_id_t get_callee_task_id(phone_t *phone)
  29. {
  30.     answerbox_t *box;
  31.     task_id_t taskid;
  32.  
  33.     spinlock_lock(&phone->lock);
  34.     if (phone->state != IPC_PHONE_CONNECTED) {
  35.         spinlock_unlock(&phone->lock);
  36.         return NULL;
  37.     }
  38.  
  39.     box = phone->callee;
  40.    
  41.     spinlock_lock(&box->lock);
  42.     taskid = box->task->taskid;
  43.     spinlock_unlock(&box->lock);
  44.     spinlock_unlock(&phone->lock);
  45.  
  46.     return taskid;
  47. }
  48.  
  49. /**
  50.  * Get and lock a phone's callee task.
  51.  *
  52.  * This will return a pointer to the task to which the phone
  53.  * is connected. It will lock the task, making sure it exists.
  54.  *
  55.  * Interrupts must be already disabled.
  56.  */
  57. static task_t *get_lock_callee_task(phone_t *phone)
  58. {
  59.     task_t *ta;
  60.     task_id_t taskid;
  61.  
  62.     taskid = get_callee_task_id(phone);
  63.  
  64.     spinlock_lock(&tasks_lock);
  65.     ta = task_find_by_id(taskid);
  66.     if (ta == NULL) {
  67.         spinlock_unlock(&tasks_lock);
  68.         return NULL;
  69.     }
  70.  
  71.     spinlock_lock(&ta->lock);
  72.     spinlock_unlock(&tasks_lock);
  73.  
  74.     return ta;
  75. }
  76.  
  77. /**
  78.  * Prepare a thread for a debugging operation.
  79.  *
  80.  * Simply put, return thread t with t->debug_lock held,
  81.  * but only if it verifies all conditions.
  82.  *
  83.  * Specifically, verifies that thread t exists, is a userspace thread,
  84.  * belongs to the callee of 'phone'. It also locks t->debug_lock,
  85.  * making sure that t->debug_active is true - that the thread is
  86.  * in a valid debugging session.
  87.  *
  88.  * Returns EOK if all went well, or an error code otherwise.
  89.  * Interrupts must be already disabled when calling this function.
  90.  *
  91.  * Note: This function sports complicated locking.
  92.  */
  93. static int _thread_op_begin(phone_t *phone, thread_t *t)
  94. {
  95.     int rc;
  96.     task_id_t taskid;
  97.     int task_match;
  98.     DEADLOCK_PROBE_INIT(p_tasklock);
  99.  
  100.     taskid = get_callee_task_id(phone);
  101.  
  102.     /* Need to lock down the thread and than it's owner task */
  103. grab_locks:
  104.     spinlock_lock(&threads_lock);
  105.  
  106.     if (!thread_exists(t)) {
  107.         spinlock_unlock(&threads_lock);
  108.         return ENOENT;
  109.     }
  110.  
  111.     spinlock_lock(&t->debug_lock);
  112.     spinlock_lock(&t->lock);
  113.    
  114.     if (!spinlock_trylock(&t->task->lock)) {
  115.         spinlock_unlock(&t->lock);
  116.         spinlock_unlock(&t->debug_lock);
  117.         DEADLOCK_PROBE(p_tasklock, DEADLOCK_THRESHOLD);
  118.         goto grab_locks;    /* avoid deadlock */
  119.     }
  120.  
  121.     /* Now verify that it's the callee */
  122.     task_match = (t->task->taskid == taskid);
  123.  
  124.     spinlock_unlock(&t->task->lock);
  125.  
  126.     if (!task_match) {
  127.         /* No such thread belonging to callee */
  128.         rc = ENOENT;
  129.         goto error_exit;
  130.     }
  131.  
  132.     /* Verify that 't' is a userspace thread */
  133.     if ((t->flags & THREAD_FLAG_USPACE) == 0) {
  134.         /* It's not, deny its existence */
  135.         rc = ENOENT;
  136.         goto error_exit;
  137.     }
  138.  
  139.     if ((t->debug_active != true) || (t->debug_stop != true)) {
  140.         /* Not in debugging session or already has GO */
  141.         rc = ENOENT;
  142.         goto error_exit;
  143.     }
  144.  
  145.     spinlock_unlock(&threads_lock);
  146.     spinlock_unlock(&t->lock);
  147.  
  148.     /* Only t->debug_lock left */
  149.  
  150.     return EOK; /* All went well */
  151.  
  152.  
  153.     /* Executed when a check on the thread fails */
  154. error_exit:
  155.     spinlock_unlock(&t->lock);
  156.     spinlock_unlock(&t->debug_lock);
  157.     spinlock_unlock(&threads_lock);
  158.  
  159.     /* No locks left here */
  160.     return rc;  /* Some errors occured */
  161. }
  162.  
  163. static void _thread_op_end(thread_t *t)
  164. {
  165.     spinlock_unlock(&t->debug_lock);
  166. }
  167.  
  168. static int udebug_rp_begin(call_t *call, phone_t *phone)
  169. {
  170.     task_t *ta;
  171.     ipl_t ipl;
  172.     int rc;
  173.  
  174.     thread_t *t;
  175.     link_t *cur;
  176.  
  177.     klog_printf("debug_begin()");
  178.  
  179.     ipl = interrupts_disable();
  180.     ta = get_lock_callee_task(phone);
  181.     klog_printf("debugging task %llu", ta->taskid);
  182.  
  183.     if (ta->dt_state != UDEBUG_TS_INACTIVE) {
  184.         spinlock_unlock(&ta->lock);
  185.         interrupts_restore(ipl);
  186.         klog_printf("debug_begin(): busy error");
  187.         return EBUSY;
  188.     }
  189.  
  190.     ta->dt_state = UDEBUG_TS_BEGINNING;
  191.     ta->debug_begin_call = call;
  192.  
  193.     if (ta->not_stoppable_count == 0) {
  194.         ta->dt_state = UDEBUG_TS_ACTIVE;
  195.         ta->debug_begin_call = NULL;
  196.         rc = 1; /* actually we need backsend with 0 retval */
  197.     } else {
  198.         rc = 0; /* no backsend */
  199.     }
  200.    
  201.     /* Set debug_active on all of the task's userspace threads */
  202.  
  203.     for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
  204.         t = list_get_instance(cur, thread_t, th_link);
  205.  
  206.         spinlock_lock(&t->debug_lock);
  207.         if ((t->flags & THREAD_FLAG_USPACE) != 0)
  208.             t->debug_active = true;
  209.         spinlock_unlock(&t->debug_lock);
  210.     }
  211.  
  212.     spinlock_unlock(&ta->lock);
  213.     interrupts_restore(ipl);
  214.  
  215.     klog_printf("debug_begin() done (%s)",
  216.         rc ? "backsend" : "stoppability wait");
  217.  
  218.     return rc;
  219. }
  220.  
  221. static int udebug_rp_end(call_t *call, phone_t *phone)
  222. {
  223.     task_t *ta;
  224.     ipl_t ipl;
  225.  
  226.     thread_t *t;
  227.     link_t *cur;
  228.     int flags;
  229.  
  230.     klog_printf("udebug_rp_end()");
  231.  
  232.     ipl = interrupts_disable();
  233.     ta = get_lock_callee_task(phone);
  234.     klog_printf("task %llu", ta->taskid);
  235.  
  236.     if (ta->dt_state == UDEBUG_TS_BEGINNING &&
  237.         ta->dt_state != UDEBUG_TS_ACTIVE) {
  238.         spinlock_unlock(&ta->lock);
  239.         interrupts_restore(ipl);
  240.         klog_printf("udebug_rp_begin(): task not being debugged");
  241.         return EINVAL;
  242.     }
  243.  
  244.     /* Finish debugging of all userspace threads */
  245.     for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
  246.         t = list_get_instance(cur, thread_t, th_link);
  247.  
  248.         spinlock_lock(&t->debug_lock);
  249.         spinlock_lock(&t->lock);
  250.  
  251.         flags = t->flags;
  252.  
  253.         spinlock_unlock(&t->lock);
  254.  
  255.         /* Only process userspace threads */
  256.         if ((flags & THREAD_FLAG_USPACE) != 0) {
  257.             /* Prevent any further debug activity in thread */
  258.             t->debug_active = false;
  259.             t->cur_event = 0;   /* none */
  260.  
  261.             /* Still has go? */
  262.             if (t->debug_stop == false) {
  263.                 /*
  264.                 * Yes, so clear go. As debug_active == false,
  265.                  * this doesn't affect anything.
  266.                  */
  267.                 t->debug_stop = true;  
  268.  
  269.                 /* Answer GO call */
  270.                 klog_printf("answer GO call with EVENT_FINISHED");
  271.                 IPC_SET_RETVAL(t->debug_go_call->data, 0);
  272.                 IPC_SET_ARG1(t->debug_go_call->data, UDEBUG_EVENT_FINISHED);
  273.                 ipc_answer(&ta->answerbox, t->debug_go_call);
  274.             } else {
  275.                 /*
  276.                  * Debug_stop is already at initial value.
  277.                  * Yet this means the thread needs waking up.
  278.                  */
  279.  
  280.                 /*
  281.                  * t's lock must not be held when calling
  282.                  * waitq_wakeup.
  283.                  */
  284.                 waitq_wakeup(&t->go_wq, WAKEUP_FIRST);
  285.             }
  286.         }
  287.         spinlock_unlock(&t->debug_lock);
  288.     }
  289.  
  290.     ta->dt_state = UDEBUG_TS_INACTIVE;
  291.  
  292.     spinlock_unlock(&ta->lock);
  293.     interrupts_restore(ipl);
  294.  
  295.     IPC_SET_RETVAL(call->data, 0);
  296.  
  297.     klog_printf("udebug_rp_end() done\n");
  298.  
  299.     return 1;
  300. }
  301.  
  302.  
  303. static int udebug_rp_go(call_t *call, phone_t *phone)
  304. {
  305.     thread_t *t;
  306.     ipl_t ipl;
  307.     int rc;
  308.  
  309.     klog_printf("debug_go()");
  310.  
  311.     t = (thread_t *)IPC_GET_ARG2(call->data);
  312.  
  313.     ipl = interrupts_disable();
  314.  
  315.     /* On success, this will lock t->debug_lock */
  316.     rc = _thread_op_begin(phone, t);
  317.     if (rc != EOK) {
  318.         interrupts_restore(ipl);
  319.         return rc;
  320.     }
  321.  
  322.     t->debug_go_call = call;
  323.     t->debug_stop = false;
  324.     t->cur_event = 0;   /* none */
  325.  
  326.     /*
  327.      * Neither t's lock nor threads_lock may be held during wakeup
  328.      */
  329.     waitq_wakeup(&t->go_wq, WAKEUP_FIRST);
  330.  
  331.     _thread_op_end(t);
  332.     interrupts_restore(ipl);
  333.  
  334.     return 0; /* no backsend */
  335. }
  336.  
  337. static int udebug_rp_args_read(call_t *call, phone_t *phone)
  338. {
  339.     thread_t *t;
  340.     void *uspace_buffer;
  341.     int rc;
  342.     ipl_t ipl;
  343.     unative_t buffer[6];
  344.  
  345.     klog_printf("debug_args_read()");
  346.  
  347.     t = (thread_t *)IPC_GET_ARG2(call->data);
  348.  
  349.     ipl = interrupts_disable();
  350.  
  351.     /* On success, this will lock t->debug_lock */
  352.     rc = _thread_op_begin(phone, t);
  353.     if (rc != EOK) {
  354.         interrupts_restore(ipl);
  355.         return rc;
  356.     }
  357.  
  358.     /* Additionally we need to verify that we are inside a syscall */
  359.     if (t->cur_event != UDEBUG_EVENT_SYSCALL) {
  360.         _thread_op_end(t);
  361.         interrupts_restore(ipl);
  362.         return EINVAL;
  363.     }
  364.  
  365.     /* Copy to a local buffer before releasing the lock */
  366.     memcpy(buffer, t->syscall_args, 6 * sizeof(unative_t));
  367.  
  368.     _thread_op_end(t);
  369.     interrupts_restore(ipl);
  370.  
  371.     /* Now copy to userspace */
  372.  
  373.     uspace_buffer = (void *)IPC_GET_ARG3(call->data);
  374.  
  375.     rc = copy_to_uspace(uspace_buffer, buffer, 6 * sizeof(unative_t));
  376.     if (rc != 0) {
  377.         klog_printf("debug_args_read() - copy failed");
  378.         return rc;
  379.     }
  380.  
  381.     klog_printf("debug_args_read() done");
  382.     return 1; /* actually need becksend with retval 0 */
  383. }
  384.  
  385. static int udebug_rp_regs_read(call_t *call, phone_t *phone)
  386. {
  387.     thread_t *t;
  388.     void *uspace_buffer;
  389.     unative_t to_copy;
  390.     int rc;
  391.     istate_t *state;
  392.     istate_t state_copy;
  393.     ipl_t ipl;
  394.  
  395.     klog_printf("debug_regs_read()");
  396.  
  397.     t = (thread_t *) IPC_GET_ARG2(call->data);
  398.  
  399.     ipl = interrupts_disable();
  400.  
  401.     /* On success, this will lock t->debug_lock */
  402.     rc = _thread_op_begin(phone, t);
  403.     if (rc != EOK) {
  404.         interrupts_restore(ipl);
  405.         return rc;
  406.     }
  407.  
  408.     state = t->uspace_state;
  409.     if (state == NULL) {
  410.         _thread_op_end(t);
  411.         interrupts_restore(ipl);
  412.         klog_printf("debug_regs_read() - istate not available");
  413.         return EBUSY;
  414.     }
  415.  
  416.     /* Copy to a local buffer so that we can release the lock */
  417.     memcpy(&state_copy, state, sizeof(state_copy));
  418.     _thread_op_end(t);
  419.     interrupts_restore(ipl);
  420.  
  421.     uspace_buffer = (void *)IPC_GET_ARG3(call->data);
  422.     to_copy = IPC_GET_ARG4(call->data);
  423.     if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t);
  424.  
  425.     rc = copy_to_uspace(uspace_buffer, &state_copy, to_copy);
  426.     if (rc != 0) {
  427.         klog_printf("debug_regs_read() - copy failed");
  428.         return rc;
  429.     }
  430.  
  431.     IPC_SET_ARG1(call->data, to_copy);
  432.     IPC_SET_ARG2(call->data, sizeof(istate_t));
  433.  
  434.     klog_printf("debug_regs_read() done");
  435.     return 1; /* actually need becksend with retval 0 */
  436. }
  437.  
  438.  
  439.  
  440. static int udebug_rp_regs_write(call_t *call, phone_t *phone)
  441. {
  442.     thread_t *t;
  443.     void *uspace_data;
  444.     unative_t to_copy;
  445.     int rc;
  446.     istate_t *state;
  447.     istate_t data_copy;
  448.     ipl_t ipl;
  449.  
  450.     klog_printf("debug_regs_write()");
  451.  
  452.     /* First copy to a local buffer */
  453.  
  454.     uspace_data = (void *)IPC_GET_ARG3(call->data);
  455.     to_copy = IPC_GET_ARG4(call->data);
  456.     if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t);
  457.  
  458.     rc = copy_from_uspace(&data_copy, uspace_data, to_copy);
  459.     if (rc != 0) {
  460.         klog_printf("debug_regs_write() - copy failed");
  461.         return rc;
  462.     }
  463.  
  464.     /* Now try to change the thread's uspace_state */
  465.  
  466.     ipl = interrupts_disable();
  467.     t = (thread_t *) IPC_GET_ARG2(call->data);
  468.  
  469.     /* On success, this will lock t->debug_lock */
  470.     rc = _thread_op_begin(phone, t);
  471.     if (rc != EOK) {
  472.         interrupts_restore(ipl);
  473.         return rc;
  474.     }
  475.  
  476.     state = t->uspace_state;
  477.     if (state == NULL) {
  478.         _thread_op_end(t);
  479.         interrupts_restore(ipl);
  480.         klog_printf("debug_regs_write() - istate not available");
  481.         return EBUSY;
  482.     }
  483.  
  484.     memcpy(t->uspace_state, &data_copy, sizeof(t->uspace_state));
  485.  
  486.     _thread_op_end(t);
  487.     interrupts_restore(ipl);
  488.  
  489.     /* Set answer values */
  490.  
  491.     IPC_SET_ARG1(call->data, to_copy);
  492.     IPC_SET_ARG2(call->data, sizeof(istate_t));
  493.  
  494.     klog_printf("debug_regs_write() done");
  495.     return 1; /* actually need becksend with retval 0 */
  496. }
  497.  
  498. static int udebug_rp_thread_read(call_t *call, phone_t *phone)
  499. {
  500.     thread_t *t;
  501.     link_t *cur;
  502.     task_t *ta;
  503.     unative_t *uspace_buffer;
  504.     unative_t to_copy;
  505.     int rc;
  506.     unsigned total_bytes;
  507.     unsigned buf_size;
  508.     unative_t tid;
  509.     unsigned num_threads, copied_ids;
  510.     ipl_t ipl;
  511.     unative_t *buffer;
  512.     int flags;
  513.  
  514.     klog_printf("debug_thread_read()");
  515.  
  516.     ipl = interrupts_disable();
  517.     ta = get_lock_callee_task(phone);
  518.  
  519.     /* Verify task state */
  520.     if (ta->dt_state != UDEBUG_TS_ACTIVE) {
  521.         spinlock_unlock(&ta->lock);
  522.         interrupts_restore(ipl);
  523.         return EBUSY;
  524.     }
  525.  
  526.     /* Count the threads first */
  527.  
  528.     num_threads = 0;
  529.     for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
  530.         /* Count all threads, to be on the safe side */
  531.         ++num_threads;
  532.     }
  533.  
  534.     /* Allocate a buffer and copy down the threads' ids */
  535.     buffer = malloc(num_threads * sizeof(unative_t), 0); // ???
  536.  
  537.     copied_ids = 0;
  538.     for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
  539.         t = list_get_instance(cur, thread_t, th_link);
  540.  
  541.         spinlock_lock(&t->lock);
  542.         flags = t->flags;
  543.         spinlock_unlock(&t->lock);
  544.  
  545.         /* Not interested in kernel threads */
  546.         if ((flags & THREAD_FLAG_USPACE) != 0) {
  547.             /* Using thread struct pointer for identification */
  548.             tid = (unative_t) t;
  549.             buffer[copied_ids++] = tid;
  550.         }
  551.     }
  552.  
  553.     spinlock_unlock(&ta->lock);
  554.     interrupts_restore(ipl);
  555.  
  556.     /* Now copy to userspace */
  557.  
  558.     uspace_buffer = (void *)IPC_GET_ARG2(call->data);
  559.     buf_size = IPC_GET_ARG3(call->data);
  560.  
  561.     total_bytes = copied_ids * sizeof(unative_t);
  562.  
  563.     if (buf_size > total_bytes)
  564.         to_copy = total_bytes;
  565.     else
  566.         to_copy = buf_size;
  567.  
  568.     rc = copy_to_uspace(uspace_buffer, buffer, to_copy);
  569.     free(buffer);
  570.  
  571.     if (rc != 0) {
  572.         klog_printf("debug_thread_read() - copy failed");
  573.         return rc;
  574.     }
  575.  
  576.     IPC_SET_ARG1(call->data, to_copy);
  577.     IPC_SET_ARG2(call->data, total_bytes);
  578.  
  579.     klog_printf("debug_thread_read() done");
  580.     return 1; /* actually need becksend with retval 0 */
  581. }
  582.  
  583. static int udebug_rp_mem_write(call_t *call, phone_t *phone)
  584. {
  585.     void *uspace_data;
  586.     unative_t to_copy;
  587.     int rc;
  588.     void *buffer;
  589.  
  590.     klog_printf("udebug_rp_mem_write()");
  591.  
  592.     uspace_data = (void *)IPC_GET_ARG2(call->data);
  593.     to_copy = IPC_GET_ARG4(call->data);
  594.  
  595.     buffer = malloc(to_copy, 0); // ???
  596.  
  597.     rc = copy_from_uspace(buffer, uspace_data, to_copy);
  598.     if (rc != 0) {
  599.         klog_printf(" - copy failed");
  600.         return rc;
  601.     }
  602.  
  603.     call->buffer = buffer;
  604.  
  605.     klog_printf(" - done");
  606.     return 1; /* actually need becksend with retval 0 */
  607. }
  608.  
  609.  
  610. int udebug_request_preprocess(call_t *call, phone_t *phone)
  611. {
  612.     int rc;
  613.  
  614.     switch (IPC_GET_ARG1(call->data)) {
  615.     case UDEBUG_M_BEGIN:
  616.         rc = udebug_rp_begin(call, phone);
  617.         return rc;
  618.     case UDEBUG_M_END:
  619.         rc = udebug_rp_end(call, phone);
  620.         return rc;
  621.     case UDEBUG_M_GO:
  622.         rc = udebug_rp_go(call, phone);
  623.         return rc;
  624.     case UDEBUG_M_ARGS_READ:
  625.         rc = udebug_rp_args_read(call, phone);
  626.         return rc;
  627.     case UDEBUG_M_REGS_READ:
  628.         rc = udebug_rp_regs_read(call, phone);
  629.         return rc;
  630.     case UDEBUG_M_REGS_WRITE:
  631.         rc = udebug_rp_regs_write(call, phone);
  632.         return rc;
  633.     case UDEBUG_M_THREAD_READ:
  634.         rc = udebug_rp_thread_read(call, phone);
  635.         return rc;
  636.     case UDEBUG_M_MEM_WRITE:
  637.         rc = udebug_rp_mem_write(call, phone);
  638.         return rc;
  639.     default:
  640.         break;
  641.     }
  642.  
  643.     return 0;
  644. }
  645.  
  646. static void udebug_receive_mem_read(call_t *call)
  647. {
  648.     unative_t uspace_dst;
  649.     void *uspace_ptr;
  650.     unsigned size;
  651.     void *buffer;
  652.     int rc;
  653.  
  654.     klog_printf("debug_mem_read()");
  655.     uspace_dst = IPC_GET_ARG2(call->data);
  656.     uspace_ptr = (void *)IPC_GET_ARG3(call->data);
  657.     size = IPC_GET_ARG4(call->data);
  658.  
  659.     buffer = malloc(size, 0); // ???
  660.     klog_printf("debug_mem_read: src=%u, size=%u", uspace_ptr, size);
  661.  
  662.     /* NOTE: this is not strictly from a syscall... but that shouldn't
  663.      * be a problem */
  664.     rc = copy_from_uspace(buffer, uspace_ptr, size);
  665.     if (rc) {
  666.         IPC_SET_RETVAL(call->data, rc);
  667.         return;
  668.     }
  669.  
  670.     klog_printf("first word: %u", *((unative_t *)buffer));
  671.  
  672.     IPC_SET_RETVAL(call->data, 0);
  673.     /* Hack: ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  674.        same code in process_answer() can be used
  675.        (no way to distinguish method in answer) */
  676.     IPC_SET_ARG1(call->data, uspace_dst);
  677.     IPC_SET_ARG2(call->data, size);
  678.     call->buffer = buffer;
  679.  
  680.     ipc_answer(&TASK->kernel_box, call);
  681. }
  682.  
  683. static void udebug_receive_mem_write(call_t *call)
  684. {
  685.     void *uspace_dst;
  686.     unsigned size;
  687.     void *buffer;
  688.     int rc;
  689.     udebug_task_state_t dts;
  690.  
  691.     klog_printf("udebug_receive_mem_write()");
  692.  
  693.     /* Verify task state */
  694.     spinlock_lock(&TASK->lock);
  695.     dts = TASK->dt_state;
  696.     spinlock_unlock(&TASK->lock);
  697.  
  698.     if (dts != UDEBUG_TS_ACTIVE) {
  699.         IPC_SET_RETVAL(call->data, EBUSY);
  700.         ipc_answer(&TASK->kernel_box, call);
  701.         return;
  702.     }
  703.    
  704.     uspace_dst = (void *)IPC_GET_ARG3(call->data);
  705.     size = IPC_GET_ARG4(call->data);
  706.  
  707.     buffer = call->buffer;
  708.     klog_printf("dst=%u, size=%u", uspace_dst, size);
  709.  
  710.     /* NOTE: this is not strictly from a syscall... but that shouldn't
  711.      * be a problem */
  712.     rc = copy_to_uspace(uspace_dst, buffer, size);
  713.     if (rc) {
  714.         IPC_SET_RETVAL(call->data, rc);
  715.         ipc_answer(&TASK->kernel_box, call);
  716.         return;
  717.     }
  718.  
  719.     IPC_SET_RETVAL(call->data, 0);
  720.  
  721.     free(call->buffer);
  722.     call->buffer = NULL;
  723.  
  724.     ipc_answer(&TASK->kernel_box, call);
  725. }
  726.  
  727.  
  728. /**
  729.  * Handle a debug call received on the kernel answerbox.
  730.  *
  731.  * This is called by the kbox servicing thread.
  732.  */
  733. void udebug_call_receive(call_t *call)
  734. {
  735.     int debug_method;
  736.  
  737.     debug_method = IPC_GET_ARG1(call->data);
  738.  
  739.     switch (debug_method) {
  740.     case UDEBUG_M_MEM_READ:
  741.         udebug_receive_mem_read(call);
  742.         break;
  743.     case UDEBUG_M_MEM_WRITE:
  744.         udebug_receive_mem_write(call);
  745.         break;
  746.     }
  747. }
  748.  
  749. /** @}
  750.  */
  751.