Subversion Repositories HelenOS

Rev

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