Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 2785 → Rev 2787

/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 \