Subversion Repositories HelenOS

Rev

Rev 2823 | Rev 2825 | 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 and lock a phone's callee task.
  22.  *
  23.  * This will return a pointer to the task to which the phone
  24.  * is connected. It will lock the task, making sure it exists.
  25.  * (TODO: make sure the udebug-cleanup of the task hasn't
  26.  * started yet)
  27.  */
  28. static task_t *get_lock_callee_task(phone_t *phone)
  29. {
  30.     answerbox_t *box;
  31.     task_t *ta;
  32.     task_id_t taskid;
  33.     ipl_t ipl;
  34.  
  35.     ipl = interrupts_disable();
  36.     spinlock_lock(&phone->lock);
  37.     if (phone->state != IPC_PHONE_CONNECTED) {
  38.         spinlock_unlock(&phone->lock);
  39.         interrupts_restore(ipl);
  40.         return NULL;
  41.     }
  42.  
  43.     box = phone->callee;
  44.    
  45.     spinlock_lock(&box->lock);
  46.     ta = box->task;
  47.     taskid = ta->taskid;
  48.     spinlock_unlock(&box->lock);
  49.     spinlock_unlock(&phone->lock);
  50.  
  51.     /* Locking decoupled using taskid */
  52.    
  53.     spinlock_lock(&tasks_lock);
  54.     ta = task_find_by_id(taskid);
  55.     if (ta == NULL) {
  56.         spinlock_unlock(&tasks_lock);
  57.         interrupts_restore(ipl);
  58.         return NULL;
  59.     }
  60.  
  61.     spinlock_lock(&ta->lock);
  62.     spinlock_unlock(&tasks_lock);
  63.     interrupts_restore(ipl);
  64.  
  65.     return ta;
  66. }
  67.  
  68. static int udebug_rp_begin(call_t *call, phone_t *phone)
  69. {
  70.     task_t *ta;
  71.     ipl_t ipl;
  72.  
  73.     klog_printf("debug_begin()");
  74.  
  75.     ipl = interrupts_disable();
  76.     ta = get_lock_callee_task(phone);
  77.     klog_printf("debugging task %llu", ta->taskid);
  78.  
  79.     if (ta->being_debugged != false) {
  80.         spinlock_unlock(&ta->lock);
  81.         interrupts_restore(ipl);
  82.         klog_printf("debug_begin(): busy error");
  83.         return EBUSY;
  84.     }
  85.  
  86.     ta->being_debugged = true;
  87.     ta->stop_request = true;
  88.     ta->debug_begin_call = call;
  89.  
  90.     if (ta->not_stoppable_count == 0) {
  91.         ta->debug_begin_call = NULL;
  92.         ta->stop_request = false;
  93.         spinlock_unlock(&ta->lock);
  94.         interrupts_restore(ipl);
  95.         klog_printf("debug_begin(): immediate backsend");
  96.         return 1; /* actually we need backsend with 0 retval */
  97.     }
  98.  
  99.     spinlock_unlock(&ta->lock);
  100.     interrupts_restore(ipl);
  101.  
  102.     klog_printf("debug_begin() done (wait for stoppability)");
  103.     return 0;
  104. }
  105.  
  106. static int udebug_rp_go(call_t *call, phone_t *phone)
  107. {
  108.     thread_t *t;
  109.     task_t *ta;
  110.     ipl_t ipl;
  111.  
  112.     klog_printf("debug_go()");
  113.     ta = get_lock_callee_task(phone);
  114.  
  115.     // FIXME: must save this in thread struct, not task struct!!!
  116.     ta->debug_go_call = call;
  117.     spinlock_unlock(&ta->lock);
  118.  
  119.     t = (thread_t *) IPC_GET_ARG2(call->data);
  120.  
  121.     ipl = interrupts_disable();
  122.     spinlock_lock(&threads_lock);
  123.     if (!thread_exists(t)) {
  124.         spinlock_unlock(&threads_lock);
  125.         interrupts_restore(ipl);
  126.         return ENOENT;
  127.     }
  128.  
  129.     waitq_wakeup(&t->go_wq, WAKEUP_FIRST);
  130.     spinlock_unlock(&threads_lock);
  131.     interrupts_restore(ipl);
  132.  
  133.     return 0; /* no backsend */
  134. }
  135.  
  136. static int udebug_rp_args_read(call_t *call, phone_t *phone)
  137. {
  138.     thread_t *t;
  139.     task_t *ta;
  140.     void *uspace_buffer;
  141.     unative_t to_copy;
  142.     int rc;
  143.     ipl_t ipl;
  144.  
  145.     klog_printf("debug_args_read()");
  146.     // FIXME: verify task/thread state
  147.  
  148.     ta = get_lock_callee_task(phone);
  149.     klog_printf("task %llu", ta->taskid);
  150.     spinlock_unlock(&ta->lock);
  151.  
  152.     t = (thread_t *) IPC_GET_ARG2(call->data);
  153.  
  154.     ipl = interrupts_disable();
  155.     spinlock_lock(&threads_lock);
  156.  
  157.     if (!thread_exists(t)) {
  158.         spinlock_unlock(&threads_lock);
  159.         interrupts_restore(ipl);
  160.         return ENOENT;
  161.     }
  162.  
  163.     // FIXME: copy to a local buffer before releasing the lock
  164.     spinlock_unlock(&threads_lock);
  165.     interrupts_restore(ipl);
  166.  
  167.     uspace_buffer = (void *)IPC_GET_ARG3(call->data);
  168.     to_copy = IPC_GET_ARG4(call->data);
  169.     if (to_copy > 6 * sizeof(unative_t)) to_copy = 6 * sizeof(unative_t);
  170.  
  171.     rc = copy_to_uspace(uspace_buffer, t->syscall_args, to_copy);
  172.     if (rc != 0) {
  173.         spinlock_unlock(&ta->lock);
  174.         klog_printf("debug_args_read() - copy failed");
  175.         return rc;
  176.     }
  177.  
  178.     IPC_SET_ARG1(call->data, to_copy);
  179.  
  180.     klog_printf("debug_args_read() done");
  181.     return 1; /* actually need becksend with retval 0 */
  182. }
  183.  
  184. static int udebug_rp_regs_read(call_t *call, phone_t *phone)
  185. {
  186.     thread_t *t;
  187.     task_t *ta;
  188.     void *uspace_buffer;
  189.     unative_t to_copy;
  190.     int rc;
  191.     istate_t *state;
  192.     istate_t state_copy;
  193.     ipl_t ipl;
  194.  
  195.     klog_printf("debug_regs_read()");
  196.     // FIXME: verify task/thread state
  197.  
  198.     ta = get_lock_callee_task(phone);
  199.     spinlock_unlock(&ta->lock);
  200.  
  201.     ipl = interrupts_disable();
  202.     spinlock_lock(&threads_lock);
  203.  
  204.     t = (thread_t *) IPC_GET_ARG2(call->data);
  205.     if (!thread_exists(t)) {
  206.         return ENOENT;
  207.     }
  208.  
  209.     state = t->uspace_state;
  210.     if (state == NULL) {
  211.         spinlock_unlock(&threads_lock);
  212.         interrupts_restore(ipl);
  213.         klog_printf("debug_regs_read() - istate not available");
  214.         return EBUSY;
  215.     }
  216.  
  217.     /* Copy to a local buffer so that we can release the lock */
  218.     memcpy(&state_copy, state, sizeof(state_copy));
  219.     spinlock_unlock(&threads_lock);
  220.     interrupts_restore(ipl);
  221.  
  222.     uspace_buffer = (void *)IPC_GET_ARG3(call->data);
  223.     to_copy = IPC_GET_ARG4(call->data);
  224.     if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t);
  225.  
  226.     rc = copy_to_uspace(uspace_buffer, &state_copy, to_copy);
  227.     if (rc != 0) {
  228.         spinlock_unlock(&ta->lock);
  229.         klog_printf("debug_regs_read() - copy failed");
  230.         return rc;
  231.     }
  232.  
  233.     IPC_SET_ARG1(call->data, to_copy);
  234.     IPC_SET_ARG2(call->data, sizeof(istate_t));
  235.  
  236.     klog_printf("debug_regs_read() done");
  237.     return 1; /* actually need becksend with retval 0 */
  238. }
  239.  
  240. static int udebug_rp_regs_write(call_t *call, phone_t *phone)
  241. {
  242.     thread_t *t;
  243.     task_t *ta;
  244.     void *uspace_data;
  245.     unative_t to_copy;
  246.     int rc;
  247.     istate_t *state;
  248.     istate_t data_copy;
  249.     ipl_t ipl;
  250.  
  251.     klog_printf("debug_regs_write()");
  252.  
  253.     /* First copy to a local buffer */
  254.  
  255.     uspace_data = (void *)IPC_GET_ARG3(call->data);
  256.     to_copy = IPC_GET_ARG4(call->data);
  257.     if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t);
  258.  
  259.     rc = copy_from_uspace(&data_copy, uspace_data, to_copy);
  260.     if (rc != 0) {
  261.         klog_printf("debug_regs_write() - copy failed");
  262.         return rc;
  263.     }
  264.  
  265.     // FIXME: verify task/thread state
  266.  
  267.     ta = get_lock_callee_task(phone);
  268.     spinlock_unlock(&ta->lock);
  269.  
  270.     /* Now try to change the thread's uspace_state */
  271.  
  272.     ipl = interrupts_disable();
  273.     spinlock_lock(&threads_lock);
  274.  
  275.     t = (thread_t *) IPC_GET_ARG2(call->data);
  276.     if (!thread_exists(t)) {
  277.         spinlock_unlock(&threads_lock);
  278.         interrupts_restore(ipl);
  279.         return ENOENT;
  280.     }
  281.  
  282.     state = t->uspace_state;
  283.     if (state == NULL) {
  284.         spinlock_unlock(&threads_lock);
  285.         interrupts_restore(ipl);
  286.         klog_printf("debug_regs_write() - istate not available");
  287.         return EBUSY;
  288.     }
  289.  
  290.     memcpy(t->uspace_state, &data_copy, sizeof(t->uspace_state));
  291.  
  292.     spinlock_unlock(&threads_lock);
  293.     interrupts_restore(ipl);
  294.  
  295.     /* Set answer values */
  296.  
  297.     IPC_SET_ARG1(call->data, to_copy);
  298.     IPC_SET_ARG2(call->data, sizeof(istate_t));
  299.  
  300.     klog_printf("debug_regs_write() done");
  301.     return 1; /* actually need becksend with retval 0 */
  302. }
  303.  
  304. static int udebug_rp_thread_read(call_t *call, phone_t *phone)
  305. {
  306.     thread_t *t;
  307.     link_t *cur;
  308.     task_t *ta;
  309.     unative_t *uspace_buffer;
  310.     unative_t to_copy;
  311.     int rc;
  312.     unsigned total_bytes;
  313.     unsigned buf_size;
  314.     unative_t tid;
  315.     unsigned num_threads, copied_ids;
  316.     ipl_t ipl;
  317.     unative_t *buffer;
  318.     int flags;
  319.  
  320.     klog_printf("debug_thread_read()");
  321.     // FIXME: verify task/thread state
  322.  
  323.     ipl = interrupts_disable();
  324.     ta = get_lock_callee_task(phone);
  325.  
  326.     /* Count the threads first */
  327.  
  328.     num_threads = 0;
  329.     for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
  330.         /* Count all threads, to be on the safe side */
  331.         ++num_threads;
  332.     }
  333.  
  334.     /* Allocate a buffer and copy down the threads' ids */
  335.     buffer = malloc(num_threads * sizeof(unative_t), 0); // ???
  336.  
  337.     copied_ids = 0;
  338.     for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
  339.         t = list_get_instance(cur, thread_t, th_link);
  340.  
  341.         spinlock_lock(&t->lock);
  342.         flags = t->flags;
  343.         spinlock_unlock(&t->lock);
  344.  
  345.         /* Not interested in kernel threads */
  346.         if ((flags & THREAD_FLAG_USPACE) != 0) {
  347.             /* Using thread struct pointer for identification */
  348.             tid = (unative_t) t;
  349.             buffer[copied_ids++] = tid;
  350.         }
  351.     }
  352.  
  353.     spinlock_unlock(&ta->lock);
  354.     interrupts_restore(ipl);
  355.  
  356.     /* Now copy to userspace */
  357.  
  358.     uspace_buffer = (void *)IPC_GET_ARG2(call->data);
  359.     buf_size = IPC_GET_ARG3(call->data);
  360.  
  361.     total_bytes = copied_ids * sizeof(unative_t);
  362.  
  363.     if (buf_size > total_bytes)
  364.         to_copy = total_bytes;
  365.     else
  366.         to_copy = buf_size;
  367.  
  368.     rc = copy_to_uspace(uspace_buffer, buffer, to_copy);
  369.     free(buffer);
  370.  
  371.     if (rc != 0) {
  372.         klog_printf("debug_thread_read() - copy failed");
  373.         return rc;
  374.     }
  375.  
  376.     IPC_SET_ARG1(call->data, to_copy);
  377.     IPC_SET_ARG2(call->data, total_bytes);
  378.  
  379.     klog_printf("debug_thread_read() done");
  380.     return 1; /* actually need becksend with retval 0 */
  381. }
  382.  
  383. static int udebug_rp_mem_write(call_t *call, phone_t *phone)
  384. {
  385.     void *uspace_data;
  386.     unative_t to_copy;
  387.     int rc;
  388.     void *buffer;
  389.  
  390.     klog_printf("udebug_rp_mem_write()");
  391.     // FIXME: verify task/thread state
  392.  
  393.     uspace_data = (void *)IPC_GET_ARG2(call->data);
  394.     to_copy = IPC_GET_ARG4(call->data);
  395.  
  396.     buffer = malloc(to_copy, 0); // ???
  397.  
  398.     rc = copy_from_uspace(buffer, uspace_data, to_copy);
  399.     if (rc != 0) {
  400.         klog_printf(" - copy failed");
  401.         return rc;
  402.     }
  403.  
  404.     call->buffer = buffer;
  405.  
  406.     klog_printf(" - done");
  407.     return 1; /* actually need becksend with retval 0 */
  408. }
  409.  
  410.  
  411. int udebug_request_preprocess(call_t *call, phone_t *phone)
  412. {
  413.     int rc;
  414.  
  415.     switch (IPC_GET_ARG1(call->data)) {
  416.     case UDEBUG_M_BEGIN:
  417.         rc = udebug_rp_begin(call, phone);
  418.         return rc;
  419.     case UDEBUG_M_GO:
  420.         rc = udebug_rp_go(call, phone);
  421.         return rc;
  422.     case UDEBUG_M_ARGS_READ:
  423.         rc = udebug_rp_args_read(call, phone);
  424.         return rc;
  425.     case UDEBUG_M_REGS_READ:
  426.         rc = udebug_rp_regs_read(call, phone);
  427.         return rc;
  428.     case UDEBUG_M_REGS_WRITE:
  429.         rc = udebug_rp_regs_write(call, phone);
  430.         return rc;
  431.     case UDEBUG_M_THREAD_READ:
  432.         rc = udebug_rp_thread_read(call, phone);
  433.         return rc;
  434.     case UDEBUG_M_MEM_WRITE:
  435.         rc = udebug_rp_mem_write(call, phone);
  436.         return rc;
  437.     default:
  438.         break;
  439.     }
  440.  
  441.     return 0;
  442. }
  443.  
  444. static void udebug_receive_mem_read(call_t *call)
  445. {
  446.     unative_t uspace_dst;
  447.     void *uspace_ptr;
  448.     unsigned size;
  449.     void *buffer;
  450.     int rc;
  451.  
  452.     klog_printf("debug_mem_read()");
  453.     uspace_dst = IPC_GET_ARG2(call->data);
  454.     uspace_ptr = (void *)IPC_GET_ARG3(call->data);
  455.     size = IPC_GET_ARG4(call->data);
  456.  
  457.     buffer = malloc(size, 0); // ???
  458.     klog_printf("debug_mem_read: src=%u, size=%u", uspace_ptr, size);
  459.  
  460.     /* NOTE: this is not strictly from a syscall... but that shouldn't
  461.      * be a problem */
  462.     rc = copy_from_uspace(buffer, uspace_ptr, size);
  463.     if (rc) {
  464.         IPC_SET_RETVAL(call->data, rc);
  465.         return;
  466.     }
  467.  
  468.     klog_printf("first word: %u", *((unative_t *)buffer));
  469.  
  470.     IPC_SET_RETVAL(call->data, 0);
  471.     /* Hack: ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
  472.        same code in process_answer() can be used
  473.        (no way to distinguish method in answer) */
  474.     IPC_SET_ARG1(call->data, uspace_dst);
  475.     IPC_SET_ARG2(call->data, size);
  476.     call->buffer = buffer;
  477.  
  478.     ipc_answer(&TASK->kernel_box, call);
  479. }
  480.  
  481. static void udebug_receive_mem_write(call_t *call)
  482. {
  483.     void *uspace_dst;
  484.     unsigned size;
  485.     void *buffer;
  486.     int rc;
  487.  
  488.     klog_printf("udebug_receive_mem_write()");
  489.     uspace_dst = (void *)IPC_GET_ARG3(call->data);
  490.     size = IPC_GET_ARG4(call->data);
  491.  
  492.     buffer = call->buffer;
  493.     klog_printf("dst=%u, size=%u", uspace_dst, size);
  494.  
  495.     /* NOTE: this is not strictly from a syscall... but that shouldn't
  496.      * be a problem */
  497.     rc = copy_to_uspace(uspace_dst, buffer, size);
  498.     if (rc) {
  499.         IPC_SET_RETVAL(call->data, rc);
  500.         return;
  501.     }
  502.  
  503.     IPC_SET_RETVAL(call->data, 0);
  504.  
  505.     free(call->buffer);
  506.     call->buffer = NULL;
  507.  
  508.     ipc_answer(&TASK->kernel_box, call);
  509. }
  510.  
  511.  
  512. /**
  513.  * Handle a debug call received on the kernel answerbox.
  514.  *
  515.  * This is called by the kbox servicing thread.
  516.  */
  517. void udebug_call_receive(call_t *call)
  518. {
  519.     int debug_method;
  520.  
  521.     debug_method = IPC_GET_ARG1(call->data);
  522.  
  523.     switch (debug_method) {
  524.     case UDEBUG_M_MEM_READ:
  525.         udebug_receive_mem_read(call);
  526.         break;
  527.     case UDEBUG_M_MEM_WRITE:
  528.         udebug_receive_mem_write(call);
  529.         break;
  530.     }
  531. }
  532.  
  533. /** @}
  534.  */
  535.