/branches/tracing/kernel/generic/include/proc/thread.h |
---|
214,6 → 214,7 |
/** What type of event are we stopped in or 0 if none */ |
udebug_event_t cur_event; |
bool debug_stop; |
bool debug_stoppable; |
bool debug_active; /**< In a debugging session */ |
} thread_t; |
/branches/tracing/kernel/generic/include/udebug/udebug.h |
---|
148,6 → 148,7 |
typedef enum { |
UDEBUG_EVENT_FINISHED = 1, /**< Debuging session has finished */ |
UDEBUG_EVENT_STOP, /**< Stopped on DEBUG_STOP request */ |
UDEBUG_EVENT_SYSCALL, /**< A syscall has been executed */ |
UDEBUG_EVENT_NEW_THREAD /**< The task created a new thread */ |
} udebug_event_t; |
/branches/tracing/kernel/generic/include/udebug/udebug_ops.h |
---|
41,6 → 41,7 |
int udebug_end(void); |
int udebug_go(thread_t *t, call_t *call); |
int udebug_stop(thread_t *t, call_t *call); |
int udebug_thread_read(void **buffer, size_t buf_size, size_t *n); |
int udebug_args_read(thread_t *t, void **buffer); |
/branches/tracing/kernel/generic/src/proc/thread.c |
---|
349,6 → 349,7 |
t->debug_go_call = NULL; |
t->uspace_state = NULL; |
t->debug_stop = true; |
t->debug_stoppable = true; |
t->debug_active = false; |
t->cur_event = 0; /* none */ |
/branches/tracing/kernel/generic/src/udebug/udebug_ipc.c |
---|
164,7 → 164,20 |
} |
} |
static void udebug_receive_stop(call_t *call) |
{ |
thread_t *t; |
int rc; |
klog_printf("debug_stop()"); |
t = (thread_t *)IPC_GET_ARG2(call->data); |
rc = udebug_stop(t, call); |
IPC_SET_RETVAL(call->data, rc); |
ipc_answer(&TASK->kernel_box, call); |
} |
static void udebug_receive_thread_read(call_t *call) |
{ |
unative_t uspace_addr; |
421,6 → 434,9 |
case UDEBUG_M_GO: |
udebug_receive_go(call); |
break; |
case UDEBUG_M_STOP: |
udebug_receive_stop(call); |
break; |
case UDEBUG_M_THREAD_READ: |
udebug_receive_thread_read(call); |
break; |
/branches/tracing/kernel/generic/src/udebug/udebug.c |
---|
44,7 → 44,7 |
void udebug_stoppable_begin(void) |
{ |
int nsc; |
call_t *db_call; |
call_t *db_call, *go_call; |
ipl_t ipl; |
ipl = interrupts_disable(); |
59,6 → 59,16 |
} |
if (TASK->dt_state == UDEBUG_TS_BEGINNING && nsc == 0) { |
/* |
* This was the last non-stoppable thread. Reply to |
* DEBUG_BEGIN call. |
*/ |
/* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
spinlock_lock(&THREAD->debug_lock); |
THREAD->debug_stoppable = true; |
spinlock_unlock(&THREAD->debug_lock); |
TASK->dt_state = UDEBUG_TS_ACTIVE; |
TASK->debug_begin_call = NULL; |
spinlock_unlock(&TASK->lock); |
67,7 → 77,53 |
IPC_SET_RETVAL(db_call->data, 0); |
klog_printf("udebug_stoppable_begin/ipc_answer"); |
ipc_answer(&TASK->answerbox, db_call); |
} else if (TASK->dt_state == UDEBUG_TS_ACTIVE) { |
/* |
* Active debugging session |
*/ |
/* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
spinlock_lock(&THREAD->debug_lock); |
THREAD->debug_stoppable = true; |
if (THREAD->debug_stop) { |
/* |
* Thread was requested to stop - answer go call |
*/ |
/* Make sure nobody takes this call away from us */ |
go_call = THREAD->debug_go_call; |
THREAD->debug_go_call = NULL; |
IPC_SET_RETVAL(go_call->data, 0); |
IPC_SET_ARG1(go_call->data, UDEBUG_EVENT_STOP); |
THREAD->cur_event = UDEBUG_EVENT_STOP; |
spinlock_unlock(&THREAD->debug_lock); |
ipc_answer(&TASK->answerbox, go_call); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
} else { |
/* |
* No stop request - nothing happens. |
*/ |
spinlock_unlock(&THREAD->debug_lock); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
} |
} else { |
/* |
* All other cases - nothing special happens. |
*/ |
/* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
spinlock_lock(&THREAD->debug_lock); |
THREAD->debug_stoppable = true; |
spinlock_unlock(&THREAD->debug_lock); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
} |
81,10 → 137,19 |
ipl = interrupts_disable(); |
spinlock_lock(&TASK->lock); |
/* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
spinlock_lock(&THREAD->debug_lock); |
if (TASK->dt_state == UDEBUG_TS_ACTIVE) { |
klog_printf("udebug_stoppable_end"); |
klog_printf("debug_stop=%d", THREAD->debug_stop); |
} |
if ((TASK->dt_state == UDEBUG_TS_BEGINNING || |
TASK->dt_state == UDEBUG_TS_ACTIVE) && |
THREAD->debug_stop == true) { |
TASK->debug_begin_call = NULL; |
spinlock_unlock(&THREAD->debug_lock); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
94,6 → 159,9 |
/* must try again - have to lose stoppability atomically */ |
} else { |
++TASK->not_stoppable_count; |
THREAD->debug_stoppable = false; |
spinlock_unlock(&THREAD->debug_lock); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
} |
/branches/tracing/kernel/generic/src/udebug/udebug_ops.c |
---|
52,9 → 52,10 |
* but only if it verifies all conditions. |
* |
* Specifically, verifies that thread t exists, is a userspace thread, |
* and belongs to the current task (TASK). It also locks t->debug_lock, |
* making sure that t->debug_active is true - that the thread is |
* in a valid debugging session. |
* and belongs to the current task (TASK). Verifies, that the thread |
* has (or hasn't) go according to having_go (typically false). |
* It also locks t->debug_lock, making sure that t->debug_active is true |
* - that the thread is in a valid debugging session. |
* |
* Returns EOK if all went well, or an error code otherwise. |
* Interrupts must be already disabled when calling this function. |
61,7 → 62,7 |
* |
* Note: This function sports complicated locking. |
*/ |
static int _thread_op_begin(thread_t *t) |
static int _thread_op_begin(thread_t *t, bool having_go) |
{ |
int rc; |
task_id_t taskid; |
93,9 → 94,9 |
goto error_exit; |
} |
if ((t->debug_active != true) || (t->debug_stop != true)) { |
/* Not in debugging session or already has GO */ |
rc = ENOENT; |
if ((t->debug_active != true) || (!t->debug_stop != having_go)) { |
/* Not in debugging session or undesired GO state */ |
rc = EINVAL; |
goto error_exit; |
} |
213,7 → 214,7 |
ipl = interrupts_disable(); |
/* On success, this will lock t->debug_lock */ |
rc = _thread_op_begin(t); |
rc = _thread_op_begin(t, false); |
if (rc != EOK) { |
interrupts_restore(ipl); |
return rc; |
234,7 → 235,60 |
return 0; |
} |
int udebug_stop(thread_t *t, call_t *call) |
{ |
ipl_t ipl; |
int rc; |
klog_printf("udebug_stop()"); |
ipl = interrupts_disable(); |
/* |
* On success, this will lock t->debug_lock. Note that this makes sure |
* the thread is not stopped. |
*/ |
rc = _thread_op_begin(t, true); |
if (rc != EOK) { |
interrupts_restore(ipl); |
return rc; |
} |
/* Take GO away from the thread */ |
t->debug_stop = true; |
if (!t->debug_stoppable) { |
/* Answer will be sent when the thread becomes stoppable */ |
_thread_op_end(t); |
interrupts_restore(ipl); |
return 0; |
} |
/* |
* Answer GO call |
*/ |
klog_printf("udebug_stop - answering go call"); |
/* Make sure nobody takes this call away from us */ |
call = t->debug_go_call; |
t->debug_go_call = NULL; |
IPC_SET_RETVAL(call->data, 0); |
IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP); |
klog_printf("udebug_stop/ipc_answer"); |
THREAD->cur_event = UDEBUG_EVENT_STOP; |
_thread_op_end(t); |
spinlock_lock(&TASK->lock); |
ipc_answer(&TASK->answerbox, call); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
klog_printf("udebog_stop/done"); |
return 0; |
} |
int udebug_thread_read(void **buffer, size_t buf_size, size_t *n) |
{ |
thread_t *t; |
310,7 → 364,7 |
ipl = interrupts_disable(); |
/* On success, this will lock t->debug_lock */ |
rc = _thread_op_begin(t); |
rc = _thread_op_begin(t, false); |
if (rc != EOK) { |
interrupts_restore(ipl); |
return rc; |
350,7 → 404,7 |
ipl = interrupts_disable(); |
/* On success, this will lock t->debug_lock */ |
rc = _thread_op_begin(t); |
rc = _thread_op_begin(t, false); |
if (rc != EOK) { |
interrupts_restore(ipl); |
return rc; |
389,7 → 443,7 |
ipl = interrupts_disable(); |
/* On success, this will lock t->debug_lock */ |
rc = _thread_op_begin(t); |
rc = _thread_op_begin(t, false); |
if (rc != EOK) { |
interrupts_restore(ipl); |
return rc; |
/branches/tracing/uspace/app/sctrace/debug_api.c |
---|
79,5 → 79,12 |
tid, (sysarg_t)ev_type, (sysarg_t)sc_id, (sysarg_t)sc_rc); |
} |
int debug_stop(unsigned phoneid, unsigned tid) |
{ |
return async_req_2_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_STOP, |
tid); |
} |
/** @} |
*/ |
/branches/tracing/uspace/app/sctrace/debug_api.h |
---|
43,6 → 43,7 |
int debug_args_read(unsigned phoneid, unsigned tid, unsigned *buffer); |
int debug_go(unsigned phoneid, unsigned tid, unsigned *ev_type, |
unsigned *sc_id, unsigned *sc_rc); |
int debug_stop(unsigned phoneid, unsigned tid); |
#endif |
/branches/tracing/uspace/app/sctrace/sctrace.c |
---|
62,6 → 62,9 |
int phoneid; |
int abort_trace; |
unsigned thash; |
volatile int paused; |
void thread_trace_start(unsigned thread_hash); |
static proto_t *proto_console; |
334,6 → 337,16 |
case UDEBUG_EVENT_SYSCALL: |
event_syscall(thread_id, thread_hash, val0, (int)val1); |
break; |
case UDEBUG_EVENT_STOP: |
printf("stop event\n"); |
printf("waiting for resume\n"); |
while (paused) { |
usleep(1000000); |
fibril_yield(); |
printf("."); |
} |
printf("resumed\n"); |
break; |
case UDEBUG_EVENT_NEW_THREAD: |
event_new_thread(val0); |
break; |
352,6 → 365,8 |
{ |
fid_t fid; |
thash = thread_hash; |
fid = fibril_create(trace_loop, (void *)thread_hash); |
if (fid == 0) { |
printf("Warning: Failed creating fibril\n"); |
364,6 → 379,7 |
int taskid; |
int i; |
int rc; |
int c; |
printf("Syscall Tracer\n"); |
printf("Press 'c' to connect\n"); |
394,7 → 410,18 |
thread_trace_start(thread_hash_buf[i]); |
} |
getchar(); |
while(1) { |
c = getchar(); |
if (c == 'q') break; |
if (c == 'p') { |
paused = 1; |
rc = debug_stop(phoneid, thash); |
printf("stop -> %d\n", rc); |
} |
if (c == 'r') { |
paused = 0; |
} |
} |
printf("terminate debugging session...\n"); |
abort_trace = 1; |
413,6 → 440,7 |
oper_t *o; |
next_thread_id = 1; |
paused = 0; |
proto_init(); |
/branches/tracing/uspace/app/tester/debug/debug1.c |
---|
43,26 → 43,33 |
#include <vfs/vfs.h> |
#include <errno.h> |
static ipc_call_t call; |
char * test_debug1(bool quiet) |
{ |
int rc; |
thread_id_t tid; |
// ipc_call_t call; |
done = 0; |
getchar(); |
if (mount("tmpfs", "/", "nulldev0") != EOK) |
return "mount() failed.\n"; |
getchar(); |
/* while(1) { |
printf("."); |
ipc_wait_for_call(&call); |
}*/ |
// getchar(); |
// if (mount("tmpfs", "/", "nulldev0") != EOK) |
// return "mount() failed.\n"; |
// getchar(); |
// printf("running debug1 test\n"); |
// rc = thread_create(t_proc, NULL, "test", &tid); |
//printf("(active) wait for thread 'test'\n"); |
// while (!done) { |
// usleep(20000000); |
// printf("."); |
// } |
while (!done) { |
usleep(1*1000*1000); |
printf("."); |
} |
// printf("done\n"); |
return NULL; |