Subversion Repositories HelenOS

Rev

Rev 2866 | Rev 2885 | 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.     ta->debugger = call->sender;
  193.  
  194.     if (ta->not_stoppable_count == 0) {
  195.         ta->dt_state = UDEBUG_TS_ACTIVE;
  196.         ta->debug_begin_call = NULL;
  197.         rc = 1; /* actually we need backsend with 0 retval */
  198.     } else {
  199.         rc = 0; /* no backsend */
  200.     }
  201.    
  202.     /* Set debug_active on all of the task's userspace threads */
  203.  
  204.     for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
  205.         t = list_get_instance(cur, thread_t, th_link);
  206.  
  207.         spinlock_lock(&t->debug_lock);
  208.         if ((t->flags & THREAD_FLAG_USPACE) != 0)
  209.             t->debug_active = true;
  210.         spinlock_unlock(&t->debug_lock);
  211.     }
  212.  
  213.     spinlock_unlock(&ta->lock);
  214.     interrupts_restore(ipl);
  215.  
  216.     klog_printf("debug_begin() done (%s)",
  217.         rc ? "backsend" : "stoppability wait");
  218.  
  219.     return rc;
  220. }
  221.  
  222. static int udebug_rp_end(call_t *call, phone_t *phone)
  223. {
  224.     task_t *ta;
  225.     ipl_t ipl;
  226.     int rc;
  227.  
  228.     klog_printf("udebug_rp_end()");
  229.  
  230.     ipl = interrupts_disable();
  231.     ta = get_lock_callee_task(phone);
  232.  
  233.     rc = udebug_task_cleanup(ta);
  234.  
  235.     klog_printf("task %llu", ta->taskid);
  236.  
  237.     spinlock_unlock(&ta->lock);
  238.     interrupts_restore(ipl);
  239.  
  240.     if (rc < 0) {
  241.         return EINVAL;
  242.     }
  243.  
  244.     IPC_SET_RETVAL(call->data, 0);
  245.  
  246.     klog_printf("udebug_rp_end() done\n");
  247.  
  248.     return 1;
  249. }
  250.  
  251.  
  252. static int udebug_rp_go(call_t *call, phone_t *phone)
  253. {
  254.     thread_t *t;
  255.     ipl_t ipl;
  256.     int rc;
  257.  
  258.     klog_printf("debug_go()");
  259.  
  260.     t = (thread_t *)IPC_GET_ARG2(call->data);
  261.  
  262.     ipl = interrupts_disable();
  263.  
  264.     /* On success, this will lock t->debug_lock */
  265.     rc = _thread_op_begin(phone, t);
  266.     if (rc != EOK) {
  267.         interrupts_restore(ipl);
  268.         return rc;
  269.     }
  270.  
  271.     t->debug_go_call = call;
  272.     t->debug_stop = false;
  273.     t->cur_event = 0;   /* none */
  274.  
  275.     /*
  276.      * Neither t's lock nor threads_lock may be held during wakeup
  277.      */
  278.     waitq_wakeup(&t->go_wq, WAKEUP_FIRST);
  279.  
  280.     _thread_op_end(t);
  281.     interrupts_restore(ipl);
  282.  
  283.     return 0; /* no backsend */
  284. }
  285.  
  286. static int udebug_rp_args_read(call_t *call, phone_t *phone)
  287. {
  288.     thread_t *t;
  289.     void *uspace_buffer;
  290.     int rc;
  291.     ipl_t ipl;
  292.     unative_t buffer[6];
  293.  
  294.     klog_printf("debug_args_read()");
  295.  
  296.     t = (thread_t *)IPC_GET_ARG2(call->data);
  297.  
  298.     ipl = interrupts_disable();
  299.  
  300.     /* On success, this will lock t->debug_lock */
  301.     rc = _thread_op_begin(phone, t);
  302.     if (rc != EOK) {
  303.         interrupts_restore(ipl);
  304.         return rc;
  305.     }
  306.  
  307.     /* Additionally we need to verify that we are inside a syscall */
  308.     if (t->cur_event != UDEBUG_EVENT_SYSCALL) {
  309.         _thread_op_end(t);
  310.         interrupts_restore(ipl);
  311.         return EINVAL;
  312.     }
  313.  
  314.     /* Copy to a local buffer before releasing the lock */
  315.     memcpy(buffer, t->syscall_args, 6 * sizeof(unative_t));
  316.  
  317.     _thread_op_end(t);
  318.     interrupts_restore(ipl);
  319.  
  320.     /* Now copy to userspace */
  321.  
  322.     uspace_buffer = (void *)IPC_GET_ARG3(call->data);
  323.  
  324.     rc = copy_to_uspace(uspace_buffer, buffer, 6 * sizeof(unative_t));
  325.     if (rc != 0) {
  326.         klog_printf("debug_args_read() - copy failed");
  327.         return rc;
  328.     }
  329.  
  330.     klog_printf("debug_args_read() done");
  331.     return 1; /* actually need becksend with retval 0 */
  332. }
  333.  
  334. static int udebug_rp_regs_read(call_t *call, phone_t *phone)
  335. {
  336.     thread_t *t;
  337.     void *uspace_buffer;
  338.     unative_t to_copy;
  339.     int rc;
  340.     istate_t *state;
  341.     istate_t state_copy;
  342.     ipl_t ipl;
  343.  
  344.     klog_printf("debug_regs_read()");
  345.  
  346.     t = (thread_t *) IPC_GET_ARG2(call->data);
  347.  
  348.     ipl = interrupts_disable();
  349.  
  350.     /* On success, this will lock t->debug_lock */
  351.     rc = _thread_op_begin(phone, t);
  352.     if (rc != EOK) {
  353.         interrupts_restore(ipl);
  354.         return rc;
  355.     }
  356.  
  357.     state = t->uspace_state;
  358.     if (state == NULL) {
  359.         _thread_op_end(t);
  360.         interrupts_restore(ipl);
  361.         klog_printf("debug_regs_read() - istate not available");
  362.         return EBUSY;
  363.     }
  364.  
  365.     /* Copy to a local buffer so that we can release the lock */
  366.     memcpy(&state_copy, state, sizeof(state_copy));
  367.     _thread_op_end(t);
  368.     interrupts_restore(ipl);
  369.  
  370.     uspace_buffer = (void *)IPC_GET_ARG3(call->data);
  371.     to_copy = IPC_GET_ARG4(call->data);
  372.     if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t);
  373.  
  374.     rc = copy_to_uspace(uspace_buffer, &state_copy, to_copy);
  375.     if (rc != 0) {
  376.         klog_printf("debug_regs_read() - copy failed");
  377.         return rc;
  378.     }
  379.  
  380.     IPC_SET_ARG1(call->data, to_copy);
  381.     IPC_SET_ARG2(call->data, sizeof(istate_t));
  382.  
  383.     klog_printf("debug_regs_read() done");
  384.     return 1; /* actually need becksend with retval 0 */
  385. }
  386.  
  387.  
  388.  
  389. static int udebug_rp_regs_write(call_t *call, phone_t *phone)
  390. {
  391.     thread_t *t;
  392.     void *uspace_data;
  393.     unative_t to_copy;
  394.     int rc;
  395.     istate_t *state;
  396.     istate_t data_copy;
  397.     ipl_t ipl;
  398.  
  399.     klog_printf("debug_regs_write()");
  400.  
  401.     /* First copy to a local buffer */
  402.  
  403.     uspace_data = (void *)IPC_GET_ARG3(call->data);
  404.     to_copy = IPC_GET_ARG4(call->data);
  405.     if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t);
  406.  
  407.     rc = copy_from_uspace(&data_copy, uspace_data, to_copy);
  408.     if (rc != 0) {
  409.         klog_printf("debug_regs_write() - copy failed");
  410.         return rc;
  411.     }
  412.  
  413.     /* Now try to change the thread's uspace_state */
  414.  
  415.     ipl = interrupts_disable();
  416.     t = (thread_t *) IPC_GET_ARG2(call->data);
  417.  
  418.     /* On success, this will lock t->debug_lock */
  419.     rc = _thread_op_begin(phone, t);
  420.     if (rc != EOK) {
  421.         interrupts_restore(ipl);
  422.         return rc;
  423.     }
  424.  
  425.     state = t->uspace_state;
  426.     if (state == NULL) {
  427.         _thread_op_end(t);
  428.         interrupts_restore(ipl);
  429.         klog_printf("debug_regs_write() - istate not available");
  430.         return EBUSY;
  431.     }
  432.  
  433.     memcpy(t->uspace_state, &data_copy, sizeof(t->uspace_state));
  434.  
  435.     _thread_op_end(t);
  436.     interrupts_restore(ipl);
  437.  
  438.     /* Set answer values */
  439.  
  440.     IPC_SET_ARG1(call->data, to_copy);
  441.     IPC_SET_ARG2(call->data, sizeof(istate_t));
  442.  
  443.     klog_printf("debug_regs_write() done");
  444.     return 1; /* actually need becksend with retval 0 */
  445. }
  446.  
  447. static int udebug_rp_thread_read(call_t *call, phone_t *phone)
  448. {
  449.     thread_t *t;
  450.     link_t *cur;
  451.     task_t *ta;
  452.     unative_t *uspace_buffer;
  453.     unative_t to_copy;
  454.     int rc;
  455.     unsigned total_bytes;
  456.     unsigned buf_size;
  457.     unative_t tid;
  458.     unsigned num_threads, copied_ids;
  459.     ipl_t ipl;
  460.     unative_t *buffer;
  461.     int flags;
  462.  
  463.     klog_printf("debug_thread_read()");
  464.  
  465.     ipl = interrupts_disable();
  466.     ta = get_lock_callee_task(phone);
  467.  
  468.     /* Verify task state */
  469.     if (ta->dt_state != UDEBUG_TS_ACTIVE) {
  470.         spinlock_unlock(&ta->lock);
  471.         interrupts_restore(ipl);
  472.         return EBUSY;
  473.     }
  474.  
  475.     /* Count the threads first */
  476.  
  477.     num_threads = 0;
  478.     for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
  479.         /* Count all threads, to be on the safe side */
  480.         ++num_threads;
  481.     }
  482.  
  483.     /* Allocate a buffer and copy down the threads' ids */
  484.     buffer = malloc(num_threads * sizeof(unative_t), 0); // ???
  485.  
  486.     copied_ids = 0;
  487.     for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
  488.         t = list_get_instance(cur, thread_t, th_link);
  489.  
  490.         spinlock_lock(&t->lock);
  491.         flags = t->flags;
  492.         spinlock_unlock(&t->lock);
  493.  
  494.         /* Not interested in kernel threads */
  495.         if ((flags & THREAD_FLAG_USPACE) != 0) {
  496.             /* Using thread struct pointer for identification */
  497.             tid = (unative_t) t;
  498.             buffer[copied_ids++] = tid;
  499.         }
  500.     }
  501.  
  502.     spinlock_unlock(&ta->lock);
  503.     interrupts_restore(ipl);
  504.  
  505.     /* Now copy to userspace */
  506.  
  507.     uspace_buffer = (void *)IPC_GET_ARG2(call->data);
  508.     buf_size = IPC_GET_ARG3(call->data);
  509.  
  510.     total_bytes = copied_ids * sizeof(unative_t);
  511.  
  512.     if (buf_size > total_bytes)
  513.         to_copy = total_bytes;
  514.     else
  515.         to_copy = buf_size;
  516.  
  517.     rc = copy_to_uspace(uspace_buffer, buffer, to_copy);
  518.     free(buffer);
  519.  
  520.     if (rc != 0) {
  521.         klog_printf("debug_thread_read() - copy failed");
  522.         return rc;
  523.     }
  524.  
  525.     IPC_SET_ARG1(call->data, to_copy);
  526.     IPC_SET_ARG2(call->data, total_bytes);
  527.  
  528.     klog_printf("debug_thread_read() done");
  529.     return 1; /* actually need becksend with retval 0 */
  530. }
  531.  
  532. static int udebug_rp_mem_write(call_t *call, phone_t *phone)
  533. {
  534.     void *uspace_data;
  535.     unative_t to_copy;
  536.     int rc;
  537.     void *buffer;
  538.  
  539.     klog_printf("udebug_rp_mem_write()");
  540.  
  541.     uspace_data = (void *)IPC_GET_ARG2(call->data);
  542.     to_copy = IPC_GET_ARG4(call->data);
  543.  
  544.     buffer = malloc(to_copy, 0); // ???
  545.  
  546.     rc = copy_from_uspace(buffer, uspace_data, to_copy);
  547.     if (rc != 0) {
  548.         klog_printf(" - copy failed");
  549.         return rc;
  550.     }
  551.  
  552.     call->buffer = buffer;
  553.  
  554.     klog_printf(" - done");
  555.     return 1; /* actually need becksend with retval 0 */
  556. }
  557.  
  558.  
  559. int udebug_request_preprocess(call_t *call, phone_t *phone)
  560. {
  561.     int rc;
  562.  
  563.     switch (IPC_GET_ARG1(call->data)) {
  564.     case UDEBUG_M_BEGIN:
  565.         rc = udebug_rp_begin(call, phone);
  566.         return rc;
  567.     case UDEBUG_M_END:
  568.         rc = udebug_rp_end(call, phone);
  569.         return rc;
  570.     case UDEBUG_M_GO:
  571.         rc = udebug_rp_go(call, phone);
  572.         return rc;
  573.     case UDEBUG_M_ARGS_READ:
  574.         rc = udebug_rp_args_read(call, phone);
  575.         return rc;
  576.     case UDEBUG_M_REGS_READ:
  577.         rc = udebug_rp_regs_read(call, phone);
  578.         return rc;
  579.     case UDEBUG_M_REGS_WRITE:
  580.         rc = udebug_rp_regs_write(call, phone);
  581.         return rc;
  582.     case UDEBUG_M_THREAD_READ:
  583.         rc = udebug_rp_thread_read(call, phone);
  584.         return rc;
  585.     case UDEBUG_M_MEM_WRITE:
  586.         rc = udebug_rp_mem_write(call, phone);
  587.         return rc;
  588.     default:
  589.         break;
  590.     }
  591.  
  592.     return 0;
  593. }
  594.  
  595. static void udebug_receive_mem_read(call_t *call)
  596. {
  597.     unative_t uspace_dst;
  598.     void *uspace_ptr;
  599.     unsigned size;
  600.     void *buffer;
  601.     int rc;
  602.  
  603.     klog_printf("debug_mem_read()");
  604.     uspace_dst = IPC_GET_ARG2(call->data);
  605.     uspace_ptr = (void *)IPC_GET_ARG3(call->data);
  606.     size = IPC_GET_ARG4(call->data);
  607.  
  608.     buffer = malloc(size, 0); // ???
  609.     klog_printf("debug_mem_read: src=%u, size=%u", uspace_ptr, size);
  610.  
  611.     /* NOTE: this is not strictly from a syscall... but that shouldn't
  612.      * be a problem */
  613.     rc = copy_from_uspace(buffer, uspace_ptr, size);
  614.     if (rc) {
  615.         IPC_SET_RETVAL(call->data, rc);
  616.         return;
  617.     }
  618.  
  619.     klog_printf("first word: %u", *((unative_t *)buffer));
  620.  
  621.     IPC_SET_RETVAL(call->data, 0);
  622.     /* Hack: ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  623.        same code in process_answer() can be used
  624.        (no way to distinguish method in answer) */
  625.     IPC_SET_ARG1(call->data, uspace_dst);
  626.     IPC_SET_ARG2(call->data, size);
  627.     call->buffer = buffer;
  628.  
  629.     ipc_answer(&TASK->kernel_box, call);
  630. }
  631.  
  632. static void udebug_receive_mem_write(call_t *call)
  633. {
  634.     void *uspace_dst;
  635.     unsigned size;
  636.     void *buffer;
  637.     int rc;
  638.     udebug_task_state_t dts;
  639.  
  640.     klog_printf("udebug_receive_mem_write()");
  641.  
  642.     /* Verify task state */
  643.     spinlock_lock(&TASK->lock);
  644.     dts = TASK->dt_state;
  645.     spinlock_unlock(&TASK->lock);
  646.  
  647.     if (dts != UDEBUG_TS_ACTIVE) {
  648.         IPC_SET_RETVAL(call->data, EBUSY);
  649.         ipc_answer(&TASK->kernel_box, call);
  650.         return;
  651.     }
  652.    
  653.     uspace_dst = (void *)IPC_GET_ARG3(call->data);
  654.     size = IPC_GET_ARG4(call->data);
  655.  
  656.     buffer = call->buffer;
  657.     klog_printf("dst=%u, size=%u", uspace_dst, size);
  658.  
  659.     /* NOTE: this is not strictly from a syscall... but that shouldn't
  660.      * be a problem */
  661.     rc = copy_to_uspace(uspace_dst, buffer, size);
  662.     if (rc) {
  663.         IPC_SET_RETVAL(call->data, rc);
  664.         ipc_answer(&TASK->kernel_box, call);
  665.         return;
  666.     }
  667.  
  668.     IPC_SET_RETVAL(call->data, 0);
  669.  
  670.     free(call->buffer);
  671.     call->buffer = NULL;
  672.  
  673.     ipc_answer(&TASK->kernel_box, call);
  674. }
  675.  
  676.  
  677. /**
  678.  * Handle a debug call received on the kernel answerbox.
  679.  *
  680.  * This is called by the kbox servicing thread.
  681.  */
  682. void udebug_call_receive(call_t *call)
  683. {
  684.     int debug_method;
  685.  
  686.     debug_method = IPC_GET_ARG1(call->data);
  687.  
  688.     switch (debug_method) {
  689.     case UDEBUG_M_MEM_READ:
  690.         udebug_receive_mem_read(call);
  691.         break;
  692.     case UDEBUG_M_MEM_WRITE:
  693.         udebug_receive_mem_write(call);
  694.         break;
  695.     }
  696. }
  697.  
  698. /** @}
  699.  */
  700.