47,34 → 47,6 |
} |
|
/** |
* Get and lock a phone's callee task. |
* |
* This will return a pointer to the task to which the phone |
* is connected. It will lock the task, making sure it exists. |
* |
* Interrupts must be already disabled. |
*/ |
static task_t *get_lock_callee_task(phone_t *phone) |
{ |
task_t *ta; |
task_id_t taskid; |
|
taskid = get_callee_task_id(phone); |
|
spinlock_lock(&tasks_lock); |
ta = task_find_by_id(taskid); |
if (ta == NULL) { |
spinlock_unlock(&tasks_lock); |
return NULL; |
} |
|
spinlock_lock(&ta->lock); |
spinlock_unlock(&tasks_lock); |
|
return ta; |
} |
|
/** |
* Prepare a thread for a debugging operation. |
* |
* Simply put, return thread t with t->debug_lock held, |
165,90 → 137,6 |
spinlock_unlock(&t->debug_lock); |
} |
|
static int udebug_rp_begin(call_t *call, phone_t *phone) |
{ |
task_t *ta; |
ipl_t ipl; |
int rc; |
|
thread_t *t; |
link_t *cur; |
|
klog_printf("debug_begin()"); |
|
ipl = interrupts_disable(); |
ta = get_lock_callee_task(phone); |
klog_printf("debugging task %llu", ta->taskid); |
|
if (ta->dt_state != UDEBUG_TS_INACTIVE) { |
spinlock_unlock(&ta->lock); |
interrupts_restore(ipl); |
klog_printf("debug_begin(): busy error"); |
return EBUSY; |
} |
|
ta->dt_state = UDEBUG_TS_BEGINNING; |
ta->debug_begin_call = call; |
ta->debugger = call->sender; |
|
if (ta->not_stoppable_count == 0) { |
ta->dt_state = UDEBUG_TS_ACTIVE; |
ta->debug_begin_call = NULL; |
rc = 1; /* actually we need backsend with 0 retval */ |
} else { |
rc = 0; /* no backsend */ |
} |
|
/* Set debug_active on all of the task's userspace threads */ |
|
for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
t = list_get_instance(cur, thread_t, th_link); |
|
spinlock_lock(&t->debug_lock); |
if ((t->flags & THREAD_FLAG_USPACE) != 0) |
t->debug_active = true; |
spinlock_unlock(&t->debug_lock); |
} |
|
spinlock_unlock(&ta->lock); |
interrupts_restore(ipl); |
|
klog_printf("debug_begin() done (%s)", |
rc ? "backsend" : "stoppability wait"); |
|
return rc; |
} |
|
static int udebug_rp_end(call_t *call, phone_t *phone) |
{ |
task_t *ta; |
ipl_t ipl; |
int rc; |
|
klog_printf("udebug_rp_end()"); |
|
ipl = interrupts_disable(); |
ta = get_lock_callee_task(phone); |
|
rc = udebug_task_cleanup(ta); |
|
klog_printf("task %llu", ta->taskid); |
|
spinlock_unlock(&ta->lock); |
interrupts_restore(ipl); |
|
if (rc < 0) { |
return EINVAL; |
} |
|
IPC_SET_RETVAL(call->data, 0); |
|
klog_printf("udebug_rp_end() done\n"); |
|
return 1; |
} |
|
|
static int udebug_rp_go(call_t *call, phone_t *phone) |
{ |
thread_t *t; |
444,14 → 332,149 |
return 1; /* actually need becksend with retval 0 */ |
} |
|
static int udebug_rp_thread_read(call_t *call, phone_t *phone) |
static int udebug_rp_mem_write(call_t *call, phone_t *phone) |
{ |
void *uspace_data; |
unative_t to_copy; |
int rc; |
void *buffer; |
|
klog_printf("udebug_rp_mem_write()"); |
|
uspace_data = (void *)IPC_GET_ARG2(call->data); |
to_copy = IPC_GET_ARG4(call->data); |
|
buffer = malloc(to_copy, 0); // ??? |
|
rc = copy_from_uspace(buffer, uspace_data, to_copy); |
if (rc != 0) { |
klog_printf(" - copy failed"); |
return rc; |
} |
|
call->buffer = buffer; |
|
klog_printf(" - done"); |
return 1; /* actually need becksend with retval 0 */ |
} |
|
|
int udebug_request_preprocess(call_t *call, phone_t *phone) |
{ |
int rc; |
|
switch (IPC_GET_ARG1(call->data)) { |
case UDEBUG_M_GO: |
rc = udebug_rp_go(call, phone); |
return rc; |
case UDEBUG_M_ARGS_READ: |
rc = udebug_rp_args_read(call, phone); |
return rc; |
case UDEBUG_M_REGS_READ: |
rc = udebug_rp_regs_read(call, phone); |
return rc; |
case UDEBUG_M_REGS_WRITE: |
rc = udebug_rp_regs_write(call, phone); |
return rc; |
case UDEBUG_M_MEM_WRITE: |
rc = udebug_rp_mem_write(call, phone); |
return rc; |
default: |
break; |
} |
|
return 0; |
} |
|
static void udebug_receive_begin(call_t *call) |
{ |
ipl_t ipl; |
int reply; |
|
thread_t *t; |
link_t *cur; |
task_t *ta; |
unative_t *uspace_buffer; |
|
klog_printf("debug_begin()"); |
|
ipl = interrupts_disable(); |
klog_printf("debugging task %llu", TASK->taskid); |
|
spinlock_lock(&TASK->lock); |
|
if (TASK->dt_state != UDEBUG_TS_INACTIVE) { |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
klog_printf("debug_begin(): busy error"); |
|
IPC_SET_RETVAL(call->data, EBUSY); |
ipc_answer(&TASK->kernel_box, call); |
} |
|
TASK->dt_state = UDEBUG_TS_BEGINNING; |
TASK->debug_begin_call = call; |
TASK->debugger = call->sender; |
|
if (TASK->not_stoppable_count == 0) { |
TASK->dt_state = UDEBUG_TS_ACTIVE; |
TASK->debug_begin_call = NULL; |
reply = 1; /* immediate reply */ |
} else { |
reply = 0; /* no reply */ |
} |
|
/* Set debug_active on all of the task's userspace threads */ |
|
for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) { |
t = list_get_instance(cur, thread_t, th_link); |
|
spinlock_lock(&t->debug_lock); |
if ((t->flags & THREAD_FLAG_USPACE) != 0) |
t->debug_active = true; |
spinlock_unlock(&t->debug_lock); |
} |
|
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
|
klog_printf("debug_begin() done (%s)", |
reply ? "reply" : "stoppability wait"); |
|
if (reply) ipc_answer(&TASK->kernel_box, call); |
} |
|
static void udebug_receive_end(call_t *call) |
{ |
ipl_t ipl; |
int rc; |
|
klog_printf("udebug_receive_end()"); |
|
ipl = interrupts_disable(); |
spinlock_lock(&TASK->lock); |
|
rc = udebug_task_cleanup(TASK); |
|
klog_printf("task %llu", TASK->taskid); |
|
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
|
if (rc < 0) { |
IPC_SET_RETVAL(call->data, EINVAL); |
ipc_answer(&TASK->kernel_box, call); |
return; |
} |
|
IPC_SET_RETVAL(call->data, 0); |
ipc_answer(&TASK->kernel_box, call); |
} |
|
static void udebug_receive_thread_read(call_t *call) |
{ |
thread_t *t; |
link_t *cur; |
unative_t uspace_addr; |
unative_t to_copy; |
int rc; |
unsigned total_bytes; |
unsigned buf_size; |
unative_t tid; |
463,19 → 486,22 |
klog_printf("debug_thread_read()"); |
|
ipl = interrupts_disable(); |
ta = get_lock_callee_task(phone); |
spinlock_lock(&TASK->lock); |
|
/* Verify task state */ |
if (ta->dt_state != UDEBUG_TS_ACTIVE) { |
spinlock_unlock(&ta->lock); |
if (TASK->dt_state != UDEBUG_TS_ACTIVE) { |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
return EBUSY; |
|
IPC_SET_RETVAL(call->data, EINVAL); |
ipc_answer(&TASK->kernel_box, call); |
return; |
} |
|
/* Count the threads first */ |
|
num_threads = 0; |
for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) { |
/* Count all threads, to be on the safe side */ |
++num_threads; |
} |
484,7 → 510,7 |
buffer = malloc(num_threads * sizeof(unative_t), 0); // ??? |
|
copied_ids = 0; |
for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) { |
t = list_get_instance(cur, thread_t, th_link); |
|
spinlock_lock(&t->lock); |
499,12 → 525,14 |
} |
} |
|
spinlock_unlock(&ta->lock); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
|
/* Now copy to userspace */ |
/* |
* Prepare data and send it back through call->buffer |
*/ |
|
uspace_buffer = (void *)IPC_GET_ARG2(call->data); |
uspace_addr = IPC_GET_ARG2(call->data); |
buf_size = IPC_GET_ARG3(call->data); |
|
total_bytes = copied_ids * sizeof(unative_t); |
514,84 → 542,20 |
else |
to_copy = buf_size; |
|
rc = copy_to_uspace(uspace_buffer, buffer, to_copy); |
free(buffer); |
IPC_SET_RETVAL(call->data, 0); |
/* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that |
same code in process_answer() can be used |
(no way to distinguish method in answer) */ |
IPC_SET_ARG1(call->data, uspace_addr); |
IPC_SET_ARG2(call->data, to_copy); |
|
if (rc != 0) { |
klog_printf("debug_thread_read() - copy failed"); |
return rc; |
} |
IPC_SET_ARG3(call->data, total_bytes); |
call->buffer = (void *)buffer; |
|
IPC_SET_ARG1(call->data, to_copy); |
IPC_SET_ARG2(call->data, total_bytes); |
|
klog_printf("debug_thread_read() done"); |
return 1; /* actually need becksend with retval 0 */ |
ipc_answer(&TASK->kernel_box, call); |
} |
|
static int udebug_rp_mem_write(call_t *call, phone_t *phone) |
{ |
void *uspace_data; |
unative_t to_copy; |
int rc; |
void *buffer; |
|
klog_printf("udebug_rp_mem_write()"); |
|
uspace_data = (void *)IPC_GET_ARG2(call->data); |
to_copy = IPC_GET_ARG4(call->data); |
|
buffer = malloc(to_copy, 0); // ??? |
|
rc = copy_from_uspace(buffer, uspace_data, to_copy); |
if (rc != 0) { |
klog_printf(" - copy failed"); |
return rc; |
} |
|
call->buffer = buffer; |
|
klog_printf(" - done"); |
return 1; /* actually need becksend with retval 0 */ |
} |
|
|
int udebug_request_preprocess(call_t *call, phone_t *phone) |
{ |
int rc; |
|
switch (IPC_GET_ARG1(call->data)) { |
case UDEBUG_M_BEGIN: |
rc = udebug_rp_begin(call, phone); |
return rc; |
case UDEBUG_M_END: |
rc = udebug_rp_end(call, phone); |
return rc; |
case UDEBUG_M_GO: |
rc = udebug_rp_go(call, phone); |
return rc; |
case UDEBUG_M_ARGS_READ: |
rc = udebug_rp_args_read(call, phone); |
return rc; |
case UDEBUG_M_REGS_READ: |
rc = udebug_rp_regs_read(call, phone); |
return rc; |
case UDEBUG_M_REGS_WRITE: |
rc = udebug_rp_regs_write(call, phone); |
return rc; |
case UDEBUG_M_THREAD_READ: |
rc = udebug_rp_thread_read(call, phone); |
return rc; |
case UDEBUG_M_MEM_WRITE: |
rc = udebug_rp_mem_write(call, phone); |
return rc; |
default: |
break; |
} |
|
return 0; |
} |
|
static void udebug_receive_mem_read(call_t *call) |
{ |
unative_t uspace_dst; |
686,6 → 650,15 |
debug_method = IPC_GET_ARG1(call->data); |
|
switch (debug_method) { |
case UDEBUG_M_BEGIN: |
udebug_receive_begin(call); |
break; |
case UDEBUG_M_END: |
udebug_receive_end(call); |
break; |
case UDEBUG_M_THREAD_READ: |
udebug_receive_thread_read(call); |
break; |
case UDEBUG_M_MEM_READ: |
udebug_receive_mem_read(call); |
break; |