/branches/tracing/kernel/doc/doxygroups.h |
---|
300,6 → 300,10 |
* @endcond |
*/ |
/** @defgroup tdebug Task Debugging |
* @ingroup kernel |
*/ |
/** @defgroup interrupt Interrupt handling and dispatching |
* @ingroup kernel |
*/ |
/branches/tracing/kernel/generic/include/proc/task.h |
---|
52,6 → 52,7 |
#include <arch/cpu.h> |
#include <mm/tlb.h> |
#include <proc/scheduler.h> |
#include <tdebug/tdebug_type.h> |
struct thread; |
107,6 → 108,9 |
/** Accumulated accounting. */ |
uint64_t cycles; |
/** Task debugging stuff */ |
task_tdebug_t tdebug; |
} task_t; |
SPINLOCK_EXTERN(tasks_lock); |
/branches/tracing/kernel/generic/include/proc/tasklet.h |
---|
58,7 → 58,7 |
tasklet_callback_t callback; |
/** Argument passed to the callback */ |
void* arg; |
void *arg; |
/** State of the tasklet */ |
tasklet_state_t state; |
/branches/tracing/kernel/generic/include/proc/thread.h |
---|
46,6 → 46,7 |
#include <arch/cpu.h> |
#include <mm/tlb.h> |
#include <proc/uarg.h> |
#include <tdebug/tdebug_type.h> |
#define THREAD_STACK_SIZE STACK_SIZE |
#define THREAD_NAME_BUFLEN 20 |
203,6 → 204,9 |
/** Thread's kernel stack. */ |
uint8_t *kstack; |
/** Task debugging stuff */ |
thread_tdebug_t tdebug; |
} thread_t; |
/** Thread list lock. |
248,6 → 252,8 |
extern void thread_update_accounting(void); |
extern bool thread_exists(thread_t *t); |
extern thread_t *thread_find_by_id(thread_id_t id); |
/** Fpu context slab cache. */ |
extern slab_cache_t *fpu_context_slab; |
/branches/tracing/kernel/generic/include/syscall/syscall.h |
---|
66,6 → 66,13 |
SYS_SYSINFO_VALID, |
SYS_SYSINFO_VALUE, |
SYS_DEBUG_ENABLE_CONSOLE, |
SYS_TDEBUG_ATTACH_TASK, |
SYS_TDEBUG_DETACH_TASK, |
SYS_TDEBUG_CONTINUE_THREAD, |
SYS_TDEBUG_GET_SYSCALL_ARGS, |
SYS_TDEBUG_SET_EVENT_MASK, |
SYS_TDEBUG_STOP_THREAD, |
SYS_TDEBUG_STOP_TASK, |
SYSCALL_END |
} syscall_t; |
/branches/tracing/kernel/generic/include/tdebug/systdebug.h |
---|
0,0 → 1,26 |
/** @addtogroup tdebug |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_SYSTDEBUG_H_ |
#define KERN_SYSTDEBUG_H_ |
#include <arch/types.h> |
#include <syscall/sysarg64.h> |
unative_t sys_tdebug_attach_task(sysarg64_t *task_id, unative_t method); |
unative_t sys_tdebug_detach_task(sysarg64_t *task_id); |
unative_t sys_tdebug_continue_thread(sysarg64_t *thread_id); |
unative_t sys_tdebug_get_syscall_args(sysarg64_t *thread_id, |
uintptr_t *buffer, unative_t *len); |
unative_t sys_tdebug_set_event_mask(sysarg64_t *thread_id, unative_t ev_mask); |
unative_t sys_tdebug_stop_thread(sysarg64_t *thread_id); |
unative_t sys_tdebug_stop_task(sysarg64_t *task_id); |
#endif |
/** @} |
*/ |
/branches/tracing/kernel/generic/include/tdebug/tdebug.h |
---|
0,0 → 1,51 |
/** @addtogroup tdebug |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_TDEBUG_H_ |
#define KERN_TDEBUG_H_ |
#include <atomic.h> |
#include <arch/types.h> |
#include <tdebug/tdebug_type.h> |
#include <arch.h> |
/* |
* Managing tdebug structures. |
*/ |
void tdebug_task_init(struct task *ta); |
void tdebug_thread_init(struct thread *t); |
void tdebug_cleanup(void); |
/* |
* Creating hooks at strategic points in the kernel. |
*/ |
void tdebug_syscall_event(unative_t a1, unative_t a2, unative_t a3, |
unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc); |
void tdebug_exception_event(int n); |
void tdebug_stopping_point(void); |
static inline int tdebug_have_monitor() |
{ |
return atomic_get(&TASK->tdebug.have_monitor); |
} |
/* |
* Used to implement tdebug syscalls |
*/ |
int tdebug_attach_task(task_id_t taskid, unative_t method); |
int tdebug_detach_task(task_id_t taskid); |
int tdebug_continue_thread(thread_id_t tid); |
int tdebug_get_syscall_args(thread_id_t tid, unative_t *sc_args); |
int tdebug_set_event_mask(thread_id_t tid, unative_t ev_mask); |
int tdebug_stop_thread(thread_id_t tid); |
int tdebug_stop_task(task_id_t taskid); |
#endif |
/** @} |
*/ |
/branches/tracing/kernel/generic/include/tdebug/tdebug_type.h |
---|
0,0 → 1,80 |
/** @addtogroup tdebug |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_TDEBUG_TYPE_H_ |
#define KERN_TDEBUG_TYPE_H_ |
/** |
* Type of tdebug event. |
*/ |
typedef enum { |
TDEBUG_EV_STOP, /**< stopped on monitor request */ |
TDEBUG_EV_SYSCALL, /**< syscall */ |
TDEBUG_EV_EXCEPTION, /**< hardware exception */ |
TDEBUG_EV_IBEFORE, /**< before executing an instruction */ |
TDEBUG_EV_IAFTER /**< after executing an instruction */ |
} tdebug_event_t; |
/** |
* Event type bitmasks. |
*/ |
typedef enum { |
TDEBUG_EVMASK_STOP = (1 << TDEBUG_EV_STOP), |
TDEBUG_EVMASK_SYSCALL = (1 << TDEBUG_EV_SYSCALL), |
TDEBUG_EVMASK_EXCEPTION = (1 << TDEBUG_EV_EXCEPTION), |
TDEBUG_EVMASK_IBEFORE = (1 << TDEBUG_EV_IBEFORE), |
TDEBUG_EVMASK_IAFTER = (1 << TDEBUG_EV_IAFTER), |
} tdebug_evmask_t; |
#ifdef KERNEL |
#include <atomic.h> |
#include <arch/types.h> |
#include <arch/interrupt.h> |
#include <synch/condvar.h> |
struct thread; |
struct task; |
/** |
* A part of the task structure related to the tdebug interface. |
* Access is synchronized using task lock of the containing task structure, |
* except for the field have_monitor, which is not locked. |
*/ |
typedef struct task_tdebug { |
atomic_t have_monitor; /**< this field is only informative */ |
struct task *monitor; /**< points to the monitoring task or NULL */ |
unative_t method; /**< method number to use with notifications */ |
link_t targets; |
link_t targets_link; |
} task_tdebug_t; |
/** |
* A part of the thread structure related to the tdebug interface. |
*/ |
typedef struct thread_tdebug { |
int stopped; |
condvar_t stopped_cv; |
unative_t current_event; |
int stop_request; |
unative_t event_mask; |
/** Points to the stored userspace istate or NULL if none */ |
istate_t *uspace_state; |
unative_t *syscall_args; |
} thread_tdebug_t; |
#endif /* KERNEL */ |
#endif |
/** @} |
*/ |
/branches/tracing/kernel/generic/src/interrupt/interrupt.c |
---|
47,6 → 47,7 |
#include <panic.h> |
#include <print.h> |
#include <symtab.h> |
#include <tdebug/tdebug.h> |
static struct { |
const char *name; |
86,8 → 87,19 |
void exc_dispatch(int n, istate_t *istate) |
{ |
ASSERT(n < IVT_ITEMS); |
if (THREAD && istate_from_uspace(istate)) { |
/* Record userspace state */ |
THREAD->tdebug.uspace_state = istate; |
} |
exc_table[n].f(n + IVT_FIRST, istate); |
if (THREAD && istate_from_uspace(istate)) { |
/* Clear it again (mostly for dev. and debugging purposes) */ |
THREAD->tdebug.uspace_state = NULL; |
} |
/* This is a safe place to exit exiting thread */ |
if (THREAD && THREAD->interrupted && istate_from_uspace(istate)) |
thread_exit(); |
/branches/tracing/kernel/generic/src/proc/task.c |
---|
57,6 → 57,7 |
#include <errno.h> |
#include <func.h> |
#include <syscall/copy.h> |
#include <tdebug/tdebug.h> |
#ifndef LOADED_PROG_STACK_PAGES_NO |
#define LOADED_PROG_STACK_PAGES_NO 1 |
170,7 → 171,10 |
ta->capabilities = 0; |
ta->cycles = 0; |
/* init tdebug related stuff */ |
tdebug_task_init(ta); |
ipc_answerbox_init(&ta->answerbox); |
for (i = 0; i < IPC_MAX_PHONES; i++) |
ipc_phone_init(&ta->phones[i]); |
/branches/tracing/kernel/generic/src/proc/thread.c |
---|
68,6 → 68,7 |
#include <syscall/copy.h> |
#include <errno.h> |
#include <console/klog.h> |
#include <tdebug/tdebug.h> |
/** Thread states */ |
341,10 → 342,14 |
avltree_node_initialize(&t->threads_tree_node); |
t->threads_tree_node.key = (uintptr_t) t; |
// t->threads_tree_node.key = (avltree_key_t) t->tid; |
/* might depend on previous initialization */ |
thread_create_arch(t); |
thread_create_arch(t); |
/* init tdebug stuff */ |
tdebug_thread_init(t); |
if (!(flags & THREAD_FLAG_NOATTACH)) |
thread_attach(t, task); |
442,6 → 447,7 |
if (THREAD->flags & THREAD_FLAG_USPACE) { |
ipc_cleanup(); |
futex_cleanup(); |
tdebug_cleanup(); |
klog_printf("Cleanup of task %llu completed.", |
TASK->taskid); |
} |
749,6 → 755,56 |
return 0; |
} |
struct fbiw { |
thread_id_t tid; |
thread_t *t; |
}; |
static bool find_by_id_walker(avltree_node_t *node, void *arg) |
{ |
thread_t *t = avltree_get_instance(node, thread_t, threads_tree_node); |
struct fbiw *s = (struct fbiw *)arg; |
if (t->tid == s->tid) { |
/* found it! */ |
s->t = t; |
return false; |
} |
return true; /* continue */ |
} |
/** Find thread structure corresponding to thread ID. |
* |
* The threads_lock must be already held by the caller of this function |
* and interrupts must be disabled. |
* |
* @param id Thread ID. |
* |
* @return Thread structure address or NULL if there is no such thread ID. |
*/ |
thread_t *thread_find_by_id(thread_id_t id) |
{ |
struct fbiw s; |
s.t = NULL; |
s.tid = id; |
avltree_walk(&threads_tree, find_by_id_walker, &s); |
return s.t; |
/* |
// ANO, takhle krasne by to fungovalo, kdyby threads_tree |
// nepouzival jako klic pointer na vlakno misto tid |
avltree_node_t *node; |
node = avltree_search(&threads_tree, (avltree_key_t) id); |
if (node) |
return avltree_get_instance(node, thread_t, threads_tree_node); |
return NULL;*/ |
} |
/** Syscall for getting TID. |
* |
* @param uspace_thread_id Userspace address of 8-byte buffer where to store |
/branches/tracing/kernel/generic/src/syscall/syscall.c |
---|
44,6 → 44,8 |
#include <errno.h> |
#include <arch.h> |
#include <debug.h> |
#include <tdebug/tdebug.h> |
#include <tdebug/systdebug.h> |
#include <ipc/sysipc.h> |
#include <synch/futex.h> |
#include <ddi/ddi.h> |
105,7 → 107,15 |
task_kill(TASK->taskid); |
thread_exit(); |
} |
if (tdebug_have_monitor()) { |
/* generate a syscall debug event */ |
tdebug_syscall_event(a1, a2, a3, a4, a5, a6, id, rc); |
/* a good place to stop */ |
tdebug_stopping_point(); |
} |
if (THREAD->interrupted) |
thread_exit(); |
158,7 → 168,16 |
(syshandler_t) sys_sysinfo_value, |
/* Debug calls */ |
(syshandler_t) sys_debug_enable_console |
(syshandler_t) sys_debug_enable_console, |
/* Task debugging calls */ |
(syshandler_t) sys_tdebug_attach_task, |
(syshandler_t) sys_tdebug_detach_task, |
(syshandler_t) sys_tdebug_continue_thread, |
(syshandler_t) sys_tdebug_get_syscall_args, |
(syshandler_t) sys_tdebug_set_event_mask, |
(syshandler_t) sys_tdebug_stop_thread, |
(syshandler_t) sys_tdebug_stop_task |
}; |
/** @} |
/branches/tracing/kernel/generic/src/tdebug/systdebug.c |
---|
0,0 → 1,172 |
/** @addtogroup tdebug |
* @{ |
*/ |
/** |
* @file |
* @brief Task Debugging Syscalls. |
*/ |
#include <proc/task.h> |
#include <syscall/sysarg64.h> |
#include <syscall/copy.h> |
#include <console/klog.h> |
#include <tdebug/tdebug.h> |
#include <tdebug/systdebug.h> |
/** |
* Syscall to start debugging a task. |
* |
* The specified task (target) is attached to the current task (monitor). |
* The monitoring task will be informed of debug events in the |
* target task through IPC notifications with the specified method number. |
*/ |
unative_t sys_tdebug_attach_task(sysarg64_t *uspace_taskid_arg, |
unative_t method) |
{ |
sysarg64_t taskid_arg; |
int rc; |
rc = copy_from_uspace(&taskid_arg, uspace_taskid_arg, sizeof(sysarg64_t)); |
if (rc != 0) |
return (unative_t) rc; |
klog_printf("sys_tdebug_attach_task(%lld, %d)", taskid_arg.value, method); |
return tdebug_attach_task(taskid_arg.value, method); |
} |
/** |
* Syscall to stop debugging a task. |
*/ |
unative_t sys_tdebug_detach_task(sysarg64_t *uspace_taskid_arg) |
{ |
sysarg64_t taskid_arg; |
int rc; |
rc = copy_from_uspace(&taskid_arg, uspace_taskid_arg, sizeof(sysarg64_t)); |
if (rc != 0) |
return (unative_t) rc; |
klog_printf("sys_tdebug_detach_task(%lld)", taskid_arg.value); |
return tdebug_detach_task(taskid_arg.value); |
} |
/** |
* Syscall to resume a thread stopped in a debugging event. |
*/ |
unative_t sys_tdebug_continue_thread(sysarg64_t *uspace_threadid_arg) |
{ |
sysarg64_t threadid_arg; |
int rc; |
rc = copy_from_uspace(&threadid_arg, uspace_threadid_arg, |
sizeof(sysarg64_t)); |
if (rc != 0) |
return (unative_t) rc; |
klog_printf("sys_tdebug_continue_thread(%lld)", threadid_arg.value); |
return tdebug_continue_thread(threadid_arg.value); |
} |
/** |
* Syscall to retrieve the arguments of a syscall. |
* |
* When a thread is stopped in a TDEBUG_EV_SYSCALL event, |
* this function may be used to retrieve the arguments of the |
* corresponding syscall. |
*/ |
unative_t sys_tdebug_get_syscall_args(sysarg64_t *uspace_threadid_arg, |
uintptr_t *uspace_buffer, unative_t *uspace_len_arg) |
{ |
sysarg64_t threadid_arg; |
unative_t len_arg; |
unative_t sc_args[6]; |
int rc; |
rc = copy_from_uspace(&threadid_arg, uspace_threadid_arg, |
sizeof(sysarg64_t)); |
if (rc != 0) |
return (unative_t) rc; |
rc = copy_from_uspace(&len_arg, uspace_len_arg, sizeof(unative_t)); |
if (rc != 0) |
return (unative_t) rc; |
klog_printf("sys_tdebug_get_syscall_args(%lld,...)", threadid_arg.value); |
/* number of args to be copied */ |
if (len_arg > 6) len_arg = 6; |
rc = tdebug_get_syscall_args(threadid_arg.value, sc_args); |
if (rc != 0) |
return (unative_t) rc; |
rc = copy_to_uspace(uspace_buffer, sc_args, len_arg * sizeof(unative_t)); |
if (rc != 0) |
return (unative_t) rc; |
/* actual number of syscall args */ |
len_arg = 6; |
rc = copy_to_uspace(uspace_len_arg, &len_arg, sizeof(unative_t)); |
if (rc != 0) |
return (unative_t) rc; |
klog_printf("success\n"); |
return 0; |
} |
unative_t sys_tdebug_set_event_mask(sysarg64_t *uspace_threadid_arg, |
unative_t ev_mask) |
{ |
sysarg64_t threadid_arg; |
int rc; |
rc = copy_from_uspace(&threadid_arg, uspace_threadid_arg, |
sizeof(sysarg64_t)); |
if (rc != 0) |
return (unative_t) rc; |
klog_printf("sys_tdebug_set_event_mask(%lld)", threadid_arg.value); |
return tdebug_set_event_mask(threadid_arg.value, ev_mask); |
} |
unative_t sys_tdebug_stop_thread(sysarg64_t *uspace_threadid_arg) |
{ |
sysarg64_t threadid_arg; |
int rc; |
rc = copy_from_uspace(&threadid_arg, uspace_threadid_arg, |
sizeof(sysarg64_t)); |
if (rc != 0) |
return (unative_t) rc; |
klog_printf("sys_tdebug_stop_thread(%lld)", threadid_arg.value); |
return tdebug_stop_thread(threadid_arg.value); |
} |
unative_t sys_tdebug_stop_task(sysarg64_t *uspace_taskid_arg) |
{ |
sysarg64_t taskid_arg; |
int rc; |
rc = copy_from_uspace(&taskid_arg, uspace_taskid_arg, sizeof(sysarg64_t)); |
if (rc != 0) |
return (unative_t) rc; |
klog_printf("sys_tdebug_stop_task(%lld)", taskid_arg.value); |
return tdebug_stop_task(taskid_arg.value); |
} |
/branches/tracing/kernel/generic/src/tdebug/tdebug.c |
---|
0,0 → 1,757 |
/** @addtogroup tdebug |
* @{ |
*/ |
/** |
* @file |
* @brief Task Debugging. |
*/ |
#include <arch.h> |
#include <atomic.h> |
#include <ipc/ipc.h> |
#include <proc/task.h> |
#include <synch/spinlock.h> |
#include <synch/waitq.h> |
#include <console/klog.h> |
#include <errno.h> |
//#include <arch/tdebug.h> |
#include <tdebug/tdebug.h> |
//FIXME: need to reset tdebug_thread structure for each thread |
//either on monitor attach or on monitor detach |
static void _tdebug_send_msg(task_t *ta, unative_t method, unative_t a1, unative_t a2, |
unative_t a3, unative_t a4, unative_t a5); |
void tdebug_task_init(struct task *ta) |
{ |
atomic_set(&ta->tdebug.have_monitor, 0); |
ta->tdebug.monitor = NULL; |
list_initialize(&ta->tdebug.targets); |
} |
/** |
* Initialize the tdebug part of a thread structure. |
*/ |
void tdebug_thread_init(struct thread *t) |
{ |
t->tdebug.stopped = 0; |
condvar_initialize(&t->tdebug.stopped_cv); |
t->tdebug.stop_request = 0; |
t->tdebug.event_mask = TDEBUG_EVMASK_SYSCALL | TDEBUG_EVMASK_EXCEPTION; |
t->tdebug.syscall_args = NULL; |
} |
/** |
* Clean-up all tdebug activities of the current task. |
*/ |
void tdebug_cleanup(void) |
{ |
ipl_t ipl; |
task_t *mon_task; |
klog_printf("tdebug_cleanup()"); |
/* |
* First detach any targets monitored by this task. |
*/ |
loop_1: |
ipl = interrupts_disable(); |
spinlock_lock(&TASK->lock); |
while (TASK->tdebug.targets.next != &TASK->tdebug.targets) { |
link_t *cur = TASK->tdebug.targets.next; |
task_t *ta; |
DEADLOCK_PROBE_INIT(p_target_lock); |
klog_printf(" - detaching a target"); |
ta = list_get_instance(cur, task_t, tdebug.targets_link); |
if (!spinlock_trylock(&ta->lock)) { |
/* |
* Avoid deadlock by trying again. |
*/ |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
DEADLOCK_PROBE(p_target_lock, DEADLOCK_THRESHOLD); |
goto loop_1; |
} |
/* this task should be the target's monitor */ |
ASSERT(TASK == ta->tdebug.monitor); |
ta->tdebug.monitor = NULL; |
list_remove(&ta->tdebug.targets_link); |
spinlock_unlock(&ta->lock); |
} |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
/* |
* Now if this task is being monitored, detach from the monitor. |
*/ |
loop_2: |
ipl = interrupts_disable(); |
spinlock_lock(&TASK->lock); |
if (TASK->tdebug.monitor != NULL) { |
/* yes, so detach */ |
DEADLOCK_PROBE_INIT(p_monitor_lock); |
klog_printf(" - detaching from the monitor"); |
mon_task = TASK->tdebug.monitor; |
if (!spinlock_trylock(&mon_task->lock)) { |
/* |
* Avoid deadlock by trying again. |
*/ |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
DEADLOCK_PROBE(p_monitor_lock, DEADLOCK_THRESHOLD); |
goto loop_2; |
} |
list_remove(&TASK->tdebug.targets_link); |
TASK->tdebug.monitor = NULL; |
spinlock_unlock(&mon_task->lock); |
} |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
klog_printf("tdebug_cleanup done"); |
} |
static void _tdebug_clear_event_unsafe(void) |
{ |
THREAD->tdebug.stopped = 0; |
THREAD->tdebug.syscall_args = NULL; |
} |
static void _tdebug_reset_thread_struct_unsafe(void) |
{ |
_tdebug_clear_event_unsafe(); |
THREAD->tdebug.stop_request = 0; |
THREAD->tdebug.event_mask = 0; |
} |
/** |
* Sleep until the thread is no longer stopped. |
* |
* Go to sleep iff the thread still has stopped==1 |
* and sleep until it is resumed. |
* |
* This will also clear the debugging event.!!!! |
*/ |
static void _tdebug_wait_and_clear(void) |
{ |
ipl_t ipl, ipl2; |
int rc; |
waitq_t *wq; |
/* wait until we are resumed */ |
klog_printf("wait..."); |
ipl = interrupts_disable(); |
spinlock_lock(&THREAD->lock); |
wq = &THREAD->tdebug.stopped_cv.wq; |
/* |
* Waiting for THREAD->tdebug.stopped to become 0. |
* |
* This is almost the same as condvar_wait, except that |
* instead of a mutex, the THREAD->lock spinlock is used |
* for mutual exclusion. |
*/ |
while (THREAD->tdebug.stopped != 0) { |
spinlock_unlock(&THREAD->lock); |
/* "spinvar_wait()" */ |
//printf("waitq_sleep_prepare...\n"); |
ipl2 = waitq_sleep_prepare(wq); |
//printf("waitq_sleep_prepare... ok\n"); |
wq->missed_wakeups = 0; |
rc = waitq_sleep_timeout_unsafe(wq, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE); |
spinlock_lock(&THREAD->lock); |
waitq_sleep_finish(wq, rc, ipl2); |
} |
_tdebug_clear_event_unsafe(); |
spinlock_unlock(&THREAD->lock); |
interrupts_restore(ipl); |
klog_printf("done waiting"); |
} |
/** |
* Send a notification to the monitoring task. |
* |
* Returns 0 on success or -1 if no debugger is present. |
*/ |
static int _tdebug_notify_debugger(thread_id_t tid, unative_t a1, |
unative_t a2, unative_t a3) |
{ |
unative_t tid_lo, tid_hi; |
ipl_t ipl; |
task_t *monitor; |
DEADLOCK_PROBE_INIT(p_monitor_lock); |
tid_lo = tid & 0xffffffff; |
tid_hi = tid >> 16; |
/* send notification to the monitoring task */ |
loop: |
ipl = interrupts_disable(); |
spinlock_lock(&TASK->lock); |
monitor = TASK->tdebug.monitor; |
if (monitor == NULL) { |
/* there's no monitor anymore */ |
spinlock_unlock(&TASK->lock); |
/* |
* Reset the debugging struct |
*/ |
spinlock_lock(&THREAD->lock); |
_tdebug_reset_thread_struct_unsafe(); |
spinlock_unlock(&THREAD->lock); |
interrupts_restore(ipl); |
return -1; |
} |
if (!spinlock_trylock(&monitor->lock)) { |
/* |
* Avoid deadlock by trying again |
*/ |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
DEADLOCK_PROBE(p_monitor_lock, DEADLOCK_THRESHOLD); |
goto loop; |
} |
_tdebug_send_msg(TASK->tdebug.monitor, TASK->tdebug.method, |
tid_lo, tid_hi, a1, a2, a3); |
spinlock_unlock(&TASK->lock); |
spinlock_unlock(&monitor->lock); |
interrupts_restore(ipl); |
return 0; |
} |
/** |
* Generate a syscall debug event. |
* |
* Called from syscall_handler() in syscall.c. The current task |
* may or may not have a monitor attached. |
* If a monitor is not attached or syscall events are not enabled, |
* no action is taken. |
*/ |
void tdebug_syscall_event(unative_t a1, unative_t a2, unative_t a3, |
unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t sc_rc) |
{ |
unative_t sc_args[6]; |
ipl_t ipl; |
thread_id_t tid; |
klog_printf("TASK %llu: Syscall id %lx", TASK->taskid, id); |
klog_printf("THREAD %llu", THREAD->tid); |
/* no need to lock this */ |
tid = THREAD->tid; |
/* copy down arguments to an array */ |
sc_args[0] = a1; |
sc_args[1] = a2; |
sc_args[2] = a3; |
sc_args[3] = a4; |
sc_args[4] = a5; |
sc_args[5] = a6; |
ipl = interrupts_disable(); |
spinlock_lock(&THREAD->lock); |
if ((THREAD->tdebug.event_mask & TDEBUG_EVMASK_SYSCALL) == 0) { |
/* syscall event not enabled */ |
spinlock_unlock(&THREAD->lock); |
interrupts_restore(ipl); |
return; |
} |
/* record the debugging event into our thread structure */ |
THREAD->tdebug.syscall_args = sc_args; |
THREAD->tdebug.stopped = 1; |
THREAD->tdebug.current_event = TDEBUG_EV_SYSCALL; |
spinlock_unlock(&THREAD->lock); |
interrupts_restore(ipl); |
/* |
* Send notification to the monitoring task |
* This may fail as we needn't have a monitor attached |
*/ |
if (_tdebug_notify_debugger(tid, TDEBUG_EV_SYSCALL, id, sc_rc) == 0) { |
/* wait for resume */ |
_tdebug_wait_and_clear(); |
} |
} |
/** |
* Generate an exception debug event. |
* |
* Called from exc_dispatch() in interrupt.c. The current task |
* may or may not have a monitor attached. |
* If a monitor is not attached or exception events are not enabled, |
* no action is taken. |
*/ |
void tdebug_exception_event(int n) |
{ |
ipl_t ipl; |
thread_id_t tid; |
klog_printf("TASK %llu: exception %d", TASK->taskid, n); |
klog_printf("THREAD %llu", THREAD->tid); |
/* no need to lock this */ |
tid = THREAD->tid; |
ipl = interrupts_disable(); |
spinlock_lock(&THREAD->lock); |
if ((THREAD->tdebug.event_mask & TDEBUG_EVMASK_EXCEPTION) == 0) { |
/* exception event not enabled */ |
spinlock_unlock(&THREAD->lock); |
interrupts_restore(ipl); |
return; |
} |
/* record the debugging event into our thread structure */ |
THREAD->tdebug.stopped = 1; |
THREAD->tdebug.current_event = TDEBUG_EV_EXCEPTION; |
spinlock_unlock(&THREAD->lock); |
interrupts_restore(ipl); |
/* |
* Send notification to the monitoring task |
* This may fail as we needn't have a monitor attached |
*/ |
if (_tdebug_notify_debugger(tid, TDEBUG_EV_EXCEPTION, n, 0) == 0) { |
/* wait for resume */ |
_tdebug_wait_and_clear(); |
} |
} |
/** |
* Stop the thread here if a stop request is pending. |
*/ |
void tdebug_stopping_point(void) |
{ |
ipl_t ipl; |
thread_id_t tid; |
klog_printf("TASK %llu: stopping point", TASK->taskid); |
klog_printf("THREAD %llu", THREAD->tid); |
/* no need to lock this */ |
tid = THREAD->tid; |
ipl = interrupts_disable(); |
spinlock_lock(&THREAD->lock); |
if (THREAD->tdebug.stop_request == 0) { |
/* stop not requested */ |
spinlock_unlock(&THREAD->lock); |
interrupts_restore(ipl); |
return; |
} |
/* record the debugging event into our thread structure */ |
THREAD->tdebug.stopped = 1; |
THREAD->tdebug.current_event = TDEBUG_EV_STOP; |
spinlock_unlock(&THREAD->lock); |
interrupts_restore(ipl); |
/* send notification to the monitoring task */ |
if (_tdebug_notify_debugger(tid, TDEBUG_EV_STOP, 0, 0) == 0) { |
/* wait for resume */ |
_tdebug_wait_and_clear(); |
} |
} |
/** |
* Send an IPC notification to a task. |
* |
* When calling the task's lock must be already held and interrupts |
* must be disabled. |
*/ |
static void _tdebug_send_msg(task_t *ta, unative_t method, unative_t a1, unative_t a2, |
unative_t a3, unative_t a4, unative_t a5) |
{ |
call_t *call; |
answerbox_t *answerbox; |
/* prepare an IPC notification structure */ |
call = ipc_call_alloc(FRAME_ATOMIC); |
if (!call) { |
return; |
} |
call->flags |= IPC_CALL_NOTIF; |
IPC_SET_METHOD(call->data, method); |
IPC_SET_ARG1(call->data, a1); |
IPC_SET_ARG2(call->data, a2); |
IPC_SET_ARG3(call->data, a3); |
IPC_SET_ARG4(call->data, a4); |
IPC_SET_ARG5(call->data, a5); |
answerbox = &ta->answerbox; |
/* analogy of send_call() from irq.c */ |
spinlock_lock(&answerbox->irq_lock); |
list_append(&call->link, &answerbox->irq_notifs); |
spinlock_unlock(&answerbox->irq_lock); |
waitq_wakeup(&answerbox->wq, WAKEUP_FIRST); |
} |
/** |
* Start debugging a task. |
* |
* The specified task (target) is attached to the current task (monitor). |
* The monitoring task will be informed of debug events in the |
* target task through IPC notifications with the specified method number. |
*/ |
int tdebug_attach_task(task_id_t taskid, unative_t method) |
{ |
task_t *ta; |
ipl_t ipl; |
DEADLOCK_PROBE_INIT(p_target_lock); |
//FIXME: pokud bychom si podrzeli tasks_lock, nemusime pokazde |
// znovu hledat ta podle id |
loop: |
ipl = interrupts_disable(); |
spinlock_lock(&tasks_lock); |
spinlock_lock(&TASK->lock); |
ta = task_find_by_id(taskid); |
if (!ta) { |
spinlock_unlock(&tasks_lock); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
klog_printf("fail: no such task\n"); |
return ENOENT; |
} |
if (!spinlock_trylock(&ta->lock)) { |
/* |
* Avoid deadlock by trying again. |
*/ |
spinlock_unlock(&TASK->lock); |
spinlock_unlock(&tasks_lock); |
interrupts_restore(ipl); |
DEADLOCK_PROBE(p_target_lock, DEADLOCK_THRESHOLD); |
goto loop; |
} |
/* we don't need tasks_lock anymore */ |
spinlock_unlock(&tasks_lock); |
if (ta->tdebug.monitor != NULL) { |
spinlock_unlock(&TASK->lock); |
spinlock_unlock(&ta->lock); |
interrupts_restore(ipl); |
klog_printf("fail: already being debugged\n"); |
return EBUSY; /* task already being debugged */ |
} |
atomic_set(&ta->tdebug.have_monitor, 1); |
ta->tdebug.monitor = TASK; |
ta->tdebug.method = method; |
/* insert ta into this task's debug-target list */ |
list_append(&ta->tdebug.targets_link, &TASK->tdebug.targets); |
spinlock_unlock(&TASK->lock); |
spinlock_unlock(&ta->lock); |
interrupts_restore(ipl); |
return 0; |
} |
/** |
* Stop debugging a task. |
*/ |
int tdebug_detach_task(task_id_t taskid) |
{ |
task_t *ta; |
ipl_t ipl; |
DEADLOCK_PROBE_INIT(p_target_lock); |
//FIXME: pokud bychom si podrzeli tasks_lock, nemusime pokazde |
// znovu hledat ta podle id |
loop: |
ipl = interrupts_disable(); |
spinlock_lock(&tasks_lock); |
spinlock_lock(&TASK->lock); |
ta = task_find_by_id(taskid); |
if (!ta) { |
spinlock_unlock(&tasks_lock); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
klog_printf("fail: no such task\n"); |
return ENOENT; |
} |
if (!spinlock_trylock(&ta->lock)) { |
/* |
* Avoid deadlock by trying again. |
*/ |
spinlock_unlock(&TASK->lock); |
spinlock_unlock(&tasks_lock); |
interrupts_restore(ipl); |
DEADLOCK_PROBE(p_target_lock, DEADLOCK_THRESHOLD); |
goto loop; |
} |
/* we don't need tasks_lock anymore */ |
spinlock_unlock(&tasks_lock); |
if (ta->tdebug.monitor == NULL) { |
spinlock_unlock(&TASK->lock); |
spinlock_unlock(&ta->lock); |
interrupts_restore(ipl); |
klog_printf("fail: not being debugged\n"); |
return EINVAL; /* task not being debugged */ |
} |
atomic_set(&ta->tdebug.have_monitor, 0); |
ta->tdebug.monitor = NULL; |
ta->tdebug.method = 0; |
/* remove target from this task's list */ |
list_remove(&ta->tdebug.targets_link); |
spinlock_unlock(&TASK->lock); |
spinlock_unlock(&ta->lock); |
interrupts_restore(ipl); |
return 0; |
} |
/** |
* Resume a thread stopped in a debugging event. |
*/ |
int tdebug_continue_thread(thread_id_t tid) |
{ |
thread_t *t; |
ipl_t ipl; |
klog_printf("sys_tdebug_continue_thread(%lld)", tid); |
//FIXME: need to verify that we are the monitor |
ipl = interrupts_disable(); |
spinlock_lock(&threads_lock); |
t = thread_find_by_id(tid); |
if (t == NULL) { |
spinlock_unlock(&threads_lock); |
interrupts_restore(ipl); |
klog_printf("fail: no such thread\n"); |
return ENOENT; |
} |
/* lock the thread */ |
spinlock_lock(&t->lock); |
/* verify that the thread is stopped */ |
if (t->tdebug.stopped == 0) { |
spinlock_unlock(&t->lock); |
interrupts_restore(ipl); |
return EINVAL; |
} |
t->tdebug.stopped = 0; |
/* no thread should be unlocked when calling waitq_wakeup */ |
spinlock_unlock(&t->lock); |
/* "spincv_signal()" */ |
waitq_wakeup(&t->tdebug.stopped_cv.wq, WAKEUP_FIRST); |
spinlock_unlock(&threads_lock); |
interrupts_restore(ipl); |
klog_printf("success\n"); |
return 0; |
} |
/** |
* Retrieve the arguments of a syscall. |
* |
* When a thread is stopped in a TDEBUG_EV_SYSCALL event, |
* this function may be used to retrieve the arguments of the |
* corresponding syscall. |
*/ |
int tdebug_get_syscall_args(thread_id_t tid, unative_t *sc_args) |
{ |
thread_t *t; |
ipl_t ipl; |
//FIXME: need to verify that we are the monitor |
ipl = interrupts_disable(); |
spinlock_lock(&threads_lock); |
t = thread_find_by_id(tid); |
if (t == NULL) { |
spinlock_unlock(&threads_lock); |
interrupts_restore(ipl); |
klog_printf("fail: no such thread\n"); |
return ENOENT; |
} |
/* keep a lock on the thread */ |
spinlock_lock(&t->lock); |
spinlock_unlock(&threads_lock); |
/* verify that the thread is stopped in a syscall event*/ |
if (t->tdebug.stopped == 0 || |
t->tdebug.current_event != TDEBUG_EV_SYSCALL) { |
spinlock_unlock(&t->lock); |
interrupts_restore(ipl); |
return EINVAL; |
} |
/* copy syscall arguments */ |
sc_args[0] = t->tdebug.syscall_args[0]; |
sc_args[1] = t->tdebug.syscall_args[1]; |
sc_args[2] = t->tdebug.syscall_args[2]; |
sc_args[3] = t->tdebug.syscall_args[3]; |
sc_args[4] = t->tdebug.syscall_args[4]; |
sc_args[5] = t->tdebug.syscall_args[5]; |
spinlock_unlock(&t->lock); |
interrupts_restore(ipl); |
return 0; |
} |
/** |
* Select which debug events will be generated. |
*/ |
int tdebug_set_event_mask(thread_id_t tid, unative_t ev_mask) |
{ |
thread_t *t; |
ipl_t ipl; |
int rc; |
//FIXME: need to verify that we are the monitor |
ipl = interrupts_disable(); |
spinlock_lock(&threads_lock); |
t = thread_find_by_id(tid); |
if (t == NULL) { |
spinlock_unlock(&threads_lock); |
interrupts_restore(ipl); |
klog_printf("fail: no such thread\n"); |
return ENOENT; |
} |
/* keep a lock on the thread */ |
spinlock_lock(&t->lock); |
spinlock_unlock(&threads_lock); |
/* verify that the thread is stopped */ |
if (t->tdebug.stopped == 0) { |
spinlock_unlock(&t->lock); |
interrupts_restore(ipl); |
klog_printf("fail: thread not stopped\n"); |
return EINVAL; |
} |
t->tdebug.event_mask = ev_mask; |
/* arch-specific update for IAFTER setting */ |
//disable this as it would break compile for all archs except ia32 |
//rc = tdebug_iafter_update(t); |
rc = 0; |
spinlock_unlock(&t->lock); |
interrupts_restore(ipl); |
return rc; |
} |
/** |
* Ask a thread to stop (without waiting for it to happen). |
*/ |
int tdebug_stop_thread(thread_id_t tid) |
{ |
thread_t *t; |
ipl_t ipl; |
//FIXME: need to verify that we are the monitor |
ipl = interrupts_disable(); |
spinlock_lock(&threads_lock); |
t = thread_find_by_id(tid); |
if (t == NULL) { |
spinlock_unlock(&threads_lock); |
interrupts_restore(ipl); |
klog_printf("fail: no such thread\n"); |
return ENOENT; |
} |
/* keep a lock on the thread */ |
spinlock_lock(&t->lock); |
spinlock_unlock(&threads_lock); |
/* verify that the thread isn't stopped */ |
if (t->tdebug.stopped == 0) { |
spinlock_unlock(&t->lock); |
interrupts_restore(ipl); |
return EINVAL; |
} |
t->tdebug.stop_request = 1; |
spinlock_unlock(&t->lock); |
interrupts_restore(ipl); |
return 0; |
} |
/** |
* Ask all threads in a task to stop (without waiting for it to happen). |
*/ |
int tdebug_stop_task(task_id_t taskid) |
{ |
return 0; |
} |
/branches/tracing/kernel/Makefile |
---|
258,6 → 258,8 |
generic/src/printf/vsprintf.c \ |
generic/src/printf/vsnprintf.c \ |
generic/src/debug/symtab.c \ |
generic/src/tdebug/tdebug.c \ |
generic/src/tdebug/systdebug.c \ |
generic/src/time/clock.c \ |
generic/src/time/timeout.c \ |
generic/src/time/delay.c \ |
/branches/tracing/kernel/arch/ia32/include/tdebug.h |
---|
0,0 → 1,15 |
/** @addtogroup ia32 |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_ia32_TDEBUG_H_ |
#define KERN_ia32_TDEBUG_H_ |
extern int tdebug_iafter_update(struct thread *t); |
#endif |
/** @} |
*/ |
/branches/tracing/kernel/arch/ia32/Makefile.inc |
---|
151,4 → 151,5 |
arch/$(ARCH)/src/boot/boot.S \ |
arch/$(ARCH)/src/boot/memmap.c \ |
arch/$(ARCH)/src/fpu_context.c \ |
arch/$(ARCH)/src/debugger.c |
arch/$(ARCH)/src/debugger.c \ |
arch/$(ARCH)/src/tdebug.c |
/branches/tracing/kernel/arch/ia32/src/tdebug.c |
---|
0,0 → 1,51 |
/** @addtogroup ia32 |
* @{ |
*/ |
/** @file |
*/ |
#include <proc/thread.h> |
#include <console/klog.h> |
#include <arch/tdebug.h> |
/* trap flag */ |
#define EFLAGS_TF 0x100 |
/** |
* Called when the IAFTER event setting is (potentially) changed. |
* |
* On this arch the TRAP flag in userspace state is set |
* according to the setting of TDEBUG_EVMASK_IAFTER |
* in order to stop after the execution of each instruction. |
* |
* The calling thread must have already locked t. |
* |
* Returns 0 on success, non-zero on failure. (Mainly if IAFTER is set, but |
* architecture does not support it.) |
*/ |
int tdebug_iafter_update(thread_t *t) |
{ |
uint32_t eflags; |
if (t->tdebug.uspace_state == NULL) { |
/* userspace state is not available */ |
/* FIXME: this should not happen when properly imlemented */ |
klog_printf("fail: uspace_state not available\n"); |
return -1; |
} |
eflags = t->tdebug.uspace_state->eflags; |
if ((t->tdebug.event_mask & TDEBUG_EVMASK_IAFTER) != 0) { |
eflags = eflags | EFLAGS_TF; |
} else { |
eflags = eflags & ~EFLAGS_TF; |
} |
t->tdebug.uspace_state->eflags = eflags; |
return 0; |
} |
/** @} |
*/ |
/branches/tracing/uspace/app/tester/tester.c |
---|
57,6 → 57,7 |
#include "ipc/hangup.def" |
#include "devmap/devmap1.def" |
#include "vfs/vfs1.def" |
#include "tdebug/tdebug1.def" |
{NULL, NULL, NULL} |
}; |
79,9 → 80,10 |
static void run_safe_tests(void) |
{ |
test_t *test; |
int i = 0, n = 0; |
unsigned int i = 0; |
unsigned int n = 0; |
printf("\n*** Running all safe tests\n\n"); |
printf("\n*** Running all safe tests ***\n\n"); |
for (test = tests; test->name != NULL; test++) { |
if (test->safe) { |
92,7 → 94,7 |
} |
} |
printf("\nSafe tests completed, %d tests run, %d passed.\n\n", i + n, i); |
printf("\nSafe tests completed, %u tests run, %u passed.\n\n", i + n, i); |
} |
static void list_tests(void) |
/branches/tracing/uspace/app/tester/tdebug/tdebug1.def |
---|
0,0 → 1,6 |
{ |
"tdebug1", |
"Tdebug interface test", |
&test_tdebug1, |
true |
}, |
/branches/tracing/uspace/app/tester/tdebug/tdebug1.c |
---|
0,0 → 1,147 |
#include <stdio.h> |
#include <unistd.h> |
#include <task.h> |
#include <tdebug.h> |
#include <async.h> |
#include <sys/types.h> |
#include <time.h> |
#include "../tester.h" |
static char *syscall_name[] = { |
"sys_io", |
"sys_tls_set", |
"sys_thread_create", |
"sys_thread_exit", |
"sys_thread_get_id", |
"sys_task_get_id", |
"sys_futex_sleep_timeout", |
"sys_futex_wakeup", |
"sys_as_area_create", |
"sys_as_area_resize", |
"sys_as_area_destroy", |
"sys_ipc_call_sync_fast", |
"sys_ipc_call_sync_slow", |
"sys_ipc_call_async_fast", |
"sys_ipc_call_async_slow", |
"sys_ipc_answer_fast", |
"sys_ipc_answer_slow", |
"sys_ipc_forward_fast", |
"sys_ipc_wait_for_call", |
"sys_ipc_hangup", |
"sys_ipc_register_irq", |
"sys_ipc_unregister_irq", |
"sys_cap_grant", |
"sys_cap_revoke", |
"sys_physmem_map", |
"sys_iospace_enable", |
"sys_preempt_control", |
"sys_sysinfo_valid", |
"sys_sysinfo_value", |
"sys_debug_enable_console", |
"sys_tdebug_attach_task", |
"sys_tdebug_continue_thread", |
"sys_tdebug_get_syscall_args" |
"sys_tdebug_set_event_mask", |
"sys_tdebug_stop_thread", |
"sys_tdebug_stop_task" |
}; |
static void event_syscall(thread_id_t tid, sysarg_t syscall_id, sysarg_t rc) |
{ |
sysarg_t sc_args[6]; |
size_t buf_len; |
int res; |
buf_len = 6; |
res = tdebug_get_syscall_args(tid, sc_args, &buf_len); |
if (res != 0) { |
printf("tdebug_get_syscall_args() -> %d\n", res); |
} |
printf("%s(", syscall_name[syscall_id]); |
switch (syscall_id) { |
case SYS_TLS_SET: printf("0x%08x", sc_args[0]); break; |
case SYS_IPC_WAIT: printf("0x%08x, %u, %d", sc_args[0], sc_args[1], sc_args[2]); break; |
default: |
printf("%u, %u, %u, %u, %u, %u", |
sc_args[0], sc_args[1], sc_args[2], |
sc_args[3], sc_args[4], sc_args[5]); |
break; |
} |
printf(") -> %d\n", rc); |
} |
static void event_exception(sysarg_t exc_no) |
{ |
printf("exception %u\n", exc_no); |
} |
static void notif_handler(ipc_callid_t iid, ipc_call_t *call) |
{ |
thread_id_t tid; |
sysarg_t method; |
sysarg_t tid_lo, tid_hi, ev_type, syscall_id, rc; |
sysarg_t exc_no; |
int res; |
(void)iid; |
method = IPC_GET_METHOD(*call); |
tid_lo = IPC_GET_ARG1(*call); |
tid_hi = IPC_GET_ARG2(*call); |
ev_type = IPC_GET_ARG3(*call); |
tid = (thread_id_t)tid_lo | ((thread_id_t)tid_hi << 32); |
switch (ev_type) { |
case TDEBUG_EV_SYSCALL: |
syscall_id = IPC_GET_ARG4(*call); |
rc = IPC_GET_ARG5(*call); |
event_syscall(tid, syscall_id, rc); |
break; |
case TDEBUG_EV_EXCEPTION: |
exc_no = IPC_GET_ARG4(*call); |
event_exception(exc_no); |
break; |
default: |
printf("unknown tdebug event notification %u\n", ev_type); |
break; |
} |
res = tdebug_continue_thread(tid); |
if (res != 0) { |
printf("tdebug_continue_thread() -> %d\n", res); |
} |
} |
char *test_tdebug1(bool quiet) |
{ |
task_id_t taskid; |
int result; |
async_set_interrupt_received(notif_handler); |
printf("test_tdebug1()\n"); |
taskid = 12; |
// tid = task_get_id(); |
// printf("this task id is %d\n", tid); |
printf("attaching...\n"); |
result = tdebug_attach_task(taskid, 368); |
printf("result is %d\n", result); |
getchar(); |
/* printf("setting event mask...\n"); |
result = tdebug_set_event_mask(taskid, TDEBUG_EVMASK_IAFTER); |
printf("result is %d\n", result); |
getchar(); |
*/ |
printf("detaching...\n"); |
result = tdebug_detach_task(taskid); |
printf("result is %d\n", result); |
return NULL; |
} |
/branches/tracing/uspace/app/tester/ipc/hangup.c |
---|
37,10 → 37,10 |
int res; |
int phoneid; |
printf("Select phoneid to hangup: 2-9 (Q to skip)\n"); |
printf("Select phoneid to hangup: 2-9 (q to skip)\n"); |
do { |
c = getchar(); |
if (c == 'Q' || c == 'q') |
if ((c == 'Q') || (c == 'q')) |
return TEST_SKIPPED; |
} while (c < '2' || c > '9'); |
phoneid = c - '0'; |
/branches/tracing/uspace/app/tester/ipc/send_sync.c |
---|
38,10 → 38,10 |
static int msgid = 1; |
char c; |
printf("Select phoneid to send msg: 2-9 (Q to skip)\n"); |
printf("Select phoneid to send msg: 2-9 (q to skip)\n"); |
do { |
c = getchar(); |
if (c == 'Q' || c == 'q') |
if ((c == 'Q') || (c == 'q')) |
return TEST_SKIPPED; |
} while (c < '2' || c > '9'); |
phoneid = c - '0'; |
/branches/tracing/uspace/app/tester/ipc/send_async.c |
---|
41,10 → 41,10 |
static int msgid = 1; |
char c; |
printf("Select phoneid to send msg: 2-9 (Q to skip)\n"); |
printf("Select phoneid to send msg: 2-9 (q to skip)\n"); |
do { |
c = getchar(); |
if (c == 'Q' || c == 'q') |
if ((c == 'Q') || (c == 'q')) |
return TEST_SKIPPED; |
} while (c < '2' || c > '9'); |
phoneid = c - '0'; |
/branches/tracing/uspace/app/tester/ipc/connect.c |
---|
36,10 → 36,10 |
int svc; |
int phid; |
printf("Choose one service: 0:10000....9:10009 (Q to skip)\n"); |
printf("Choose one service: 0:10000....9:10009 (q to skip)\n"); |
do { |
c = getchar(); |
if (c == 'Q' || c == 'q') |
if ((c == 'Q') || (c == 'q')) |
return TEST_SKIPPED; |
} while (c < '0' || c > '9'); |
/branches/tracing/uspace/app/tester/tester.h |
---|
70,6 → 70,7 |
extern char * test_hangup(bool quiet); |
extern char * test_devmap1(bool quiet); |
extern char * test_vfs1(bool quiet); |
extern char * test_tdebug1(bool quiet); |
extern test_t tests[]; |
/branches/tracing/uspace/app/tester/Makefile |
---|
53,7 → 53,8 |
ipc/answer.c \ |
ipc/hangup.c \ |
devmap/devmap1.c \ |
vfs/vfs1.c |
vfs/vfs1.c \ |
tdebug/tdebug1.c |
OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) |
/branches/tracing/uspace/app/tetris/tetris.c |
---|
222,6 → 222,7 |
break; |
case 'h': |
*(int *)0 = 0; /* generate a page fault */ |
showscores(firstgame); |
tetris_menu_draw(*level); |
break; |
/branches/tracing/uspace/lib/libc/include/tdebug.h |
---|
0,0 → 1,55 |
/* |
* Copyright (c) 2006 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup libc |
* @{ |
*/ |
/** @file |
*/ |
#ifndef LIBC_TDEBUG_H_ |
#define LIBC_TDEBUG_H_ |
#include <task.h> |
#include <thread.h> |
#include <ipc/ipc.h> |
#include <kernel/tdebug/tdebug_type.h> |
int tdebug_attach_task(task_id_t id, ipcarg_t method); |
int tdebug_detach_task(task_id_t id); |
int tdebug_continue_thread(thread_id_t id); |
int tdebug_get_syscall_args(thread_id_t id, sysarg_t *buffer, size_t *len); |
int tdebug_set_event_mask(thread_id_t id, unsigned ev_mask); |
int tdebug_stop_thread(thread_id_t id); |
int tdebug_stop_task(task_id_t id); |
#endif |
/** @} |
*/ |
/branches/tracing/uspace/lib/libc/generic/tdebug.c |
---|
0,0 → 1,118 |
/* |
* Copyright (c) 2006 Jakub Jermar |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* |
* - Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* - Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* - The name of the author may not be used to endorse or promote products |
* derived from this software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
/** @addtogroup libc |
* @{ |
*/ |
/** @file |
*/ |
#include <tdebug.h> |
#include <task.h> |
#include <thread.h> |
#include <ipc/ipc.h> |
#include <libc.h> |
#include <kernel/syscall/sysarg64.h> |
int tdebug_attach_task(task_id_t id, ipcarg_t method) |
{ |
sysarg64_t arg; |
arg.value = (unsigned long long) id; |
return __SYSCALL2(SYS_TDEBUG_ATTACH_TASK, (sysarg_t) &arg, |
(sysarg_t) method); |
} |
int tdebug_detach_task(task_id_t id) |
{ |
sysarg64_t arg; |
arg.value = (unsigned long long) id; |
return __SYSCALL1(SYS_TDEBUG_DETACH_TASK, (sysarg_t) &arg); |
} |
int tdebug_continue_thread(thread_id_t id) |
{ |
sysarg64_t arg; |
arg.value = (unsigned long long) id; |
return __SYSCALL1(SYS_TDEBUG_CONTINUE_THREAD, (sysarg_t) &arg); |
} |
int tdebug_get_syscall_args(thread_id_t id, sysarg_t *buffer, size_t *len) |
{ |
sysarg64_t sa_id; |
sysarg_t sa_len; |
int rc; |
sa_id.value = (unsigned long long) id; |
sa_len = *len; |
rc = __SYSCALL3(SYS_TDEBUG_GET_SYSCALL_ARGS, (sysarg_t) &sa_id, |
(sysarg_t) buffer, (sysarg_t) &sa_len); |
*len = sa_len; |
return rc; |
} |
int tdebug_set_event_mask(task_id_t id, unsigned ev_mask) |
{ |
sysarg64_t arg; |
arg.value = (unsigned long long) id; |
return __SYSCALL2(SYS_TDEBUG_SET_EVENT_MASK, (sysarg_t) &arg, |
(sysarg_t) ev_mask); |
} |
int tdebug_stop_thread(thread_id_t id) |
{ |
sysarg64_t arg; |
arg.value = (unsigned long long) id; |
return __SYSCALL1(SYS_TDEBUG_STOP_THREAD, (sysarg_t) &arg); |
} |
int tdebug_stop_task(task_id_t id) |
{ |
sysarg64_t arg; |
arg.value = (unsigned long long) id; |
return __SYSCALL1(SYS_TDEBUG_STOP_TASK, (sysarg_t) &arg); |
} |
/** @} |
*/ |
/branches/tracing/uspace/lib/libc/Makefile |
---|
54,6 → 54,7 |
generic/thread.c \ |
generic/tls.c \ |
generic/task.c \ |
generic/tdebug.c \ |
generic/futex.c \ |
generic/io/io.c \ |
generic/io/printf.c \ |