Subversion Repositories HelenOS

Rev

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