Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2884 → Rev 2885

/branches/tracing/kernel/generic/src/udebug/udebug_ipc.c
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;