/branches/dynload/kernel/kernel.config |
---|
144,6 → 144,8 |
# Virtually indexed D-cache support |
! [ARCH=sparc64] CONFIG_VIRT_IDX_DCACHE (y/n) |
# Support for userspace debuggers |
! CONFIG_UDEBUG (n/y) |
## Debugging configuration directives |
/branches/dynload/kernel/generic/include/proc/task.h |
---|
52,6 → 52,7 |
#include <arch/cpu.h> |
#include <mm/tlb.h> |
#include <proc/scheduler.h> |
#include <udebug/udebug.h> |
struct thread; |
93,6 → 94,20 |
* certain extent. |
*/ |
atomic_t active_calls; |
#ifdef CONFIG_UDEBUG |
/** Debugging stuff */ |
udebug_task_t udebug; |
/** Kernel answerbox */ |
answerbox_t kernel_box; |
/** Thread used to service kernel answerbox */ |
struct thread *kb_thread; |
/** Kbox thread creation vs. begin of cleanup mutual exclusion */ |
mutex_t kb_cleanup_lock; |
/** True if cleanup of kbox has already started */ |
bool kb_finished; |
#endif |
/** Architecture specific task data. */ |
task_arch_t arch; |
/branches/dynload/kernel/generic/include/proc/thread.h |
---|
46,6 → 46,7 |
#include <arch/cpu.h> |
#include <mm/tlb.h> |
#include <proc/uarg.h> |
#include <udebug/udebug.h> |
#define THREAD_STACK_SIZE STACK_SIZE |
#define THREAD_NAME_BUFLEN 20 |
203,6 → 204,12 |
/** Thread's kernel stack. */ |
uint8_t *kstack; |
#ifdef CONFIG_UDEBUG |
/** Debugging stuff */ |
udebug_thread_t udebug; |
#endif |
} thread_t; |
/** Thread list lock. |
/branches/dynload/kernel/generic/include/udebug/udebug.h |
---|
0,0 → 1,218 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 generic |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_UDEBUG_H_ |
#define KERN_UDEBUG_H_ |
#include <ipc/ipc.h> |
typedef enum { /* udebug_method_t */ |
/** Start debugging the recipient. |
* Causes all threads in the receiving task to stop. When they |
* are all stoped, an answer with retval 0 is generated. |
*/ |
UDEBUG_M_BEGIN = 1, |
/** Finish debugging the recipient. |
* Answers all pending GO and GUARD messages. |
*/ |
UDEBUG_M_END, |
/** Set which events should be captured. |
*/ |
UDEBUG_M_SET_EVMASK, |
/** Make sure the debugged task is still there. |
* This message is answered when the debugged task dies |
* or the debugging session ends. |
*/ |
UDEBUG_M_GUARD, |
/** Run a thread until a debugging event occurs. |
* This message is answered when the thread stops |
* in a debugging event. |
* |
* - ARG2 - id of the thread to run |
*/ |
UDEBUG_M_GO, |
/** Stop a thread being debugged. |
* Creates a special STOP event in the thread, causing |
* it to answer a pending GO message (if any). |
*/ |
UDEBUG_M_STOP, |
/** Read arguments of a syscall. |
* |
* - ARG2 - thread identification |
* - ARG3 - destination address in the caller's address space |
* |
*/ |
UDEBUG_M_ARGS_READ, |
/** Read the list of the debugged tasks's threads. |
* |
* - ARG2 - destination address in the caller's address space |
* - ARG3 - size of receiving buffer in bytes |
* |
* The kernel fills the buffer with a series of sysarg_t values |
* (thread ids). On answer, the kernel will set: |
* |
* - ARG2 - number of bytes that were actually copied |
* - ARG3 - number of bytes of the complete data |
* |
*/ |
UDEBUG_M_THREAD_READ, |
/** Read the debugged tasks's memory. |
* |
* - ARG2 - destination address in the caller's address space |
* - ARG3 - source address in the recipient's address space |
* - ARG4 - size of receiving buffer in bytes |
* |
*/ |
UDEBUG_M_MEM_READ, |
} udebug_method_t; |
typedef enum { |
UDEBUG_EVENT_FINISHED = 1, /**< Debuging session has finished */ |
UDEBUG_EVENT_STOP, /**< Stopped on DEBUG_STOP request */ |
UDEBUG_EVENT_SYSCALL_B, /**< Before beginning syscall execution */ |
UDEBUG_EVENT_SYSCALL_E, /**< After finishing syscall execution */ |
UDEBUG_EVENT_THREAD_B, /**< The task created a new thread */ |
UDEBUG_EVENT_THREAD_E /**< A thread exited */ |
} udebug_event_t; |
#define UDEBUG_EVMASK(event) (1 << ((event) - 1)) |
typedef enum { |
UDEBUG_EM_FINISHED = UDEBUG_EVMASK(UDEBUG_EVENT_FINISHED), |
UDEBUG_EM_STOP = UDEBUG_EVMASK(UDEBUG_EVENT_STOP), |
UDEBUG_EM_SYSCALL_B = UDEBUG_EVMASK(UDEBUG_EVENT_SYSCALL_B), |
UDEBUG_EM_SYSCALL_E = UDEBUG_EVMASK(UDEBUG_EVENT_SYSCALL_E), |
UDEBUG_EM_THREAD_B = UDEBUG_EVMASK(UDEBUG_EVENT_THREAD_B), |
UDEBUG_EM_THREAD_E = UDEBUG_EVMASK(UDEBUG_EVENT_THREAD_E), |
UDEBUG_EM_ALL = |
UDEBUG_EVMASK(UDEBUG_EVENT_FINISHED) | |
UDEBUG_EVMASK(UDEBUG_EVENT_STOP) | |
UDEBUG_EVMASK(UDEBUG_EVENT_SYSCALL_B) | |
UDEBUG_EVMASK(UDEBUG_EVENT_SYSCALL_E) | |
UDEBUG_EVMASK(UDEBUG_EVENT_THREAD_B) | |
UDEBUG_EVMASK(UDEBUG_EVENT_THREAD_E) |
} udebug_evmask_t; |
#ifdef KERNEL |
#include <synch/mutex.h> |
#include <arch/interrupt.h> |
#include <atomic.h> |
typedef enum { |
/** Task is not being debugged */ |
UDEBUG_TS_INACTIVE, |
/** BEGIN operation in progress (waiting for threads to stop) */ |
UDEBUG_TS_BEGINNING, |
/** Debugger fully connected */ |
UDEBUG_TS_ACTIVE, |
/** Task is shutting down, no more debug activities allowed */ |
UDEBUG_TS_SHUTDOWN |
} udebug_task_state_t; |
/** Debugging part of task_t structure. |
*/ |
typedef struct { |
/** Synchronize debug ops on this task / access to this structure */ |
mutex_t lock; |
char *lock_owner; |
udebug_task_state_t dt_state; |
call_t *begin_call; |
int not_stoppable_count; |
struct task *debugger; |
udebug_evmask_t evmask; |
} udebug_task_t; |
/** Debugging part of thread_t structure. |
*/ |
typedef struct { |
/** |
* Prevent deadlock with udebug_before_thread_runs() in interrupt |
* handler, without actually disabling interrupts. |
* ==0 means "unlocked", >0 means "locked" |
*/ |
atomic_t int_lock; |
/** Synchronize debug ops on this thread / access to this structure */ |
mutex_t lock; |
waitq_t go_wq; |
call_t *go_call; |
unative_t syscall_args[6]; |
/** What type of event are we stopped in or 0 if none */ |
udebug_event_t cur_event; |
bool stop; |
bool stoppable; |
bool debug_active; /**< In a debugging session */ |
} udebug_thread_t; |
struct task; |
struct thread; |
void udebug_task_init(udebug_task_t *ut); |
void udebug_thread_initialize(udebug_thread_t *ut); |
void udebug_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, |
bool end_variant); |
void udebug_thread_b_event(struct thread *t); |
void udebug_thread_e_event(void); |
void udebug_stoppable_begin(void); |
void udebug_stoppable_end(void); |
void udebug_before_thread_runs(void); |
int udebug_task_cleanup(struct task *ta); |
#endif |
#endif |
/** @} |
*/ |
/branches/dynload/kernel/generic/include/udebug/udebug_ops.h |
---|
0,0 → 1,55 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 generic |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_UDEBUG_OPS_H_ |
#define KERN_UDEBUG_OPS_H_ |
#include <ipc/ipc.h> |
int udebug_begin(call_t *call); |
int udebug_end(void); |
int udebug_set_evmask(udebug_evmask_t mask); |
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); |
int udebug_mem_read(unative_t uspace_addr, size_t n, void **buffer); |
#endif |
/** @} |
*/ |
/branches/dynload/kernel/generic/include/udebug/udebug_ipc.h |
---|
0,0 → 1,47 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 generic |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_UDEBUG_IPC_H_ |
#define KERN_UDEBUG_IPC_H_ |
#include <ipc/ipc.h> |
int udebug_request_preprocess(call_t *call, phone_t *phone); |
void udebug_call_receive(call_t *call); |
#endif |
/** @} |
*/ |
/branches/dynload/kernel/generic/include/syscall/syscall.h |
---|
79,7 → 79,7 |
SYS_DEBUG_PUTINT, |
SYS_DEBUG_ENABLE_CONSOLE, |
SYS_IPC_CONNECT_KBOX, |
SYSCALL_END |
} syscall_t; |
/branches/dynload/kernel/generic/include/ipc/sysipc.h |
---|
57,6 → 57,7 |
unative_t sys_ipc_register_irq(inr_t inr, devno_t devno, unative_t method, |
irq_code_t *ucode); |
unative_t sys_ipc_unregister_irq(inr_t inr, devno_t devno); |
unative_t sys_ipc_connect_kbox(sysarg64_t *task_id); |
#endif |
/branches/dynload/kernel/generic/include/ipc/ipc.h |
---|
195,6 → 195,12 |
*/ |
#define IPC_M_DATA_READ 7 |
/** Debug the recipient. |
* - ARG1 - specifies the debug method (from udebug_method_t) |
* - other arguments are specific to the debug method |
*/ |
#define IPC_M_DEBUG_ALL 8 |
/* Well-known methods */ |
#define IPC_M_LAST_SYSTEM 511 |
#define IPC_M_PING 512 |
307,6 → 313,8 |
extern int ipc_phone_hangup(phone_t *); |
extern void ipc_backsend_err(phone_t *, call_t *, unative_t); |
extern void ipc_print_task(task_id_t); |
extern void ipc_answerbox_slam_phones(answerbox_t *, bool); |
extern void ipc_cleanup_call_list(link_t *); |
extern answerbox_t *ipc_phone_0; |
/branches/dynload/kernel/generic/include/ipc/kbox.h |
---|
0,0 → 1,46 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 genericipc |
* @{ |
*/ |
/** @file |
*/ |
#ifndef KERN_IPC_KBOX_H_ |
#define KERN_IPC_KBOX_H_ |
#include <typedefs.h> |
extern int ipc_connect_kbox(task_id_t); |
extern void ipc_kbox_cleanup(void); |
#endif |
/** @} |
*/ |
/branches/dynload/kernel/generic/src/main/uinit.c |
---|
46,7 → 46,9 |
#include <userspace.h> |
#include <mm/slab.h> |
#include <arch.h> |
#include <udebug/udebug.h> |
/** Thread used to bring up userspace thread. |
* |
* @param arg Pointer to structure containing userspace entry and stack |
65,6 → 67,10 |
* deployed for the event of forceful task termination. |
*/ |
thread_detach(THREAD); |
#ifdef CONFIG_UDEBUG |
udebug_stoppable_end(); |
#endif |
uarg.uspace_entry = ((uspace_arg_t *) arg)->uspace_entry; |
uarg.uspace_stack = ((uspace_arg_t *) arg)->uspace_stack; |
/branches/dynload/kernel/generic/src/proc/task.c |
---|
155,7 → 155,18 |
ta->capabilities = 0; |
ta->cycles = 0; |
#ifdef CONFIG_UDEBUG |
/* Init debugging stuff */ |
udebug_task_init(&ta->udebug); |
/* Init kbox stuff */ |
ipc_answerbox_init(&ta->kernel_box, ta); |
ta->kb_thread = NULL; |
mutex_initialize(&ta->kb_cleanup_lock, MUTEX_PASSIVE); |
ta->kb_finished = false; |
#endif |
ipc_answerbox_init(&ta->answerbox, ta); |
for (i = 0; i < IPC_MAX_PHONES; i++) |
ipc_phone_init(&ta->phones[i]); |
/branches/dynload/kernel/generic/src/proc/thread.c |
---|
180,6 → 180,10 |
return -1; |
} |
#ifdef CONFIG_UDEBUG |
mutex_initialize(&t->udebug.lock, MUTEX_PASSIVE); |
#endif |
return 0; |
} |
347,6 → 351,11 |
avltree_node_initialize(&t->threads_tree_node); |
t->threads_tree_node.key = (uintptr_t) t; |
#ifdef CONFIG_UDEBUG |
/* Init debugging stuff */ |
udebug_thread_initialize(&t->udebug); |
#endif |
/* might depend on previous initialization */ |
thread_create_arch(t); |
409,12 → 418,17 |
ipl_t ipl; |
/* |
* Attach to the current task. |
* Attach to the specified task. |
*/ |
ipl = interrupts_disable(); |
spinlock_lock(&task->lock); |
atomic_inc(&task->refcount); |
atomic_inc(&task->lifecount); |
/* Must not count kbox thread into lifecount */ |
if (t->flags & THREAD_FLAG_USPACE) |
atomic_inc(&task->lifecount); |
list_append(&t->th_link, &task->th_head); |
spinlock_unlock(&task->lock); |
437,14 → 451,19 |
{ |
ipl_t ipl; |
if (atomic_predec(&TASK->lifecount) == 0) { |
/* |
* We are the last thread in the task that still has not exited. |
* With the exception of the moment the task was created, new |
* threads can only be created by threads of the same task. |
* We are safe to perform cleanup. |
*/ |
if (THREAD->flags & THREAD_FLAG_USPACE) { |
if (THREAD->flags & THREAD_FLAG_USPACE) { |
#ifdef CONFIG_UDEBUG |
/* Generate udebug THREAD_E event */ |
udebug_thread_e_event(); |
#endif |
if (atomic_predec(&TASK->lifecount) == 0) { |
/* |
* We are the last userspace thread in the task that |
* still has not exited. With the exception of the |
* moment the task was created, new userspace threads |
* can only be created by threads of the same task. |
* We are safe to perform cleanup. |
*/ |
ipc_cleanup(); |
futex_cleanup(); |
LOG("Cleanup of task %" PRIu64" completed.", TASK->taskid); |
741,6 → 760,11 |
thread_attach(t, TASK); |
thread_ready(t); |
#ifdef CONFIG_UDEBUG |
/* Generate udebug THREAD_B event */ |
udebug_thread_b_event(t); |
#endif |
return 0; |
} else |
free(kernel_uarg); |
/branches/dynload/kernel/generic/src/mm/as.c |
---|
385,7 → 385,7 |
if (pages < area->pages) { |
bool cond; |
uintptr_t start_free = area->base + pages*PAGE_SIZE; |
uintptr_t start_free = area->base + pages * PAGE_SIZE; |
/* |
* Shrinking the area. |
395,7 → 395,7 |
/* |
* Start TLB shootdown sequence. |
*/ |
tlb_shootdown_start(TLB_INVL_PAGES, AS->asid, area->base + |
tlb_shootdown_start(TLB_INVL_PAGES, as->asid, area->base + |
pages * PAGE_SIZE, area->pages - pages); |
/* |
/branches/dynload/kernel/generic/src/syscall/syscall.c |
---|
53,6 → 53,7 |
#include <syscall/copy.h> |
#include <sysinfo/sysinfo.h> |
#include <console/console.h> |
#include <udebug/udebug.h> |
/** Print using kernel facility |
* |
108,9 → 109,16 |
{ |
unative_t rc; |
if (id < SYSCALL_END) |
#ifdef CONFIG_UDEBUG |
udebug_syscall_event(a1, a2, a3, a4, a5, a6, id, 0, false); |
#endif |
if (id < SYSCALL_END) { |
#ifdef CONFIG_UDEBUG |
udebug_stoppable_begin(); |
#endif |
rc = syscall_table[id](a1, a2, a3, a4, a5, a6); |
else { |
} else { |
printf("Task %" PRIu64": Unknown syscall %#" PRIxn, TASK->taskid, id); |
task_kill(TASK->taskid); |
thread_exit(); |
118,6 → 126,11 |
if (THREAD->interrupted) |
thread_exit(); |
#ifdef CONFIG_UDEBUG |
udebug_syscall_event(a1, a2, a3, a4, a5, a6, id, rc, true); |
udebug_stoppable_end(); |
#endif |
return rc; |
} |
173,7 → 186,9 |
/* Debug calls */ |
(syshandler_t) sys_debug_putint, |
(syshandler_t) sys_debug_enable_console |
(syshandler_t) sys_debug_enable_console, |
(syshandler_t) sys_ipc_connect_kbox |
}; |
/** @} |
/branches/dynload/kernel/generic/src/ipc/kbox.c |
---|
0,0 → 1,220 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 genericipc |
* @{ |
*/ |
/** @file |
*/ |
#include <synch/synch.h> |
#include <synch/spinlock.h> |
#include <synch/mutex.h> |
#include <ipc/ipc.h> |
#include <ipc/ipcrsc.h> |
#include <arch.h> |
#include <errno.h> |
#include <debug.h> |
#include <udebug/udebug_ipc.h> |
#include <ipc/kbox.h> |
void ipc_kbox_cleanup(void) |
{ |
bool have_kb_thread; |
/* Only hold kb_cleanup_lock while setting kb_finished - this is enough */ |
mutex_lock(&TASK->kb_cleanup_lock); |
TASK->kb_finished = true; |
mutex_unlock(&TASK->kb_cleanup_lock); |
have_kb_thread = (TASK->kb_thread != NULL); |
/* From now on nobody will try to connect phones or attach kbox threads */ |
/* |
* Disconnect all phones connected to our kbox. Passing true for |
* notify_box causes a HANGUP message to be inserted for each |
* disconnected phone. This ensures the kbox thread is going to |
* wake up and terminate. |
*/ |
ipc_answerbox_slam_phones(&TASK->kernel_box, have_kb_thread); |
if (have_kb_thread) { |
LOG("join kb_thread..\n"); |
thread_join(TASK->kb_thread); |
thread_detach(TASK->kb_thread); |
LOG("join done\n"); |
TASK->kb_thread = NULL; |
} |
/* Answer all messages in 'calls' and 'dispatched_calls' queues */ |
spinlock_lock(&TASK->kernel_box.lock); |
ipc_cleanup_call_list(&TASK->kernel_box.dispatched_calls); |
ipc_cleanup_call_list(&TASK->kernel_box.calls); |
spinlock_unlock(&TASK->kernel_box.lock); |
} |
static void kbox_thread_proc(void *arg) |
{ |
call_t *call; |
int method; |
bool done; |
ipl_t ipl; |
(void)arg; |
LOG("kbox_thread_proc()\n"); |
done = false; |
while (!done) { |
call = ipc_wait_for_call(&TASK->kernel_box, SYNCH_NO_TIMEOUT, |
SYNCH_FLAGS_NONE); |
if (call != NULL) { |
method = IPC_GET_METHOD(call->data); |
if (method == IPC_M_DEBUG_ALL) { |
udebug_call_receive(call); |
} |
if (method == IPC_M_PHONE_HUNGUP) { |
LOG("kbox: handle hangup message\n"); |
/* Was it our debugger, who hung up? */ |
if (call->sender == TASK->udebug.debugger) { |
/* Terminate debugging session (if any) */ |
LOG("kbox: terminate debug session\n"); |
ipl = interrupts_disable(); |
spinlock_lock(&TASK->lock); |
udebug_task_cleanup(TASK); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
} else { |
LOG("kbox: was not debugger\n"); |
} |
LOG("kbox: continue with hangup message\n"); |
IPC_SET_RETVAL(call->data, 0); |
ipc_answer(&TASK->kernel_box, call); |
ipl = interrupts_disable(); |
spinlock_lock(&TASK->lock); |
spinlock_lock(&TASK->answerbox.lock); |
if (list_empty(&TASK->answerbox.connected_phones)) { |
/* Last phone has been disconnected */ |
TASK->kb_thread = NULL; |
done = true; |
LOG("phone list is empty\n"); |
} |
spinlock_unlock(&TASK->answerbox.lock); |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
} |
} |
} |
LOG("kbox: finished\n"); |
} |
/** |
* Connect phone to a task kernel-box specified by id. |
* |
* Note that this is not completely atomic. For optimisation reasons, |
* The task might start cleaning up kbox after the phone has been connected |
* and before a kbox thread has been created. This must be taken into account |
* in the cleanup code. |
* |
* @return Phone id on success, or negative error code. |
*/ |
int ipc_connect_kbox(task_id_t taskid) |
{ |
int newphid; |
task_t *ta; |
thread_t *kb_thread; |
ipl_t ipl; |
ipl = interrupts_disable(); |
spinlock_lock(&tasks_lock); |
ta = task_find_by_id(taskid); |
if (ta == NULL) { |
spinlock_unlock(&tasks_lock); |
interrupts_restore(ipl); |
return ENOENT; |
} |
atomic_inc(&ta->refcount); |
spinlock_unlock(&tasks_lock); |
interrupts_restore(ipl); |
mutex_lock(&ta->kb_cleanup_lock); |
if (atomic_predec(&ta->refcount) == 0) { |
mutex_unlock(&ta->kb_cleanup_lock); |
task_destroy(ta); |
return ENOENT; |
} |
if (ta->kb_finished != false) { |
mutex_unlock(&ta->kb_cleanup_lock); |
return EINVAL; |
} |
newphid = phone_alloc(); |
if (newphid < 0) { |
mutex_unlock(&ta->kb_cleanup_lock); |
return ELIMIT; |
} |
/* Connect the newly allocated phone to the kbox */ |
ipc_phone_connect(&TASK->phones[newphid], &ta->kernel_box); |
if (ta->kb_thread != NULL) { |
mutex_unlock(&ta->kb_cleanup_lock); |
return newphid; |
} |
/* Create a kbox thread */ |
kb_thread = thread_create(kbox_thread_proc, NULL, ta, 0, "kbox", false); |
if (!kb_thread) { |
mutex_unlock(&ta->kb_cleanup_lock); |
return ENOMEM; |
} |
ta->kb_thread = kb_thread; |
thread_ready(kb_thread); |
mutex_unlock(&ta->kb_cleanup_lock); |
return newphid; |
} |
/** @} |
*/ |
/branches/dynload/kernel/generic/src/ipc/sysipc.c |
---|
42,8 → 42,9 |
#include <ipc/sysipc.h> |
#include <ipc/irq.h> |
#include <ipc/ipcrsc.h> |
#include <ipc/kbox.h> |
#include <udebug/udebug_ipc.h> |
#include <arch/interrupt.h> |
#include <print.h> |
#include <syscall/copy.h> |
#include <security/cap.h> |
#include <mm/as.h> |
295,10 → 296,11 |
/** Called before the request is sent. |
* |
* @param call Call structure with the request. |
* @param phone Phone that the call will be sent through. |
* |
* @return Return 0 on success, ELIMIT or EPERM on error. |
*/ |
static int request_preprocess(call_t *call) |
static int request_preprocess(call_t *call, phone_t *phone) |
{ |
int newphid; |
size_t size; |
340,6 → 342,10 |
return rc; |
} |
break; |
#ifdef CONFIG_UDEBUG |
case IPC_M_DEBUG_ALL: |
return udebug_request_preprocess(call, phone); |
#endif |
default: |
break; |
} |
369,6 → 375,7 |
if (call->buffer) { |
/* This must be an affirmative answer to IPC_M_DATA_READ. */ |
/* or IPC_M_DEBUG_ALL/UDEBUG_M_MEM_READ... */ |
uintptr_t dst = IPC_GET_ARG1(call->data); |
size_t size = IPC_GET_ARG2(call->data); |
int rc = copy_to_uspace((void *) dst, call->buffer, size); |
399,7 → 406,13 |
return -1; |
} |
IPC_SET_ARG5(call->data, phoneid); |
} |
} |
switch (IPC_GET_METHOD(call->data)) { |
case IPC_M_DEBUG_ALL: |
return -1; |
default: |
break; |
} |
return 0; |
} |
441,7 → 454,7 |
IPC_SET_ARG4(call.data, 0); |
IPC_SET_ARG5(call.data, 0); |
if (!(res = request_preprocess(&call))) { |
if (!(res = request_preprocess(&call, phone))) { |
rc = ipc_call_sync(phone, &call); |
if (rc != EOK) |
return rc; |
481,7 → 494,7 |
GET_CHECK_PHONE(phone, phoneid, return ENOENT); |
if (!(res = request_preprocess(&call))) { |
if (!(res = request_preprocess(&call, phone))) { |
rc = ipc_call_sync(phone, &call); |
if (rc != EOK) |
return rc; |
550,7 → 563,7 |
*/ |
IPC_SET_ARG5(call->data, 0); |
if (!(res = request_preprocess(call))) |
if (!(res = request_preprocess(call, phone))) |
ipc_call(phone, call); |
else |
ipc_backsend_err(phone, call, res); |
584,7 → 597,7 |
ipc_call_free(call); |
return (unative_t) rc; |
} |
if (!(res = request_preprocess(call))) |
if (!(res = request_preprocess(call, phone))) |
ipc_call(phone, call); |
else |
ipc_backsend_err(phone, call, res); |
868,5 → 881,30 |
return 0; |
} |
#include <console/console.h> |
/** |
* Syscall connect to a task by id. |
* |
* @return Phone id on success, or negative error code. |
*/ |
unative_t sys_ipc_connect_kbox(sysarg64_t *uspace_taskid_arg) |
{ |
#ifdef CONFIG_UDEBUG |
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; |
LOG("sys_ipc_connect_kbox(%" PRIu64 ")\n", taskid_arg.value); |
return ipc_connect_kbox(taskid_arg.value); |
#else |
return (unative_t) ENOTSUP; |
#endif |
} |
/** @} |
*/ |
/branches/dynload/kernel/generic/src/ipc/ipc.c |
---|
43,6 → 43,7 |
#include <synch/waitq.h> |
#include <synch/synch.h> |
#include <ipc/ipc.h> |
#include <ipc/kbox.h> |
#include <errno.h> |
#include <mm/slab.h> |
#include <arch.h> |
51,6 → 52,7 |
#include <debug.h> |
#include <print.h> |
#include <console/console.h> |
#include <proc/thread.h> |
#include <arch/interrupt.h> |
#include <ipc/irq.h> |
427,7 → 429,7 |
* |
* @param lst Head of the list to be cleaned up. |
*/ |
static void ipc_cleanup_call_list(link_t *lst) |
void ipc_cleanup_call_list(link_t *lst) |
{ |
call_t *call; |
442,33 → 444,31 |
} |
} |
/** Cleans up all IPC communication of the current task. |
/** Disconnects all phones connected to an answerbox. |
* |
* Note: ipc_hangup sets returning answerbox to TASK->answerbox, you |
* have to change it as well if you want to cleanup other tasks than TASK. |
* @param box Answerbox to disconnect phones from. |
* @param notify_box If true, the answerbox will get a hangup message for |
* each disconnected phone. |
*/ |
void ipc_cleanup(void) |
void ipc_answerbox_slam_phones(answerbox_t *box, bool notify_box) |
{ |
int i; |
call_t *call; |
phone_t *phone; |
DEADLOCK_PROBE_INIT(p_phonelck); |
ipl_t ipl; |
call_t *call; |
/* Disconnect all our phones ('ipc_phone_hangup') */ |
for (i = 0; i < IPC_MAX_PHONES; i++) |
ipc_phone_hangup(&TASK->phones[i]); |
call = notify_box ? ipc_call_alloc(0) : NULL; |
/* Disconnect all connected irqs */ |
ipc_irq_cleanup(&TASK->answerbox); |
/* Disconnect all phones connected to our answerbox */ |
restart_phones: |
spinlock_lock(&TASK->answerbox.lock); |
while (!list_empty(&TASK->answerbox.connected_phones)) { |
phone = list_get_instance(TASK->answerbox.connected_phones.next, |
ipl = interrupts_disable(); |
spinlock_lock(&box->lock); |
while (!list_empty(&box->connected_phones)) { |
phone = list_get_instance(box->connected_phones.next, |
phone_t, link); |
if (SYNCH_FAILED(mutex_trylock(&phone->lock))) { |
spinlock_unlock(&TASK->answerbox.lock); |
spinlock_unlock(&box->lock); |
interrupts_restore(ipl); |
DEADLOCK_PROBE(p_phonelck, DEADLOCK_THRESHOLD); |
goto restart_phones; |
} |
475,13 → 475,69 |
/* Disconnect phone */ |
ASSERT(phone->state == IPC_PHONE_CONNECTED); |
list_remove(&phone->link); |
phone->state = IPC_PHONE_SLAMMED; |
list_remove(&phone->link); |
if (notify_box) { |
mutex_unlock(&phone->lock); |
spinlock_unlock(&box->lock); |
interrupts_restore(ipl); |
/* |
* Send one message to the answerbox for each |
* phone. Used to make sure the kbox thread |
* wakes up after the last phone has been |
* disconnected. |
*/ |
IPC_SET_METHOD(call->data, IPC_M_PHONE_HUNGUP); |
call->flags |= IPC_CALL_DISCARD_ANSWER; |
_ipc_call(phone, box, call); |
/* Allocate another call in advance */ |
call = ipc_call_alloc(0); |
/* Must start again */ |
goto restart_phones; |
} |
mutex_unlock(&phone->lock); |
} |
spinlock_unlock(&box->lock); |
interrupts_restore(ipl); |
/* Free unused call */ |
if (call) ipc_call_free(call); |
} |
/** Cleans up all IPC communication of the current task. |
* |
* Note: ipc_hangup sets returning answerbox to TASK->answerbox, you |
* have to change it as well if you want to cleanup other tasks than TASK. |
*/ |
void ipc_cleanup(void) |
{ |
int i; |
call_t *call; |
/* Disconnect all our phones ('ipc_phone_hangup') */ |
for (i = 0; i < IPC_MAX_PHONES; i++) |
ipc_phone_hangup(&TASK->phones[i]); |
/* Disconnect all connected irqs */ |
ipc_irq_cleanup(&TASK->answerbox); |
/* Disconnect all phones connected to our regular answerbox */ |
ipc_answerbox_slam_phones(&TASK->answerbox, false); |
#ifdef CONFIG_UDEBUG |
/* Clean up kbox thread and communications */ |
ipc_kbox_cleanup(); |
#endif |
/* Answer all messages in 'calls' and 'dispatched_calls' queues */ |
spinlock_lock(&TASK->answerbox.lock); |
ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls); |
ipc_cleanup_call_list(&TASK->answerbox.calls); |
spinlock_unlock(&TASK->answerbox.lock); |
/branches/dynload/kernel/generic/src/udebug/udebug_ipc.c |
---|
0,0 → 1,294 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 generic |
* @{ |
*/ |
/** |
* @file |
* @brief Udebug IPC message handling. |
*/ |
#include <proc/task.h> |
#include <proc/thread.h> |
#include <arch.h> |
#include <errno.h> |
#include <ipc/ipc.h> |
#include <syscall/copy.h> |
#include <udebug/udebug.h> |
#include <udebug/udebug_ops.h> |
#include <udebug/udebug_ipc.h> |
int udebug_request_preprocess(call_t *call, phone_t *phone) |
{ |
switch (IPC_GET_ARG1(call->data)) { |
/* future UDEBUG_M_REGS_WRITE, UDEBUG_M_MEM_WRITE: */ |
default: |
break; |
} |
return 0; |
} |
static void udebug_receive_begin(call_t *call) |
{ |
int rc; |
rc = udebug_begin(call); |
if (rc < 0) { |
IPC_SET_RETVAL(call->data, rc); |
ipc_answer(&TASK->kernel_box, call); |
return; |
} |
if (rc != 0) { |
IPC_SET_RETVAL(call->data, 0); |
ipc_answer(&TASK->kernel_box, call); |
} |
} |
static void udebug_receive_end(call_t *call) |
{ |
int rc; |
rc = udebug_end(); |
IPC_SET_RETVAL(call->data, rc); |
ipc_answer(&TASK->kernel_box, call); |
} |
static void udebug_receive_set_evmask(call_t *call) |
{ |
int rc; |
udebug_evmask_t mask; |
mask = IPC_GET_ARG2(call->data); |
rc = udebug_set_evmask(mask); |
IPC_SET_RETVAL(call->data, rc); |
ipc_answer(&TASK->kernel_box, call); |
} |
static void udebug_receive_go(call_t *call) |
{ |
thread_t *t; |
int rc; |
t = (thread_t *)IPC_GET_ARG2(call->data); |
rc = udebug_go(t, call); |
if (rc < 0) { |
IPC_SET_RETVAL(call->data, rc); |
ipc_answer(&TASK->kernel_box, call); |
return; |
} |
} |
static void udebug_receive_stop(call_t *call) |
{ |
thread_t *t; |
int rc; |
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; |
unative_t to_copy; |
unsigned total_bytes; |
unsigned buf_size; |
void *buffer; |
size_t n; |
int rc; |
uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */ |
buf_size = IPC_GET_ARG3(call->data); /* Dest. buffer size */ |
/* |
* Read thread list. Variable n will be filled with actual number |
* of threads times thread-id size. |
*/ |
rc = udebug_thread_read(&buffer, buf_size, &n); |
if (rc < 0) { |
IPC_SET_RETVAL(call->data, rc); |
ipc_answer(&TASK->kernel_box, call); |
return; |
} |
total_bytes = n; |
/* Copy MAX(buf_size, total_bytes) bytes */ |
if (buf_size > total_bytes) |
to_copy = total_bytes; |
else |
to_copy = buf_size; |
/* |
* Make use of call->buffer to transfer data to caller's userspace |
*/ |
IPC_SET_RETVAL(call->data, 0); |
/* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that |
same code in process_answer() can be used |
(no way to distinguish method in answer) */ |
IPC_SET_ARG1(call->data, uspace_addr); |
IPC_SET_ARG2(call->data, to_copy); |
IPC_SET_ARG3(call->data, total_bytes); |
call->buffer = buffer; |
ipc_answer(&TASK->kernel_box, call); |
} |
static void udebug_receive_args_read(call_t *call) |
{ |
thread_t *t; |
unative_t uspace_addr; |
int rc; |
void *buffer; |
t = (thread_t *)IPC_GET_ARG2(call->data); |
rc = udebug_args_read(t, &buffer); |
if (rc != EOK) { |
IPC_SET_RETVAL(call->data, rc); |
ipc_answer(&TASK->kernel_box, call); |
return; |
} |
/* |
* Make use of call->buffer to transfer data to caller's userspace |
*/ |
uspace_addr = IPC_GET_ARG3(call->data); |
IPC_SET_RETVAL(call->data, 0); |
/* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that |
same code in process_answer() can be used |
(no way to distinguish method in answer) */ |
IPC_SET_ARG1(call->data, uspace_addr); |
IPC_SET_ARG2(call->data, 6 * sizeof(unative_t)); |
call->buffer = buffer; |
ipc_answer(&TASK->kernel_box, call); |
} |
static void udebug_receive_mem_read(call_t *call) |
{ |
unative_t uspace_dst; |
unative_t uspace_src; |
unsigned size; |
void *buffer; |
int rc; |
uspace_dst = IPC_GET_ARG2(call->data); |
uspace_src = IPC_GET_ARG3(call->data); |
size = IPC_GET_ARG4(call->data); |
rc = udebug_mem_read(uspace_src, size, &buffer); |
if (rc < 0) { |
IPC_SET_RETVAL(call->data, rc); |
ipc_answer(&TASK->kernel_box, call); |
return; |
} |
IPC_SET_RETVAL(call->data, 0); |
/* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that |
same code in process_answer() can be used |
(no way to distinguish method in answer) */ |
IPC_SET_ARG1(call->data, uspace_dst); |
IPC_SET_ARG2(call->data, size); |
call->buffer = buffer; |
ipc_answer(&TASK->kernel_box, call); |
} |
/** |
* Handle a debug call received on the kernel answerbox. |
* |
* This is called by the kbox servicing thread. |
*/ |
void udebug_call_receive(call_t *call) |
{ |
int debug_method; |
debug_method = IPC_GET_ARG1(call->data); |
if (debug_method != UDEBUG_M_BEGIN) { |
/* |
* Verify that the sender is this task's debugger. |
* Note that this is the only thread that could change |
* TASK->debugger. Therefore no locking is necessary |
* and the sender can be safely considered valid until |
* control exits this function. |
*/ |
if (TASK->udebug.debugger != call->sender) { |
IPC_SET_RETVAL(call->data, EINVAL); |
ipc_answer(&TASK->kernel_box, call); |
return; |
} |
} |
switch (debug_method) { |
case UDEBUG_M_BEGIN: |
udebug_receive_begin(call); |
break; |
case UDEBUG_M_END: |
udebug_receive_end(call); |
break; |
case UDEBUG_M_SET_EVMASK: |
udebug_receive_set_evmask(call); |
break; |
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; |
case UDEBUG_M_ARGS_READ: |
udebug_receive_args_read(call); |
break; |
case UDEBUG_M_MEM_READ: |
udebug_receive_mem_read(call); |
break; |
} |
} |
/** @} |
*/ |
/branches/dynload/kernel/generic/src/udebug/udebug.c |
---|
0,0 → 1,502 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 generic |
* @{ |
*/ |
/** |
* @file |
* @brief Udebug. |
* |
* Functions in this file are executed directly in each thread, which |
* may or may not be the subject of debugging. The udebug_stoppable_begin/end() |
* functions are also executed in the clock interrupt handler. To avoid |
* deadlock, functions in this file are protected from the interrupt |
* by locking the recursive lock THREAD->udebug.int_lock (just an atomic |
* variable). This prevents udebug_stoppable_begin/end() from being |
* executed in the interrupt handler (they are skipped). |
* |
* Functions in udebug_ops.c and udebug_ipc.c execute in different threads, |
* so they needn't be protected from the (preemptible) interrupt-initiated |
* code. |
*/ |
#include <synch/waitq.h> |
#include <debug.h> |
#include <udebug/udebug.h> |
#include <errno.h> |
#include <arch.h> |
static inline void udebug_int_lock(void) |
{ |
atomic_inc(&THREAD->udebug.int_lock); |
} |
static inline void udebug_int_unlock(void) |
{ |
atomic_dec(&THREAD->udebug.int_lock); |
} |
void udebug_task_init(udebug_task_t *ut) |
{ |
mutex_initialize(&ut->lock, MUTEX_PASSIVE); |
ut->dt_state = UDEBUG_TS_INACTIVE; |
ut->begin_call = NULL; |
ut->not_stoppable_count = 0; |
ut->evmask = 0; |
} |
void udebug_thread_initialize(udebug_thread_t *ut) |
{ |
mutex_initialize(&ut->lock, MUTEX_PASSIVE); |
waitq_initialize(&ut->go_wq); |
/* |
* At the beginning the thread is stoppable, so int_lock be set, too. |
*/ |
atomic_set(&ut->int_lock, 1); |
ut->go_call = NULL; |
ut->stop = true; |
ut->stoppable = true; |
ut->debug_active = false; |
ut->cur_event = 0; /* none */ |
} |
static void udebug_wait_for_go(waitq_t *wq) |
{ |
int rc; |
ipl_t ipl; |
ipl = waitq_sleep_prepare(wq); |
wq->missed_wakeups = 0; /* Enforce blocking. */ |
rc = waitq_sleep_timeout_unsafe(wq, SYNCH_NO_TIMEOUT, SYNCH_FLAGS_NONE); |
waitq_sleep_finish(wq, rc, ipl); |
} |
/** Do a preliminary check that a debugging session is in progress. |
* |
* This only requires the THREAD->udebug.lock mutex (and not |
* TASK->udebug.lock mutex). For an undebugged task, this will |
* never block (while there could be collisions by different threads |
* on the TASK mutex), thus improving SMP perormance for undebugged tasks. |
*/ |
static bool udebug_thread_precheck(void) |
{ |
bool res; |
mutex_lock(&THREAD->udebug.lock); |
res = THREAD->udebug.debug_active; |
mutex_unlock(&THREAD->udebug.lock); |
return res; |
} |
void udebug_stoppable_begin(void) |
{ |
int nsc; |
call_t *db_call, *go_call; |
ASSERT(THREAD); |
ASSERT(TASK); |
udebug_int_lock(); |
/* Early check for undebugged tasks */ |
if (!udebug_thread_precheck()) { |
udebug_int_unlock(); |
return; |
} |
mutex_lock(&TASK->udebug.lock); |
nsc = --TASK->udebug.not_stoppable_count; |
/* Lock order OK, THREAD->udebug.lock is after TASK->udebug.lock */ |
mutex_lock(&THREAD->udebug.lock); |
ASSERT(THREAD->udebug.stoppable == false); |
THREAD->udebug.stoppable = true; |
if (TASK->udebug.dt_state == UDEBUG_TS_BEGINNING && nsc == 0) { |
/* |
* This was the last non-stoppable thread. Reply to |
* DEBUG_BEGIN call. |
*/ |
db_call = TASK->udebug.begin_call; |
ASSERT(db_call); |
TASK->udebug.dt_state = UDEBUG_TS_ACTIVE; |
TASK->udebug.begin_call = NULL; |
IPC_SET_RETVAL(db_call->data, 0); |
ipc_answer(&TASK->answerbox, db_call); |
} else if (TASK->udebug.dt_state == UDEBUG_TS_ACTIVE) { |
/* |
* Active debugging session |
*/ |
if (THREAD->udebug.debug_active && THREAD->udebug.stop) { |
/* |
* Thread was requested to stop - answer go call |
*/ |
/* Make sure nobody takes this call away from us */ |
go_call = THREAD->udebug.go_call; |
THREAD->udebug.go_call = NULL; |
ASSERT(go_call); |
IPC_SET_RETVAL(go_call->data, 0); |
IPC_SET_ARG1(go_call->data, UDEBUG_EVENT_STOP); |
THREAD->udebug.cur_event = UDEBUG_EVENT_STOP; |
ipc_answer(&TASK->answerbox, go_call); |
} |
} |
mutex_unlock(&THREAD->udebug.lock); |
mutex_unlock(&TASK->udebug.lock); |
} |
void udebug_stoppable_end(void) |
{ |
/* Early check for undebugged tasks */ |
if (!udebug_thread_precheck()) { |
udebug_int_unlock(); |
return; |
} |
restart: |
mutex_lock(&TASK->udebug.lock); |
mutex_lock(&THREAD->udebug.lock); |
if (THREAD->udebug.debug_active && |
THREAD->udebug.stop == true) { |
TASK->udebug.begin_call = NULL; |
mutex_unlock(&THREAD->udebug.lock); |
mutex_unlock(&TASK->udebug.lock); |
udebug_wait_for_go(&THREAD->udebug.go_wq); |
goto restart; |
/* must try again - have to lose stoppability atomically */ |
} else { |
++TASK->udebug.not_stoppable_count; |
ASSERT(THREAD->udebug.stoppable == true); |
THREAD->udebug.stoppable = false; |
mutex_unlock(&THREAD->udebug.lock); |
mutex_unlock(&TASK->udebug.lock); |
} |
udebug_int_unlock(); |
} |
/** Upon being scheduled to run, check if the current thread should stop. |
* |
* This function is called from clock(). Preemption is enabled. |
* interrupts are disabled, but since this is called after |
* being scheduled-in, we can enable them, if we're careful enough |
* not to allow arbitrary recursion or deadlock with the thread context. |
*/ |
void udebug_before_thread_runs(void) |
{ |
ipl_t ipl; |
return; |
ASSERT(!PREEMPTION_DISABLED); |
/* |
* Prevent agains re-entering, such as when preempted inside this |
* function. |
*/ |
if (atomic_get(&THREAD->udebug.int_lock) != 0) |
return; |
udebug_int_lock(); |
ipl = interrupts_enable(); |
/* Now we're free to do whatever we need (lock mutexes, sleep, etc.) */ |
/* Check if we're supposed to stop */ |
udebug_stoppable_begin(); |
udebug_stoppable_end(); |
interrupts_restore(ipl); |
udebug_int_unlock(); |
} |
void udebug_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, |
bool end_variant) |
{ |
call_t *call; |
udebug_event_t etype; |
etype = end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B; |
udebug_int_lock(); |
/* Early check for undebugged tasks */ |
if (!udebug_thread_precheck()) { |
udebug_int_unlock(); |
return; |
} |
mutex_lock(&TASK->udebug.lock); |
mutex_lock(&THREAD->udebug.lock); |
/* Must only generate events when in debugging session and have go */ |
if (THREAD->udebug.debug_active != true || |
THREAD->udebug.stop == true || |
(TASK->udebug.evmask & UDEBUG_EVMASK(etype)) == 0) { |
mutex_unlock(&THREAD->udebug.lock); |
mutex_unlock(&TASK->udebug.lock); |
return; |
} |
//printf("udebug_syscall_event\n"); |
call = THREAD->udebug.go_call; |
THREAD->udebug.go_call = NULL; |
IPC_SET_RETVAL(call->data, 0); |
IPC_SET_ARG1(call->data, etype); |
IPC_SET_ARG2(call->data, id); |
IPC_SET_ARG3(call->data, rc); |
//printf("udebug_syscall_event/ipc_answer\n"); |
THREAD->udebug.syscall_args[0] = a1; |
THREAD->udebug.syscall_args[1] = a2; |
THREAD->udebug.syscall_args[2] = a3; |
THREAD->udebug.syscall_args[3] = a4; |
THREAD->udebug.syscall_args[4] = a5; |
THREAD->udebug.syscall_args[5] = a6; |
/* |
* Make sure udebug.stop is true when going to sleep |
* in case we get woken up by DEBUG_END. (At which |
* point it must be back to the initial true value). |
*/ |
THREAD->udebug.stop = true; |
THREAD->udebug.cur_event = etype; |
ipc_answer(&TASK->answerbox, call); |
mutex_unlock(&THREAD->udebug.lock); |
mutex_unlock(&TASK->udebug.lock); |
udebug_wait_for_go(&THREAD->udebug.go_wq); |
udebug_int_unlock(); |
} |
void udebug_thread_b_event(struct thread *t) |
{ |
call_t *call; |
udebug_int_lock(); |
mutex_lock(&TASK->udebug.lock); |
mutex_lock(&THREAD->udebug.lock); |
LOG("udebug_thread_b_event\n"); |
LOG("- check state\n"); |
/* Must only generate events when in debugging session */ |
if (THREAD->udebug.debug_active != true) { |
LOG("- debug_active: %s, udebug.stop: %s\n", |
THREAD->udebug.debug_active ? "yes(+)" : "no(-)", |
THREAD->udebug.stop ? "yes(-)" : "no(+)"); |
mutex_unlock(&THREAD->udebug.lock); |
mutex_unlock(&TASK->udebug.lock); |
return; |
} |
LOG("- trigger event\n"); |
call = THREAD->udebug.go_call; |
THREAD->udebug.go_call = NULL; |
IPC_SET_RETVAL(call->data, 0); |
IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_B); |
IPC_SET_ARG2(call->data, (unative_t)t); |
/* |
* Make sure udebug.stop is true when going to sleep |
* in case we get woken up by DEBUG_END. (At which |
* point it must be back to the initial true value). |
*/ |
THREAD->udebug.stop = true; |
THREAD->udebug.cur_event = UDEBUG_EVENT_THREAD_B; |
ipc_answer(&TASK->answerbox, call); |
mutex_unlock(&THREAD->udebug.lock); |
mutex_unlock(&TASK->udebug.lock); |
LOG("- sleep\n"); |
udebug_wait_for_go(&THREAD->udebug.go_wq); |
udebug_int_unlock(); |
} |
void udebug_thread_e_event(void) |
{ |
call_t *call; |
udebug_int_lock(); |
mutex_lock(&TASK->udebug.lock); |
mutex_lock(&THREAD->udebug.lock); |
LOG("udebug_thread_e_event\n"); |
LOG("- check state\n"); |
/* Must only generate events when in debugging session */ |
if (THREAD->udebug.debug_active != true) { |
/* printf("- debug_active: %s, udebug.stop: %s\n", |
THREAD->udebug.debug_active ? "yes(+)" : "no(-)", |
THREAD->udebug.stop ? "yes(-)" : "no(+)");*/ |
mutex_unlock(&THREAD->udebug.lock); |
mutex_unlock(&TASK->udebug.lock); |
return; |
} |
LOG("- trigger event\n"); |
call = THREAD->udebug.go_call; |
THREAD->udebug.go_call = NULL; |
IPC_SET_RETVAL(call->data, 0); |
IPC_SET_ARG1(call->data, UDEBUG_EVENT_THREAD_E); |
/* Prevent any further debug activity in thread */ |
THREAD->udebug.debug_active = false; |
THREAD->udebug.cur_event = 0; /* none */ |
THREAD->udebug.stop = true; /* set to initial value */ |
ipc_answer(&TASK->answerbox, call); |
mutex_unlock(&THREAD->udebug.lock); |
mutex_unlock(&TASK->udebug.lock); |
/* Leave int_lock enabled */ |
/* This event does not sleep - debugging has finished in this thread */ |
} |
/** |
* Terminate task debugging session. |
* |
* \param ta->udebug.lock must be already locked. |
* \return Zero on success or negative error code. |
*/ |
int udebug_task_cleanup(struct task *ta) |
{ |
thread_t *t; |
link_t *cur; |
int flags; |
ipl_t ipl; |
LOG("udebug_task_cleanup()\n"); |
LOG("task %" PRIu64 "\n", ta->taskid); |
udebug_int_lock(); |
if (ta->udebug.dt_state != UDEBUG_TS_BEGINNING && |
ta->udebug.dt_state != UDEBUG_TS_ACTIVE) { |
LOG("udebug_task_cleanup(): task not being debugged\n"); |
return EINVAL; |
} |
/* Finish debugging of all userspace threads */ |
for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
t = list_get_instance(cur, thread_t, th_link); |
mutex_lock(&t->udebug.lock); |
ipl = interrupts_disable(); |
spinlock_lock(&t->lock); |
flags = t->flags; |
spinlock_unlock(&t->lock); |
interrupts_restore(ipl); |
/* Only process userspace threads */ |
if ((flags & THREAD_FLAG_USPACE) != 0) { |
/* Prevent any further debug activity in thread */ |
t->udebug.debug_active = false; |
t->udebug.cur_event = 0; /* none */ |
/* Still has go? */ |
if (t->udebug.stop == false) { |
/* |
* Yes, so clear go. As debug_active == false, |
* this doesn't affect anything. |
*/ |
t->udebug.stop = true; |
/* Answer GO call */ |
LOG("answer GO call with EVENT_FINISHED\n"); |
IPC_SET_RETVAL(t->udebug.go_call->data, 0); |
IPC_SET_ARG1(t->udebug.go_call->data, UDEBUG_EVENT_FINISHED); |
ipc_answer(&ta->answerbox, t->udebug.go_call); |
t->udebug.go_call = NULL; |
} else { |
/* |
* Debug_stop is already at initial value. |
* Yet this means the thread needs waking up. |
*/ |
/* |
* t's lock must not be held when calling |
* waitq_wakeup. |
*/ |
waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST); |
} |
} |
mutex_unlock(&t->udebug.lock); |
} |
ta->udebug.dt_state = UDEBUG_TS_INACTIVE; |
ta->udebug.debugger = NULL; |
udebug_int_unlock(); |
return 0; |
} |
/** @} |
*/ |
/branches/dynload/kernel/generic/src/udebug/udebug_ops.c |
---|
0,0 → 1,436 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 generic |
* @{ |
*/ |
/** |
* @file |
* @brief Udebug operations. |
*/ |
#include <debug.h> |
#include <proc/task.h> |
#include <proc/thread.h> |
#include <arch.h> |
#include <errno.h> |
#include <syscall/copy.h> |
#include <ipc/ipc.h> |
#include <udebug/udebug.h> |
#include <udebug/udebug_ops.h> |
/** |
* Prepare a thread for a debugging operation. |
* |
* Simply put, return thread t with t->udebug.lock held, |
* but only if it verifies all conditions. |
* |
* Specifically, verifies that thread t exists, is a userspace thread, |
* 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->udebug.lock, making sure that t->udebug.debug_active |
* is true - that the thread is in a valid debugging session. |
* |
* With this verified and the t->udebug.lock mutex held, it is ensured |
* that the thread cannot leave the debugging session, let alone cease |
* to exist. |
* |
* In this function, holding the TASK->udebug.lock mutex prevents the |
* thread from leaving the debugging session, while relaxing from |
* the t->lock spinlock to the t->udebug.lock mutex. |
* |
* Returns EOK if all went well, or an error code otherwise. |
*/ |
static int _thread_op_begin(thread_t *t, bool having_go) |
{ |
task_id_t taskid; |
ipl_t ipl; |
taskid = TASK->taskid; |
mutex_lock(&TASK->udebug.lock); |
/* thread_exists() must be called with threads_lock held */ |
ipl = interrupts_disable(); |
spinlock_lock(&threads_lock); |
if (!thread_exists(t)) { |
spinlock_unlock(&threads_lock); |
interrupts_restore(ipl); |
mutex_unlock(&TASK->udebug.lock); |
return ENOENT; |
} |
/* t->lock is enough to ensure the thread's existence */ |
spinlock_lock(&t->lock); |
spinlock_unlock(&threads_lock); |
/* Verify that 't' is a userspace thread */ |
if ((t->flags & THREAD_FLAG_USPACE) == 0) { |
/* It's not, deny its existence */ |
spinlock_unlock(&t->lock); |
interrupts_restore(ipl); |
mutex_unlock(&TASK->udebug.lock); |
return ENOENT; |
} |
/* Verify debugging state */ |
if (t->udebug.debug_active != true) { |
/* Not in debugging session or undesired GO state */ |
spinlock_unlock(&t->lock); |
interrupts_restore(ipl); |
mutex_unlock(&TASK->udebug.lock); |
return ENOENT; |
} |
/* |
* Since the thread has debug_active == true, TASK->udebug.lock |
* is enough to ensure its existence and that debug_active remains |
* true. |
*/ |
spinlock_unlock(&t->lock); |
interrupts_restore(ipl); |
/* Only mutex TASK->udebug.lock left */ |
/* Now verify that the thread belongs to the current task */ |
if (t->task != TASK) { |
/* No such thread belonging this task*/ |
mutex_unlock(&TASK->udebug.lock); |
return ENOENT; |
} |
/* |
* Now we need to grab the thread's debug lock for synchronization |
* of the threads stoppability/stop state. |
*/ |
mutex_lock(&t->udebug.lock); |
/* The big task mutex is no longer needed */ |
mutex_unlock(&TASK->udebug.lock); |
if (!t->udebug.stop != having_go) { |
/* Not in debugging session or undesired GO state */ |
mutex_unlock(&t->udebug.lock); |
return EINVAL; |
} |
/* Only t->udebug.lock left */ |
return EOK; /* All went well */ |
} |
static void _thread_op_end(thread_t *t) |
{ |
mutex_unlock(&t->udebug.lock); |
} |
/** |
* \return 0 (ok, but not done yet), 1 (done) or negative error code. |
*/ |
int udebug_begin(call_t *call) |
{ |
int reply; |
thread_t *t; |
link_t *cur; |
LOG("udebug_begin()\n"); |
mutex_lock(&TASK->udebug.lock); |
LOG("debugging task %llu\n", TASK->taskid); |
if (TASK->udebug.dt_state != UDEBUG_TS_INACTIVE) { |
mutex_unlock(&TASK->udebug.lock); |
LOG("udebug_begin(): busy error\n"); |
return EBUSY; |
} |
TASK->udebug.dt_state = UDEBUG_TS_BEGINNING; |
TASK->udebug.begin_call = call; |
TASK->udebug.debugger = call->sender; |
if (TASK->udebug.not_stoppable_count == 0) { |
TASK->udebug.dt_state = UDEBUG_TS_ACTIVE; |
TASK->udebug.begin_call = NULL; |
reply = 1; /* immediate reply */ |
} else { |
reply = 0; /* no reply */ |
} |
/* Set udebug.debug_active on all of the task's userspace threads */ |
for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) { |
t = list_get_instance(cur, thread_t, th_link); |
mutex_lock(&t->udebug.lock); |
if ((t->flags & THREAD_FLAG_USPACE) != 0) |
t->udebug.debug_active = true; |
mutex_unlock(&t->udebug.lock); |
} |
mutex_unlock(&TASK->udebug.lock); |
LOG("udebug_begin() done (%s)\n", |
reply ? "reply" : "stoppability wait"); |
return reply; |
} |
int udebug_end(void) |
{ |
int rc; |
LOG("udebug_end()\n"); |
mutex_lock(&TASK->udebug.lock); |
LOG("task %" PRIu64 "\n", TASK->taskid); |
rc = udebug_task_cleanup(TASK); |
mutex_unlock(&TASK->udebug.lock); |
return rc; |
} |
int udebug_set_evmask(udebug_evmask_t mask) |
{ |
LOG("udebug_set_mask()\n"); |
mutex_lock(&TASK->udebug.lock); |
if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) { |
mutex_unlock(&TASK->udebug.lock); |
LOG("udebug_set_mask(): not active debuging session\n"); |
return EINVAL; |
} |
TASK->udebug.evmask = mask; |
mutex_unlock(&TASK->udebug.lock); |
return 0; |
} |
int udebug_go(thread_t *t, call_t *call) |
{ |
int rc; |
/* On success, this will lock t->udebug.lock */ |
rc = _thread_op_begin(t, false); |
if (rc != EOK) { |
return rc; |
} |
t->udebug.go_call = call; |
t->udebug.stop = false; |
t->udebug.cur_event = 0; /* none */ |
/* |
* Neither t's lock nor threads_lock may be held during wakeup |
*/ |
waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST); |
_thread_op_end(t); |
return 0; |
} |
int udebug_stop(thread_t *t, call_t *call) |
{ |
int rc; |
LOG("udebug_stop()\n"); |
mutex_lock(&TASK->udebug.lock); |
/* |
* On success, this will lock t->udebug.lock. Note that this makes sure |
* the thread is not stopped. |
*/ |
rc = _thread_op_begin(t, true); |
if (rc != EOK) { |
return rc; |
} |
/* Take GO away from the thread */ |
t->udebug.stop = true; |
if (!t->udebug.stoppable) { |
/* Answer will be sent when the thread becomes stoppable */ |
_thread_op_end(t); |
return 0; |
} |
/* |
* Answer GO call |
*/ |
LOG("udebug_stop - answering go call\n"); |
/* Make sure nobody takes this call away from us */ |
call = t->udebug.go_call; |
t->udebug.go_call = NULL; |
IPC_SET_RETVAL(call->data, 0); |
IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP); |
LOG("udebug_stop/ipc_answer\n"); |
THREAD->udebug.cur_event = UDEBUG_EVENT_STOP; |
_thread_op_end(t); |
ipc_answer(&TASK->answerbox, call); |
mutex_unlock(&TASK->udebug.lock); |
LOG("udebog_stop/done\n"); |
return 0; |
} |
int udebug_thread_read(void **buffer, size_t buf_size, size_t *n) |
{ |
thread_t *t; |
link_t *cur; |
unative_t tid; |
unsigned copied_ids; |
ipl_t ipl; |
unative_t *id_buffer; |
int flags; |
size_t max_ids; |
LOG("udebug_thread_read()\n"); |
/* Allocate a buffer to hold thread IDs */ |
id_buffer = malloc(buf_size, 0); |
mutex_lock(&TASK->udebug.lock); |
/* Verify task state */ |
if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) { |
mutex_unlock(&TASK->udebug.lock); |
return EINVAL; |
} |
ipl = interrupts_disable(); |
spinlock_lock(&TASK->lock); |
/* Copy down the thread IDs */ |
max_ids = buf_size / sizeof(unative_t); |
copied_ids = 0; |
/* FIXME: make sure the thread isn't past debug shutdown... */ |
for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) { |
/* Do not write past end of buffer */ |
if (copied_ids >= max_ids) break; |
t = list_get_instance(cur, thread_t, th_link); |
spinlock_lock(&t->lock); |
flags = t->flags; |
spinlock_unlock(&t->lock); |
/* Not interested in kernel threads */ |
if ((flags & THREAD_FLAG_USPACE) != 0) { |
/* Using thread struct pointer as identification hash */ |
tid = (unative_t) t; |
id_buffer[copied_ids++] = tid; |
} |
} |
spinlock_unlock(&TASK->lock); |
interrupts_restore(ipl); |
mutex_unlock(&TASK->udebug.lock); |
*buffer = id_buffer; |
*n = copied_ids * sizeof(unative_t); |
return 0; |
} |
int udebug_args_read(thread_t *t, void **buffer) |
{ |
int rc; |
unative_t *arg_buffer; |
/* Prepare a buffer to hold the arguments */ |
arg_buffer = malloc(6 * sizeof(unative_t), 0); |
/* On success, this will lock t->udebug.lock */ |
rc = _thread_op_begin(t, false); |
if (rc != EOK) { |
return rc; |
} |
/* Additionally we need to verify that we are inside a syscall */ |
if (t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_B && |
t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_E) { |
_thread_op_end(t); |
return EINVAL; |
} |
/* Copy to a local buffer before releasing the lock */ |
memcpy(arg_buffer, t->udebug.syscall_args, 6 * sizeof(unative_t)); |
_thread_op_end(t); |
*buffer = arg_buffer; |
return 0; |
} |
int udebug_mem_read(unative_t uspace_addr, size_t n, void **buffer) |
{ |
void *data_buffer; |
int rc; |
/* Verify task state */ |
mutex_lock(&TASK->udebug.lock); |
if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) { |
mutex_unlock(&TASK->udebug.lock); |
return EBUSY; |
} |
data_buffer = malloc(n, 0); |
/* NOTE: this is not strictly from a syscall... but that shouldn't |
* be a problem */ |
rc = copy_from_uspace(data_buffer, (void *)uspace_addr, n); |
mutex_unlock(&TASK->udebug.lock); |
if (rc != 0) return rc; |
*buffer = data_buffer; |
return 0; |
} |
/** @} |
*/ |
/branches/dynload/kernel/Makefile |
---|
150,6 → 150,10 |
endif |
endif |
ifeq ($(CONFIG_UDEBUG),y) |
DEFS += -DCONFIG_UDEBUG |
endif |
## Simple detection for the type of the host system |
# |
HOST = $(shell uname) |
283,6 → 287,17 |
generic/src/security/cap.c \ |
generic/src/sysinfo/sysinfo.c |
## Udebug interface sources |
# |
ifeq ($(CONFIG_UDEBUG),y) |
GENERIC_SOURCES += \ |
generic/src/ipc/kbox.c \ |
generic/src/udebug/udebug.c \ |
generic/src/udebug/udebug_ops.c \ |
generic/src/udebug/udebug_ipc.c |
endif |
## Test sources |
# |
/branches/dynload/kernel/arch/arm32/include/interrupt.h |
---|
37,6 → 37,7 |
#define KERN_arm32_INTERRUPT_H_ |
#include <arch/types.h> |
#include <arch/exception.h> |
/** Initial size of exception dispatch table. */ |
#define IVT_ITEMS 6 |
/branches/dynload/uspace/app/bdsh/cmds/mknewcmd |
---|
120,8 → 120,8 |
EOF |
[ "${CMDTYPE}" = "module" ] && cat << EOF >> ${OUTDIR}/entry.h |
/* Entry points for the ${CMDNAME} command */ |
extern int * ${CMDENTRY}(char **); |
extern void * ${HELPENTRY}(unsigned int); |
extern int ${CMDENTRY}(char **); |
extern void ${HELPENTRY}(unsigned int); |
#endif /* ${defname}_ENTRY_H */ |
170,22 → 170,22 |
static char *cmdname = "${CMDNAME}"; |
/* Dispays help for ${CMDNAME} in various levels */ |
void * ${HELPENTRY}(unsigned int level) |
void ${HELPENTRY}(unsigned int level) |
{ |
printf("This is the %s help for '%s'.\n", |
level ? EXT_HELP : SHORT_HELP, cmdname); |
return CMD_VOID; |
return; |
} |
EOF |
[ "${CMDTYPE}" = "module" ] && cat << EOF >> ${OUTDIR}/${CMDNAME}.c |
/* Main entry point for ${CMDNAME}, accepts an array of arguments */ |
int * ${CMDENTRY}(char **argv) |
int ${CMDENTRY}(char **argv) |
EOF |
[ "${CMDTYPE}" = "builtin" ] && cat << EOF >> ${OUTDIR}/${CMDNAME}.c |
/* Main entry point for ${CMDNAME}, accepts an array of arguments and a |
* pointer to the cliuser_t structure */ |
int * ${CMDENTRY}(char **argv, cliuser_t *usr) |
int ${CMDENTRY}(char **argv, cliuser_t *usr) |
EOF |
cat << EOF >> ${OUTDIR}/${CMDNAME}.c |
{ |
/branches/dynload/uspace/app/bdsh/cmds/modules/quit/quit.c |
---|
39,15 → 39,15 |
extern volatile unsigned int cli_quit; |
extern const char *progname; |
void * help_cmd_quit(unsigned int level) |
void help_cmd_quit(unsigned int level) |
{ |
printf("Type `%s' to exit %s\n", cmdname, progname); |
return CMD_VOID; |
return; |
} |
/* Quits the program and returns the status of whatever command |
* came before invoking 'quit' */ |
int * cmd_quit(char *argv[]) |
int cmd_quit(char *argv[]) |
{ |
/* Inform that we're outta here */ |
cli_quit = 1; |
/branches/dynload/uspace/app/bdsh/cmds/modules/quit/entry.h |
---|
2,8 → 2,8 |
#define QUIT_ENTRY_H_ |
/* Entry points for the quit command */ |
extern void * help_cmd_quit(unsigned int); |
extern int * cmd_quit(char *[]); |
extern void help_cmd_quit(unsigned int); |
extern int cmd_quit(char *[]); |
#endif |
/branches/dynload/uspace/app/bdsh/cmds/modules/touch/touch.c |
---|
48,7 → 48,7 |
static char *cmdname = "touch"; |
/* Dispays help for touch in various levels */ |
void * help_cmd_touch(unsigned int level) |
void help_cmd_touch(unsigned int level) |
{ |
if (level == HELP_SHORT) { |
printf("`%s' updates access times for files\n", cmdname); |
58,11 → 58,11 |
"created\n", cmdname); |
} |
return CMD_VOID; |
return; |
} |
/* Main entry point for touch, accepts an array of arguments */ |
int * cmd_touch(char **argv) |
int cmd_touch(char **argv) |
{ |
unsigned int argc, i = 0, ret = 0; |
int fd; |
/branches/dynload/uspace/app/bdsh/cmds/modules/touch/entry.h |
---|
2,8 → 2,8 |
#define TOUCH_ENTRY_H |
/* Entry points for the touch command */ |
extern int * cmd_touch(char **); |
extern void * help_cmd_touch(unsigned int); |
extern int cmd_touch(char **); |
extern void help_cmd_touch(unsigned int); |
#endif /* TOUCH_ENTRY_H */ |
/branches/dynload/uspace/app/bdsh/cmds/modules/cp/cp.c |
---|
0,0 → 1,73 |
/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com> |
* 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. |
* |
* Neither the name of the original program's authors nor the names of its |
* contributors may be used to endorse or promote products derived from this |
* software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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. |
*/ |
#include <stdio.h> |
#include <stdlib.h> |
#include "config.h" |
#include "util.h" |
#include "errors.h" |
#include "entry.h" |
#include "cp.h" |
#include "cmds.h" |
static char *cmdname = "cp"; |
/* Dispays help for cp in various levels */ |
void help_cmd_cp(unsigned int level) |
{ |
printf("This is the %s help for '%s'.\n", |
level ? EXT_HELP : SHORT_HELP, cmdname); |
return; |
} |
/* Main entry point for cp, accepts an array of arguments */ |
int cmd_cp(char **argv) |
{ |
unsigned int argc; |
unsigned int i; |
/* Count the arguments */ |
for (argc = 0; argv[argc] != NULL; argc ++); |
printf("%s %s\n", TEST_ANNOUNCE, cmdname); |
printf("%d arguments passed to %s", argc - 1, cmdname); |
if (argc < 2) { |
printf("\n"); |
return CMD_SUCCESS; |
} |
printf(":\n"); |
for (i = 1; i < argc; i++) |
printf("[%d] -> %s\n", i, argv[i]); |
return CMD_SUCCESS; |
} |
/branches/dynload/uspace/app/bdsh/cmds/modules/cp/cp_def.h |
---|
0,0 → 1,8 |
{ |
"cp", |
"Copy files and directories", |
&cmd_cp, |
&help_cmd_cp, |
0 |
}, |
/branches/dynload/uspace/app/bdsh/cmds/modules/cp/entry.h |
---|
0,0 → 1,9 |
#ifndef CP_ENTRY_H |
#define CP_ENTRY_H |
/* Entry points for the cp command */ |
extern int cmd_cp(char **); |
extern void help_cmd_cp(unsigned int); |
#endif /* CP_ENTRY_H */ |
/branches/dynload/uspace/app/bdsh/cmds/modules/cp/cp.h |
---|
0,0 → 1,8 |
#ifndef CP_H |
#define CP_H |
/* Prototypes for the cp command, excluding entry points */ |
#endif /* CP_H */ |
/branches/dynload/uspace/app/bdsh/cmds/modules/mkdir/entry.h |
---|
2,8 → 2,8 |
#define MKDIR_ENTRY_H |
/* Entry points for the mkdir command */ |
extern int * cmd_mkdir(char **); |
extern void * help_cmd_mkdir(unsigned int); |
extern int cmd_mkdir(char **); |
extern void help_cmd_mkdir(unsigned int); |
#endif /* MKDIR_ENTRY_H */ |
/branches/dynload/uspace/app/bdsh/cmds/modules/mkdir/mkdir.c |
---|
60,7 → 60,7 |
}; |
void * help_cmd_mkdir(unsigned int level) |
void help_cmd_mkdir(unsigned int level) |
{ |
if (level == HELP_SHORT) { |
printf("`%s' creates a new directory\n", cmdname); |
79,7 → 79,7 |
cmdname, cmdname); |
} |
return CMD_VOID; |
return; |
} |
/* This is kind of clunky, but effective for now */ |
181,7 → 181,7 |
return ret; |
} |
int * cmd_mkdir(char **argv) |
int cmd_mkdir(char **argv) |
{ |
unsigned int argc, create_parents = 0, i, ret = 0, follow = 0; |
unsigned int verbose = 0; |
/branches/dynload/uspace/app/bdsh/cmds/modules/cat/entry.h |
---|
2,8 → 2,8 |
#define CAT_ENTRY_H |
/* Entry points for the cat command */ |
extern int * cmd_cat(char **); |
extern void * help_cmd_cat(unsigned int); |
extern int cmd_cat(char **); |
extern void help_cmd_cat(unsigned int); |
#endif /* CAT_ENTRY_H */ |
/branches/dynload/uspace/app/bdsh/cmds/modules/cat/cat.c |
---|
59,7 → 59,7 |
}; |
/* Dispays help for cat in various levels */ |
void * help_cmd_cat(unsigned int level) |
void help_cmd_cat(unsigned int level) |
{ |
if (level == HELP_SHORT) { |
printf("`%s' shows the contents of files\n", cmdname); |
78,7 → 78,7 |
cmdname, cmdname); |
} |
return CMD_VOID; |
return; |
} |
static unsigned int cat_file(const char *fname, size_t blen) |
121,12 → 121,6 |
return 1; |
} |
/* Debug stuff, newline not added purposefully */ |
printf("** %s is a file with the size of %ld bytes\n", |
fname, total); |
printf( "** %d bytes were read in a buffer of %d bytes in %d reads\n", |
count, blen, reads); |
printf("** Read %s\n", count == total ? "Succeeded" : "Failed"); |
free(buff); |
return 0; |
133,7 → 127,7 |
} |
/* Main entry point for cat, accepts an array of arguments */ |
int * cmd_cat(char **argv) |
int cmd_cat(char **argv) |
{ |
unsigned int argc, i, ret = 0, buffer = 0; |
int c, opt_ind; |
/branches/dynload/uspace/app/bdsh/cmds/modules/help/entry.h |
---|
2,7 → 2,7 |
#define HELP_ENTRY_H_ |
/* Entry points for the help command */ |
extern void * help_cmd_help(unsigned int); |
extern int * cmd_help(char *[]); |
extern void help_cmd_help(unsigned int); |
extern int cmd_help(char *[]); |
#endif |
/branches/dynload/uspace/app/bdsh/cmds/modules/help/help.c |
---|
69,7 → 69,7 |
return HELP_IS_RUBBISH; |
} |
void *help_cmd_help(unsigned int level) |
void help_cmd_help(unsigned int level) |
{ |
if (level == HELP_SHORT) { |
printf( |
86,10 → 86,10 |
cmdname, cmdname, cmdname, cmdname); |
} |
return CMD_VOID; |
return; |
} |
int *cmd_help(char *argv[]) |
int cmd_help(char *argv[]) |
{ |
module_t *mod; |
builtin_t *cmd; |
/branches/dynload/uspace/app/bdsh/cmds/modules/sleep/entry.h |
---|
0,0 → 1,9 |
#ifndef SLEEP_ENTRY_H |
#define SLEEP_ENTRY_H |
/* Entry points for the sleep command */ |
extern int cmd_sleep(char **); |
extern void help_cmd_sleep(unsigned int); |
#endif /* SLEEP_ENTRY_H */ |
/branches/dynload/uspace/app/bdsh/cmds/modules/sleep/sleep.c |
---|
0,0 → 1,73 |
/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com> |
* 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. |
* |
* Neither the name of the original program's authors nor the names of its |
* contributors may be used to endorse or promote products derived from this |
* software without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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. |
*/ |
#include <stdio.h> |
#include <stdlib.h> |
#include "config.h" |
#include "util.h" |
#include "errors.h" |
#include "entry.h" |
#include "sleep.h" |
#include "cmds.h" |
static char *cmdname = "sleep"; |
/* Dispays help for sleep in various levels */ |
void help_cmd_sleep(unsigned int level) |
{ |
printf("This is the %s help for '%s'.\n", |
level ? EXT_HELP : SHORT_HELP, cmdname); |
return; |
} |
/* Main entry point for sleep, accepts an array of arguments */ |
int cmd_sleep(char **argv) |
{ |
unsigned int argc; |
unsigned int i; |
/* Count the arguments */ |
for (argc = 0; argv[argc] != NULL; argc ++); |
printf("%s %s\n", TEST_ANNOUNCE, cmdname); |
printf("%d arguments passed to %s", argc - 1, cmdname); |
if (argc < 2) { |
printf("\n"); |
return CMD_SUCCESS; |
} |
printf(":\n"); |
for (i = 1; i < argc; i++) |
printf("[%d] -> %s\n", i, argv[i]); |
return CMD_SUCCESS; |
} |
/branches/dynload/uspace/app/bdsh/cmds/modules/sleep/sleep_def.h |
---|
0,0 → 1,8 |
{ |
"sleep", |
"Pause for given time interval (in seconds)", |
&cmd_sleep, |
&help_cmd_sleep, |
0 |
}, |
/branches/dynload/uspace/app/bdsh/cmds/modules/sleep/sleep.h |
---|
0,0 → 1,8 |
#ifndef SLEEP_H |
#define SLEEP_H |
/* Prototypes for the sleep command, excluding entry points */ |
#endif /* SLEEP_H */ |
/branches/dynload/uspace/app/bdsh/cmds/modules/pwd/entry.h |
---|
4,8 → 4,8 |
#include "scli.h" |
/* Entry points for the pwd command */ |
extern void * help_cmd_pwd(unsigned int); |
extern int * cmd_pwd(char **); |
extern void help_cmd_pwd(unsigned int); |
extern int cmd_pwd(char **); |
#endif |
/branches/dynload/uspace/app/bdsh/cmds/modules/pwd/pwd.c |
---|
39,13 → 39,13 |
static char * cmdname = "pwd"; |
void * help_cmd_pwd(unsigned int level) |
void help_cmd_pwd(unsigned int level) |
{ |
printf("`%s' prints your current working directory.\n", cmdname); |
return CMD_VOID; |
return; |
} |
int * cmd_pwd(char *argv[]) |
int cmd_pwd(char *argv[]) |
{ |
char *buff; |
/branches/dynload/uspace/app/bdsh/cmds/modules/ls/ls.c |
---|
132,7 → 132,7 |
return; |
} |
void * help_cmd_ls(unsigned int level) |
void help_cmd_ls(unsigned int level) |
{ |
if (level == HELP_SHORT) { |
printf("`%s' lists files and directories.\n", cmdname); |
142,10 → 142,10 |
"working directory is used.\n", cmdname); |
} |
return CMD_VOID; |
return; |
} |
int * cmd_ls(char **argv) |
int cmd_ls(char **argv) |
{ |
unsigned int argc; |
unsigned int scope; |
/branches/dynload/uspace/app/bdsh/cmds/modules/ls/entry.h |
---|
2,8 → 2,8 |
#define LS_ENTRY_H |
/* Entry points for the ls command */ |
extern int * cmd_ls(char **); |
extern void * help_cmd_ls(unsigned int); |
extern int cmd_ls(char **); |
extern void help_cmd_ls(unsigned int); |
#endif /* LS_ENTRY_H */ |
/branches/dynload/uspace/app/bdsh/cmds/modules/modules.h |
---|
25,6 → 25,8 |
#include "touch/entry.h" |
#include "ls/entry.h" |
#include "pwd/entry.h" |
#include "sleep/entry.h" |
#include "cp/entry.h" |
/* Each .def function fills the module_t struct with the individual name, entry |
* point, help entry point, etc. You can use config.h to control what modules |
39,6 → 41,8 |
#include "touch/touch_def.h" |
#include "ls/ls_def.h" |
#include "pwd/pwd_def.h" |
#include "sleep/sleep_def.h" |
#include "cp/cp_def.h" |
{NULL, NULL, NULL, NULL} |
}; |
/branches/dynload/uspace/app/bdsh/cmds/modules/rm/rm.c |
---|
144,7 → 144,7 |
} |
/* Dispays help for rm in various levels */ |
void * help_cmd_rm(unsigned int level) |
void help_cmd_rm(unsigned int level) |
{ |
if (level == HELP_SHORT) { |
printf("`%s' removes files and directories.\n", cmdname); |
161,11 → 161,11 |
"Currently, %s is under development, some options don't work.\n", |
cmdname, cmdname); |
} |
return CMD_VOID; |
return; |
} |
/* Main entry point for rm, accepts an array of arguments */ |
int * cmd_rm(char **argv) |
int cmd_rm(char **argv) |
{ |
unsigned int argc; |
unsigned int i, scope, ret = 0; |
/branches/dynload/uspace/app/bdsh/cmds/modules/rm/entry.h |
---|
2,8 → 2,8 |
#define RM_ENTRY_H |
/* Entry points for the rm command */ |
extern int * cmd_rm(char **); |
extern void * help_cmd_rm(unsigned int); |
extern int cmd_rm(char **); |
extern void help_cmd_rm(unsigned int); |
#endif /* RM_ENTRY_H */ |
/branches/dynload/uspace/app/bdsh/cmds/builtins/cd/cd.c |
---|
42,7 → 42,7 |
static char * cmdname = "cd"; |
void * help_cmd_cd(unsigned int level) |
void help_cmd_cd(unsigned int level) |
{ |
if (level == HELP_SHORT) { |
printf("`%s' changes the current working directory.\n", cmdname); |
53,12 → 53,12 |
cmdname, cmdname); |
} |
return CMD_VOID; |
return; |
} |
/* This is a very rudamentary 'cd' command. It is not 'link smart' (yet) */ |
int * cmd_cd(char **argv, cliuser_t *usr) |
int cmd_cd(char **argv, cliuser_t *usr) |
{ |
int argc, rc = 0; |
/branches/dynload/uspace/app/bdsh/cmds/builtins/cd/entry.h |
---|
4,8 → 4,8 |
#include "scli.h" |
/* Entry points for the cd command */ |
extern void * help_cmd_cd(unsigned int); |
extern int * cmd_cd(char **, cliuser_t *); |
extern void help_cmd_cd(unsigned int); |
extern int cmd_cd(char **, cliuser_t *); |
#endif |
/branches/dynload/uspace/app/bdsh/cmds/cmds.h |
---|
19,17 → 19,16 |
#define BUFF_SMALL 255 |
/* Return macros for int type entry points */ |
#define CMD_FAILURE (int*)1 |
#define CMD_FAILURE 1 |
#define CMD_SUCCESS 0 |
#define CMD_VOID (void *)NULL |
/* Types for module command entry and help */ |
typedef int * (* mod_entry_t)(char **); |
typedef void * (* mod_help_t)(unsigned int); |
typedef int (* mod_entry_t)(char **); |
typedef void (* mod_help_t)(unsigned int); |
/* Built-in commands need to be able to modify cliuser_t */ |
typedef int * (* builtin_entry_t)(char **, cliuser_t *); |
typedef void * (* builtin_help_t)(unsigned int); |
typedef int (* builtin_entry_t)(char **, cliuser_t *); |
typedef void (* builtin_help_t)(unsigned int); |
/* Module structure */ |
typedef struct { |
/branches/dynload/uspace/app/bdsh/config.h |
---|
1,15 → 1,18 |
/* Various things that are used in many files |
* Various temporary port work-arounds are addressed in __HELENOS__ , this |
* serves as a convenience and later as a guide to make "phony.h" for future |
* ports */ |
/* Various things that are used in many places including a few |
* tidbits left over from autoconf prior to the HelenOS port */ |
/* Specific port work-arounds : */ |
#ifndef PATH_MAX |
#define PATH_MAX 255 |
#endif |
#ifndef EXIT_SUCCESS |
#define EXIT_SUCCESS 0 |
#define EXIT_FAILURE 0 |
#define EXIT_FAILURE 1 |
#endif |
/* Work around for getenv() */ |
#define PATH "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin" |
#define PATH "/srv:/app" |
#define PATH_DELIM ":" |
/* Used in many places */ |
26,7 → 29,7 |
#define PACKAGE_BUGREPORT "echo@echoreply.us" |
#define PACKAGE_NAME "bdsh" |
#define PACKAGE_STRING "The brain dead shell" |
#define PACKAGE_TARNAME "scli" |
#define PACKAGE_TARNAME "bdsh" |
#define PACKAGE_VERSION "0.0.1" |
/branches/dynload/uspace/app/bdsh/README |
---|
57,12 → 57,12 |
They are typed as such (from cmds.h): |
/* Types for module command entry and help */ |
typedef int * (* mod_entry_t)(char **); |
typedef void * (* mod_help_t)(unsigned int); |
typedef int (* mod_entry_t)(char **); |
typedef void (* mod_help_t)(unsigned int); |
/* Built-in commands need to be able to modify cliuser_t */ |
typedef int * (* builtin_entry_t)(char **, cliuser_t *); |
typedef void * (* builtin_help_t)(unsigned int); |
typedef int (* builtin_entry_t)(char **, cliuser_t *); |
typedef void (* builtin_help_t)(unsigned int); |
As you can see, both modular and builtin commands expect an array of |
arguments, however bulitins also expect to be pointed to cliuser_t. |
153,9 → 153,7 |
2: Change your "usage()" command as shown: |
-- void usage(...) |
++ void * help_cmd_foo(unsigned int level) |
-- return; |
++ retrn CMD_VOID; |
++ void help_cmd_foo(unsigned int level) |
'level' is either 0 or 1, indicating the level of help requested. |
If the help / usage function currently exits based on how it is |
163,33 → 161,19 |
3: Change the programs "main()" as shown: |
-- int main(int argc, char **argv) |
++ int * cmd_foo(char **argv) |
++ int cmd_foo(char **argv) |
-- return 1; |
++ return CMD_FAILURE; |
-- return 0; |
++ return CMD_SUCCESS; |
If main() returns an int that is not 1 or 0 (e.g. 127), cast it as |
such: |
-- return 127; |
++ return (int *) 127; |
NOTE: _ONLY_ the main and help entry points need to return int * or |
void *, respectively. Also take note that argc has changed. The type |
for entry points may soon change. |
NOTE: If main is void, you'll need to change it and ensure that its |
expecting an array of arguments, even if they'll never be read or |
used. I.e.: |
-- void main(void) |
++ int * cmd_foo(char **argv) |
++ int cmd_foo(char **argv) |
Similararly, do not try to return CMD_VOID within the modules main |
entry point. If somehow you escape the compiler yelling at you, you |
will surely see pretty blue and yellow fireworks once its reached. |
4: Don't expose more than the entry and help points: |
-- void my_function(int n) |
++ static void my_function(int n) |
/branches/dynload/uspace/app/bdsh/util.c |
---|
273,7 → 273,7 |
if (NULL == usr->cwd) |
snprintf(usr->cwd, PATH_MAX, "(unknown)"); |
if (1 < cli_psprintf(&usr->prompt, "%s # ", usr->cwd)) { |
if (1 < cli_psprintf(&usr->prompt, "%s ", usr->cwd)) { |
cli_error(cli_errno, "Failed to set prompt"); |
return 1; |
} |
/branches/dynload/uspace/app/bdsh/scli.c |
---|
53,8 → 53,8 |
const char *progname = PACKAGE_NAME; |
/* These are not exposed, even to builtins */ |
static int cli_init(cliuser_t *usr); |
static void cli_finit(cliuser_t *usr); |
static int cli_init(cliuser_t *); |
static void cli_finit(cliuser_t *); |
/* Constructor */ |
static int cli_init(cliuser_t *usr) |
/branches/dynload/uspace/app/bdsh/Makefile |
---|
64,6 → 64,8 |
cmds/modules/touch/ \ |
cmds/modules/ls/ \ |
cmds/modules/pwd/ \ |
cmds/modules/sleep/ \ |
cmds/modules/cp/ \ |
cmds/builtins/ \ |
cmds/builtins/cd/ |
76,6 → 78,8 |
cmds/modules/touch/touch.c \ |
cmds/modules/ls/ls.c \ |
cmds/modules/pwd/pwd.c \ |
cmds/modules/sleep/sleep.c \ |
cmds/modules/cp/cp.c \ |
cmds/builtins/cd/cd.c \ |
cmds/mod_cmds.c \ |
cmds/builtin_cmds.c \ |
/branches/dynload/uspace/app/init/init.c |
---|
108,17 → 108,15 |
return -1; |
} |
buf = malloc(BUF_SIZE); |
// FIXME: spawn("/srv/pci"); |
spawn("/srv/fb"); |
spawn("/srv/kbd"); |
spawn("/srv/console"); |
// FIXME: spawn("/sbin/pci"); |
spawn("/sbin/fb"); |
spawn("/sbin/kbd"); |
spawn("/sbin/console"); |
console_wait(); |
version_print(); |
spawn("/sbin/bdsh"); |
spawn("/app/bdsh"); |
free(buf); |
return 0; |
/branches/dynload/uspace/app/tester/tester.c |
---|
133,7 → 133,7 |
if (c == 'a') |
break; |
if (c > 'a') |
if (test->name == NULL) |
printf("Unknown test\n\n"); |
else |
run_test(test); |
/branches/dynload/uspace/app/trace/trace.c |
---|
0,0 → 1,658 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 trace |
* @{ |
*/ |
/** @file |
*/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <syscall.h> |
#include <ipc/ipc.h> |
#include <fibril.h> |
#include <errno.h> |
#include <udebug.h> |
#include <async.h> |
#include <task.h> |
// Temporary: service and method names |
#include "proto.h" |
#include <ipc/services.h> |
#include "../../srv/vfs/vfs.h" |
#include "../../srv/console/console.h" |
#include "syscalls.h" |
#include "ipcp.h" |
#include "errors.h" |
#include "trace.h" |
#define THBUF_SIZE 64 |
unsigned thread_hash_buf[THBUF_SIZE]; |
unsigned n_threads; |
int next_thread_id; |
int phoneid; |
int abort_trace; |
unsigned thash; |
volatile int paused; |
void thread_trace_start(unsigned thread_hash); |
static proto_t *proto_console; |
static task_id_t task_id; |
/** Combination of events/data to print. */ |
display_mask_t display_mask; |
static int task_connect(task_id_t task_id) |
{ |
int rc; |
rc = ipc_connect_kbox(task_id); |
if (rc == ENOTSUP) { |
printf("You do not have userspace debugging support " |
"compiled in the kernel.\n"); |
printf("Compile kernel with 'Support for userspace debuggers' " |
"(CONFIG_UDEBUG) enabled.\n"); |
return rc; |
} |
if (rc < 0) { |
printf("Error connecting\n"); |
printf("ipc_connect_task(%lld) -> %d ", task_id, rc); |
return rc; |
} |
phoneid = rc; |
rc = udebug_begin(phoneid); |
if (rc < 0) { |
printf("udebug_begin() -> %d\n", rc); |
return rc; |
} |
rc = udebug_set_evmask(phoneid, UDEBUG_EM_ALL); |
if (rc < 0) { |
printf("udebug_set_evmask(0x%x) -> %d\n ", UDEBUG_EM_ALL, rc); |
return rc; |
} |
return 0; |
} |
static int get_thread_list(void) |
{ |
int rc; |
size_t tb_copied; |
size_t tb_needed; |
int i; |
rc = udebug_thread_read(phoneid, thread_hash_buf, |
THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed); |
if (rc < 0) { |
printf("udebug_thread_read() -> %d\n", rc); |
return rc; |
} |
n_threads = tb_copied / sizeof(unsigned); |
printf("Threads:"); |
for (i = 0; i < n_threads; i++) { |
printf(" [%d] (hash 0x%x)", 1+i, thread_hash_buf[i]); |
} |
printf("\ntotal of %u threads\n", tb_needed/sizeof(unsigned)); |
return 0; |
} |
static void print_sc_retval(int retval, rv_type_t rv_type) |
{ |
printf (" -> "); |
if (rv_type == RV_INTEGER) { |
printf("%d", retval); |
} else if (rv_type == RV_HASH) { |
printf("0x%08x", retval); |
} else if (rv_type == RV_ERRNO) { |
if (retval >= -15 && retval <= 0) { |
printf("%d %s (%s)", retval, |
err_desc[retval].name, |
err_desc[retval].desc); |
} else { |
printf("%d", retval); |
} |
} else if (rv_type == RV_INT_ERRNO) { |
if (retval >= -15 && retval < 0) { |
printf("%d %s (%s)", retval, |
err_desc[retval].name, |
err_desc[retval].desc); |
} else { |
printf("%d", retval); |
} |
} |
putchar('\n'); |
} |
static void print_sc_args(unsigned *sc_args, int n) |
{ |
int i; |
putchar('('); |
if (n > 0) printf("%d", sc_args[0]); |
for (i=1; i<n; i++) { |
printf(", %d", sc_args[i]); |
} |
putchar(')'); |
} |
static void sc_ipc_call_async_fast(unsigned *sc_args, int sc_rc) |
{ |
ipc_call_t call; |
int phoneid; |
if (sc_rc == IPC_CALLRET_FATAL || sc_rc == IPC_CALLRET_TEMPORARY) |
return; |
phoneid = sc_args[0]; |
IPC_SET_METHOD(call, sc_args[1]); |
IPC_SET_ARG1(call, sc_args[2]); |
IPC_SET_ARG2(call, sc_args[3]); |
IPC_SET_ARG3(call, sc_args[4]); |
IPC_SET_ARG4(call, sc_args[5]); |
IPC_SET_ARG5(call, 0); |
ipcp_call_out(phoneid, &call, sc_rc); |
} |
static void sc_ipc_call_async_slow(unsigned *sc_args, int sc_rc) |
{ |
ipc_call_t call; |
int rc; |
if (sc_rc == IPC_CALLRET_FATAL || sc_rc == IPC_CALLRET_TEMPORARY) |
return; |
memset(&call, 0, sizeof(call)); |
rc = udebug_mem_read(phoneid, &call.args, sc_args[1], sizeof(call.args)); |
if (rc >= 0) { |
ipcp_call_out(sc_args[0], &call, sc_rc); |
} |
} |
static void sc_ipc_call_sync_fast(unsigned *sc_args) |
{ |
ipc_call_t question, reply; |
int rc; |
int phoneidx; |
// printf("sc_ipc_call_sync_fast()\n"); |
phoneidx = sc_args[0]; |
IPC_SET_METHOD(question, sc_args[1]); |
IPC_SET_ARG1(question, sc_args[2]); |
IPC_SET_ARG2(question, sc_args[3]); |
IPC_SET_ARG3(question, sc_args[4]); |
IPC_SET_ARG4(question, 0); |
IPC_SET_ARG5(question, 0); |
// printf("memset\n"); |
memset(&reply, 0, sizeof(reply)); |
// printf("udebug_mem_read(phone=%d, buffer_ptr=%u, src_addr=%d, n=%d\n", |
// phoneid, &reply.args, sc_args[5], sizeof(reply.args)); |
rc = udebug_mem_read(phoneid, &reply.args, sc_args[5], sizeof(reply.args)); |
// printf("dmr->%d\n", rc); |
if (rc < 0) return; |
// printf("call ipc_call_sync\n"); |
ipcp_call_sync(phoneidx, &question, &reply); |
} |
static void sc_ipc_call_sync_slow(unsigned *sc_args) |
{ |
ipc_call_t question, reply; |
int rc; |
memset(&question, 0, sizeof(question)); |
rc = udebug_mem_read(phoneid, &question.args, sc_args[1], sizeof(question.args)); |
printf("dmr->%d\n", rc); |
if (rc < 0) return; |
memset(&reply, 0, sizeof(reply)); |
rc = udebug_mem_read(phoneid, &reply.args, sc_args[2], sizeof(reply.args)); |
printf("dmr->%d\n", rc); |
if (rc < 0) return; |
ipcp_call_sync(sc_args[0], &question, &reply); |
} |
static void sc_ipc_wait(unsigned *sc_args, int sc_rc) |
{ |
ipc_call_t call; |
int rc; |
if (sc_rc == 0) return; |
memset(&call, 0, sizeof(call)); |
rc = udebug_mem_read(phoneid, &call, sc_args[0], sizeof(call)); |
// printf("udebug_mem_read(phone %d, dest %d, app-mem src %d, size %d -> %d\n", |
// phoneid, (int)&call, sc_args[0], sizeof(call), rc); |
if (rc >= 0) { |
ipcp_call_in(&call, sc_rc); |
} |
} |
static void event_syscall_b(unsigned thread_id, unsigned thread_hash, unsigned sc_id, int sc_rc) |
{ |
unsigned sc_args[6]; |
int rc; |
/* Read syscall arguments */ |
rc = udebug_args_read(phoneid, thread_hash, sc_args); |
async_serialize_start(); |
// printf("[%d] ", thread_id); |
if (rc < 0) { |
printf("error\n"); |
async_serialize_end(); |
return; |
} |
if ((display_mask & DM_SYSCALL) != 0) { |
/* Print syscall name and arguments */ |
printf("%s", syscall_desc[sc_id].name); |
print_sc_args(sc_args, syscall_desc[sc_id].n_args); |
} |
async_serialize_end(); |
} |
static void event_syscall_e(unsigned thread_id, unsigned thread_hash, unsigned sc_id, int sc_rc) |
{ |
unsigned sc_args[6]; |
int rv_type; |
int rc; |
/* Read syscall arguments */ |
rc = udebug_args_read(phoneid, thread_hash, sc_args); |
async_serialize_start(); |
// printf("[%d] ", thread_id); |
if (rc < 0) { |
printf("error\n"); |
async_serialize_end(); |
return; |
} |
if ((display_mask & DM_SYSCALL) != 0) { |
/* Print syscall return value */ |
rv_type = syscall_desc[sc_id].rv_type; |
print_sc_retval(sc_rc, rv_type); |
} |
switch (sc_id) { |
case SYS_IPC_CALL_ASYNC_FAST: |
sc_ipc_call_async_fast(sc_args, sc_rc); |
break; |
case SYS_IPC_CALL_ASYNC_SLOW: |
sc_ipc_call_async_slow(sc_args, sc_rc); |
break; |
case SYS_IPC_CALL_SYNC_FAST: |
sc_ipc_call_sync_fast(sc_args); |
break; |
case SYS_IPC_CALL_SYNC_SLOW: |
sc_ipc_call_sync_slow(sc_args); |
break; |
case SYS_IPC_WAIT: |
sc_ipc_wait(sc_args, sc_rc); |
break; |
default: |
break; |
} |
async_serialize_end(); |
} |
static void event_thread_b(unsigned hash) |
{ |
async_serialize_start(); |
printf("New thread, hash 0x%x\n", hash); |
async_serialize_end(); |
thread_trace_start(hash); |
} |
static int trace_loop(void *thread_hash_arg) |
{ |
int rc; |
unsigned ev_type; |
unsigned thread_hash; |
unsigned thread_id; |
unsigned val0, val1; |
thread_hash = (unsigned)thread_hash_arg; |
thread_id = next_thread_id++; |
printf("Start tracing thread [%d] (hash 0x%x)\n", thread_id, thread_hash); |
while (!abort_trace) { |
/* Run thread until an event occurs */ |
rc = udebug_go(phoneid, thread_hash, |
&ev_type, &val0, &val1); |
// printf("rc = %d, ev_type=%d\n", rc, ev_type); |
if (ev_type == UDEBUG_EVENT_FINISHED) { |
/* Done tracing this thread */ |
break; |
} |
if (rc >= 0) { |
switch (ev_type) { |
case UDEBUG_EVENT_SYSCALL_B: |
event_syscall_b(thread_id, thread_hash, val0, (int)val1); |
break; |
case UDEBUG_EVENT_SYSCALL_E: |
event_syscall_e(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_THREAD_B: |
event_thread_b(val0); |
break; |
case UDEBUG_EVENT_THREAD_E: |
printf("Thread 0x%x exited\n", val0); |
abort_trace = 1; |
break; |
default: |
printf("Unknown event type %d\n", ev_type); |
break; |
} |
} |
} |
printf("Finished tracing thread [%d]\n", thread_id); |
return 0; |
} |
void thread_trace_start(unsigned thread_hash) |
{ |
fid_t fid; |
thash = thread_hash; |
fid = fibril_create(trace_loop, (void *)thread_hash); |
if (fid == 0) { |
printf("Warning: Failed creating fibril\n"); |
} |
fibril_add_ready(fid); |
} |
static void trace_active_task(task_id_t task_id) |
{ |
int i; |
int rc; |
int c; |
rc = task_connect(task_id); |
if (rc < 0) { |
printf("Failed to connect to task %lld\n", task_id); |
return; |
} |
printf("Connected to task %lld\n", task_id); |
ipcp_init(); |
/* |
* User apps now typically have console on phone 3. |
* (Phones 1 and 2 are used by the loader). |
*/ |
ipcp_connection_set(3, 0, proto_console); |
rc = get_thread_list(); |
if (rc < 0) { |
printf("Failed to get thread list (error %d)\n", rc); |
return; |
} |
abort_trace = 0; |
for (i = 0; i < n_threads; i++) { |
thread_trace_start(thread_hash_buf[i]); |
} |
while(1) { |
c = getchar(); |
if (c == 'q') break; |
if (c == 'p') { |
paused = 1; |
rc = udebug_stop(phoneid, thash); |
printf("stop -> %d\n", rc); |
} |
if (c == 'r') { |
paused = 0; |
} |
} |
printf("\nTerminate debugging session...\n"); |
abort_trace = 1; |
udebug_end(phoneid); |
ipc_hangup(phoneid); |
ipcp_cleanup(); |
printf("Done\n"); |
return; |
} |
static void main_init(void) |
{ |
proto_t *p; |
oper_t *o; |
next_thread_id = 1; |
paused = 0; |
proto_init(); |
p = proto_new("vfs"); |
o = oper_new("read"); |
proto_add_oper(p, VFS_READ, o); |
o = oper_new("write"); |
proto_add_oper(p, VFS_WRITE, o); |
o = oper_new("truncate"); |
proto_add_oper(p, VFS_TRUNCATE, o); |
o = oper_new("mount"); |
proto_add_oper(p, VFS_MOUNT, o); |
o = oper_new("unmount"); |
proto_add_oper(p, VFS_UNMOUNT, o); |
proto_register(SERVICE_VFS, p); |
p = proto_new("console"); |
o = oper_new("getchar"); |
proto_add_oper(p, CONSOLE_GETCHAR, o); |
o = oper_new("putchar"); |
proto_add_oper(p, CONSOLE_PUTCHAR, o); |
o = oper_new("clear"); |
proto_add_oper(p, CONSOLE_CLEAR, o); |
o = oper_new("goto"); |
proto_add_oper(p, CONSOLE_GOTO, o); |
o = oper_new("getsize"); |
proto_add_oper(p, CONSOLE_GETSIZE, o); |
o = oper_new("flush"); |
proto_add_oper(p, CONSOLE_FLUSH, o); |
o = oper_new("set_style"); |
proto_add_oper(p, CONSOLE_SET_STYLE, o); |
o = oper_new("cursor_visibility"); |
proto_add_oper(p, CONSOLE_CURSOR_VISIBILITY, o); |
o = oper_new("flush"); |
proto_add_oper(p, CONSOLE_FLUSH, o); |
proto_console = p; |
proto_register(SERVICE_CONSOLE, p); |
} |
static void print_syntax() |
{ |
printf("Syntax:\n"); |
printf("\ttrace [+<events>] <executable> [<arg1> [...]]\n"); |
printf("or\ttrace [+<events>] -t <task_id>\n"); |
printf("Events: (default is +tp)\n"); |
printf("\n"); |
printf("\tt ... Thread creation and termination\n"); |
printf("\ts ... System calls\n"); |
printf("\ti ... Low-level IPC\n"); |
printf("\tp ... Protocol level\n"); |
printf("\n"); |
printf("Examples:\n"); |
printf("\ttrace +s /app/tetris\n"); |
printf("\ttrace +tsip -t 12\n"); |
} |
static display_mask_t parse_display_mask(char *text) |
{ |
display_mask_t dm; |
char *c; |
c = text; |
while (*c) { |
switch (*c) { |
case 't': dm = dm | DM_THREAD; break; |
case 's': dm = dm | DM_SYSCALL; break; |
case 'i': dm = dm | DM_IPC; break; |
case 'p': dm = dm | DM_SYSTEM | DM_USER; break; |
default: |
printf("Unexpected event type '%c'\n", *c); |
exit(1); |
} |
++c; |
} |
return dm; |
} |
static int parse_args(int argc, char *argv[]) |
{ |
char *arg; |
char *err_p; |
task_id = 0; |
--argc; ++argv; |
while (argc > 0) { |
arg = *argv; |
if (arg[0] == '+') { |
display_mask = parse_display_mask(&arg[1]); |
} else if (arg[0] == '-') { |
if (arg[1] == 't') { |
/* Trace an already running task */ |
--argc; ++argv; |
task_id = strtol(*argv, &err_p, 10); |
if (*err_p) { |
printf("Task ID syntax error\n"); |
print_syntax(); |
return -1; |
} |
} else { |
printf("Uknown option '%s'\n", arg[0]); |
print_syntax(); |
return -1; |
} |
} else { |
break; |
} |
--argc; ++argv; |
} |
if (task_id != 0) { |
if (argc == 0) return; |
printf("Extra arguments\n"); |
print_syntax(); |
return -1; |
} |
if (argc < 1) { |
printf("Missing argument\n"); |
print_syntax(); |
return -1; |
} |
/* Execute the specified command and trace the new task. */ |
printf("Spawning '%s' with arguments:\n", *argv); |
{ |
char **cp = argv; |
while (*cp) printf("'%s'\n", *cp++); |
} |
task_id = task_spawn(*argv, argv); |
return 0; |
} |
int main(int argc, char *argv[]) |
{ |
printf("System Call / IPC Tracer\n"); |
display_mask = DM_THREAD | DM_SYSTEM | DM_USER; |
if (parse_args(argc, argv) < 0) |
return 1; |
main_init(); |
trace_active_task(task_id); |
return 0; |
} |
/** @} |
*/ |
/branches/dynload/uspace/app/trace/trace.h |
---|
0,0 → 1,57 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 trace |
* @{ |
*/ |
/** @file |
*/ |
#ifndef TRACE_H_ |
#define TRACE_H_ |
/** |
* Classes of events that can be displayed. Can be or-ed together. |
*/ |
typedef enum { |
DM_THREAD = 1, /**< Thread creation and termination events */ |
DM_SYSCALL = 2, /**< System calls */ |
DM_IPC = 4, /**< Low-level IPC */ |
DM_SYSTEM = 8, /**< Sysipc protocol */ |
DM_USER = 16 /**< User IPC protocols */ |
} display_mask_t; |
/** Combination of events to print. */ |
extern display_mask_t display_mask; |
#endif |
/** @} |
*/ |
/branches/dynload/uspace/app/trace/ipcp.c |
---|
0,0 → 1,334 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 trace |
* @{ |
*/ |
/** @file |
*/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <libadt/hash_table.h> |
#include "ipc_desc.h" |
#include "proto.h" |
#include "trace.h" |
#include "ipcp.h" |
#define IPCP_CALLID_SYNC 0 |
typedef struct { |
int phone_hash; |
ipc_call_t question; |
int call_hash; |
link_t link; |
} pending_call_t; |
typedef struct { |
int server; |
proto_t *proto; |
} connection_t; |
#define MAX_PHONE 64 |
connection_t connections[MAX_PHONE]; |
int have_conn[MAX_PHONE]; |
#define PCALL_TABLE_CHAINS 32 |
hash_table_t pending_calls; |
/* |
* Pseudo-protocols |
*/ |
proto_t *proto_system; /**< Protocol describing system IPC methods. */ |
proto_t *proto_unknown; /**< Protocol with no known methods. */ |
static hash_index_t pending_call_hash(unsigned long key[]); |
static int pending_call_compare(unsigned long key[], hash_count_t keys, |
link_t *item); |
static void pending_call_remove_callback(link_t *item); |
hash_table_operations_t pending_call_ops = { |
.hash = pending_call_hash, |
.compare = pending_call_compare, |
.remove_callback = pending_call_remove_callback |
}; |
static hash_index_t pending_call_hash(unsigned long key[]) |
{ |
// printf("pending_call_hash\n"); |
return key[0] % PCALL_TABLE_CHAINS; |
} |
static int pending_call_compare(unsigned long key[], hash_count_t keys, |
link_t *item) |
{ |
pending_call_t *hs; |
// printf("pending_call_compare\n"); |
hs = hash_table_get_instance(item, pending_call_t, link); |
return key[0] == hs->call_hash; |
} |
static void pending_call_remove_callback(link_t *item) |
{ |
// printf("pending_call_remove_callback\n"); |
} |
void ipcp_connection_set(int phone, int server, proto_t *proto) |
{ |
if (phone <0 || phone >= MAX_PHONE) return; |
connections[phone].server = server; |
connections[phone].proto = proto; |
have_conn[phone] = 1; |
} |
void ipcp_connection_clear(int phone) |
{ |
have_conn[phone] = 0; |
connections[phone].server = 0; |
connections[phone].proto = NULL; |
} |
static void ipc_m_print(proto_t *proto, ipcarg_t method) |
{ |
oper_t *oper; |
/* Try system methods first */ |
oper = proto_get_oper(proto_system, method); |
if (oper == NULL && proto != NULL) { |
/* Not a system method, try the user protocol. */ |
oper = proto_get_oper(proto, method); |
} |
if (oper != NULL) { |
printf("%s (%d)", oper->name, method); |
return; |
} |
printf("%d", method); |
} |
void ipcp_init(void) |
{ |
ipc_m_desc_t *desc; |
oper_t *oper; |
/* |
* Create a pseudo-protocol 'unknown' that has no known methods. |
*/ |
proto_unknown = proto_new("unknown"); |
/* |
* Create a pseudo-protocol 'system' defining names of system IPC |
* methods. |
*/ |
proto_system = proto_new("system"); |
desc = ipc_methods; |
while (desc->number != 0) { |
oper = oper_new(desc->name); |
proto_add_oper(proto_system, desc->number, oper); |
++desc; |
} |
hash_table_create(&pending_calls, PCALL_TABLE_CHAINS, 1, &pending_call_ops); |
} |
void ipcp_cleanup(void) |
{ |
proto_delete(proto_system); |
hash_table_destroy(&pending_calls); |
} |
void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash) |
{ |
pending_call_t *pcall; |
proto_t *proto; |
unsigned long key[1]; |
oper_t *oper; |
if (have_conn[phone]) proto = connections[phone].proto; |
else proto = NULL; |
if ((display_mask & DM_IPC) != 0) { |
printf("Call ID: 0x%x, phone: %d, proto: %s, method: ", hash, |
phone, (proto ? proto->name : "n/a")); |
ipc_m_print(proto, IPC_GET_METHOD(*call)); |
printf(" args: (%u, %u, %u, %u, %u)\n", |
IPC_GET_ARG1(*call), |
IPC_GET_ARG2(*call), |
IPC_GET_ARG3(*call), |
IPC_GET_ARG4(*call), |
IPC_GET_ARG5(*call) |
); |
} |
if ((display_mask & DM_USER) != 0) { |
if (proto != NULL) { |
oper = proto_get_oper(proto, IPC_GET_METHOD(*call)); |
} else { |
oper = NULL; |
} |
if (oper != NULL) { |
printf("%s(%d).%s", (proto ? proto->name : "n/a"), |
phone, (oper ? oper->name : "unknown")); |
printf("(%u, %u, %u, %u, %u)\n", |
IPC_GET_ARG1(*call), |
IPC_GET_ARG2(*call), |
IPC_GET_ARG3(*call), |
IPC_GET_ARG4(*call), |
IPC_GET_ARG5(*call) |
); |
} |
} |
/* Store call in hash table for response matching */ |
pcall = malloc(sizeof(pending_call_t)); |
pcall->phone_hash = phone; |
pcall->question = *call; |
pcall->call_hash = hash; |
key[0] = hash; |
hash_table_insert(&pending_calls, key, &pcall->link); |
} |
static void parse_answer(ipc_callid_t hash, pending_call_t *pcall, |
ipc_call_t *answer) |
{ |
int phone; |
ipcarg_t method; |
ipcarg_t service; |
int retval; |
proto_t *proto; |
int cphone; |
// printf("parse_answer\n"); |
phone = pcall->phone_hash; |
method = IPC_GET_METHOD(pcall->question); |
retval = IPC_GET_RETVAL(*answer); |
if ((display_mask & DM_IPC) != 0) { |
printf("Response to 0x%x: retval=%d, args = (%u, %u, %u, %u, %u)\n", |
hash, retval, IPC_GET_ARG1(*answer), |
IPC_GET_ARG2(*answer), IPC_GET_ARG3(*answer), |
IPC_GET_ARG4(*answer), IPC_GET_ARG5(*answer)); |
} |
if ((display_mask & DM_USER) != 0) { |
printf("-> %d\n", retval); |
} |
if (phone == 0 && method == IPC_M_CONNECT_ME_TO && retval == 0) { |
/* Connected to a service (through NS) */ |
service = IPC_GET_ARG1(pcall->question); |
proto = proto_get_by_srv(service); |
if (proto == NULL) proto = proto_unknown; |
cphone = IPC_GET_ARG5(*answer); |
if ((display_mask & DM_SYSTEM) != 0) { |
printf("Registering connection (phone %d, protocol: %s)\n", cphone, |
proto->name); |
} |
ipcp_connection_set(cphone, 0, proto); |
} |
} |
void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash) |
{ |
link_t *item; |
pending_call_t *pcall; |
unsigned long key[1]; |
// printf("ipcp_call_in()\n"); |
/* printf("phone: %d, method: ", call->in_phone_hash); |
ipc_m_print(IPC_GET_METHOD(*call)); |
printf(" args: (%u, %u, %u, %u, %u)\n", |
IPC_GET_ARG1(*call), |
IPC_GET_ARG2(*call), |
IPC_GET_ARG3(*call), |
IPC_GET_ARG4(*call), |
IPC_GET_ARG5(*call) |
);*/ |
if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) { |
/* Not a response */ |
if ((display_mask & DM_IPC) != 0) { |
printf("Not a response (hash %d)\n", hash); |
} |
return; |
} |
hash = hash & ~IPC_CALLID_ANSWERED; |
key[0] = hash; |
item = hash_table_find(&pending_calls, key); |
if (item == NULL) return; // No matching question found |
/* |
* Response matched to question. |
*/ |
pcall = hash_table_get_instance(item, pending_call_t, link); |
hash_table_remove(&pending_calls, key, 1); |
parse_answer(hash, pcall, call); |
free(pcall); |
} |
void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer) |
{ |
ipcp_call_out(phone, call, IPCP_CALLID_SYNC); |
ipcp_call_in(answer, IPCP_CALLID_SYNC); |
} |
void ipcp_hangup(int phone, int rc) |
{ |
if ((display_mask & DM_SYSTEM) != 0) { |
printf("Hang phone %d up -> %d\n", phone, rc); |
ipcp_connection_clear(phone); |
} |
} |
/** @} |
*/ |
/branches/dynload/uspace/app/trace/proto.c |
---|
0,0 → 1,223 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 trace |
* @{ |
*/ |
/** @file |
*/ |
#include <stdio.h> |
#include <stdlib.h> |
#include <ipc/ipc.h> |
#include <libadt/hash_table.h> |
#include "proto.h" |
#define SRV_PROTO_TABLE_CHAINS 32 |
#define METHOD_OPER_TABLE_CHAINS 32 |
hash_table_t srv_proto; |
typedef struct { |
int srv; |
proto_t *proto; |
link_t link; |
} srv_proto_t; |
typedef struct { |
ipcarg_t method; |
oper_t *oper; |
link_t link; |
} method_oper_t; |
static hash_index_t srv_proto_hash(unsigned long key[]); |
static int srv_proto_compare(unsigned long key[], hash_count_t keys, |
link_t *item); |
static void srv_proto_remove_callback(link_t *item); |
hash_table_operations_t srv_proto_ops = { |
.hash = srv_proto_hash, |
.compare = srv_proto_compare, |
.remove_callback = srv_proto_remove_callback |
}; |
static hash_index_t method_oper_hash(unsigned long key[]); |
static int method_oper_compare(unsigned long key[], hash_count_t keys, |
link_t *item); |
static void method_oper_remove_callback(link_t *item); |
hash_table_operations_t method_oper_ops = { |
.hash = method_oper_hash, |
.compare = method_oper_compare, |
.remove_callback = method_oper_remove_callback |
}; |
static hash_index_t srv_proto_hash(unsigned long key[]) |
{ |
return key[0] % SRV_PROTO_TABLE_CHAINS; |
} |
static int srv_proto_compare(unsigned long key[], hash_count_t keys, |
link_t *item) |
{ |
srv_proto_t *sp; |
sp = hash_table_get_instance(item, srv_proto_t, link); |
return key[0] == sp->srv; |
} |
static void srv_proto_remove_callback(link_t *item) |
{ |
} |
static hash_index_t method_oper_hash(unsigned long key[]) |
{ |
return key[0] % METHOD_OPER_TABLE_CHAINS; |
} |
static int method_oper_compare(unsigned long key[], hash_count_t keys, |
link_t *item) |
{ |
method_oper_t *mo; |
mo = hash_table_get_instance(item, method_oper_t, link); |
return key[0] == mo->method; |
} |
static void method_oper_remove_callback(link_t *item) |
{ |
} |
void proto_init(void) |
{ |
hash_table_create(&srv_proto, SRV_PROTO_TABLE_CHAINS, 1, |
&srv_proto_ops); |
} |
void proto_cleanup(void) |
{ |
hash_table_destroy(&srv_proto); |
} |
void proto_register(int srv, proto_t *proto) |
{ |
srv_proto_t *sp; |
unsigned long key; |
sp = malloc(sizeof(srv_proto_t)); |
sp->srv = srv; |
sp->proto = proto; |
key = srv; |
hash_table_insert(&srv_proto, &key, &sp->link); |
} |
proto_t *proto_get_by_srv(int srv) |
{ |
unsigned long key; |
link_t *item; |
srv_proto_t *sp; |
key = srv; |
item = hash_table_find(&srv_proto, &key); |
if (item == NULL) return NULL; |
sp = hash_table_get_instance(item, srv_proto_t, link); |
return sp->proto; |
} |
static void proto_struct_init(proto_t *proto, char *name) |
{ |
proto->name = name; |
hash_table_create(&proto->method_oper, SRV_PROTO_TABLE_CHAINS, 1, |
&method_oper_ops); |
} |
proto_t *proto_new(char *name) |
{ |
proto_t *p; |
p = malloc(sizeof(proto_t)); |
proto_struct_init(p, name); |
return p; |
} |
void proto_delete(proto_t *proto) |
{ |
free(proto); |
} |
void proto_add_oper(proto_t *proto, int method, oper_t *oper) |
{ |
method_oper_t *mo; |
unsigned long key; |
mo = malloc(sizeof(method_oper_t)); |
mo->method = method; |
mo->oper = oper; |
key = method; |
hash_table_insert(&proto->method_oper, &key, &mo->link); |
} |
oper_t *proto_get_oper(proto_t *proto, int method) |
{ |
unsigned long key; |
link_t *item; |
method_oper_t *mo; |
key = method; |
item = hash_table_find(&proto->method_oper, &key); |
if (item == NULL) return NULL; |
mo = hash_table_get_instance(item, method_oper_t, link); |
return mo->oper; |
} |
static void oper_struct_init(oper_t *oper, char *name) |
{ |
oper->name = name; |
} |
oper_t *oper_new(char *name) |
{ |
oper_t *o; |
o = malloc(sizeof(oper_t)); |
oper_struct_init(o, name); |
return o; |
} |
/** @} |
*/ |
/branches/dynload/uspace/app/trace/proto.h |
---|
0,0 → 1,71 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 trace |
* @{ |
*/ |
/** @file |
*/ |
#ifndef PROTO_H_ |
#define PROTO_H_ |
#include <libadt/hash_table.h> |
typedef struct { |
char *name; |
} oper_t; |
typedef struct { |
/** Protocol name */ |
char *name; |
/** Maps method number to operation */ |
hash_table_t method_oper; |
} proto_t; |
/* Maps service number to protocol */ |
extern hash_table_t srv_proto; |
void proto_init(void); |
void proto_cleanup(void); |
void proto_register(int srv, proto_t *proto); |
proto_t *proto_get_by_srv(int srv); |
proto_t *proto_new(char *name); |
void proto_delete(proto_t *proto); |
void proto_add_oper(proto_t *proto, int method, oper_t *oper); |
oper_t *proto_get_oper(proto_t *proto, int method); |
oper_t *oper_new(char *name); |
#endif |
/** @} |
*/ |
/branches/dynload/uspace/app/trace/ipc_desc.h |
---|
0,0 → 1,48 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 trace |
* @{ |
*/ |
/** @file |
*/ |
#ifndef IPC_DESC_H_ |
#define IPC_DESC_H_ |
typedef struct { |
int number; |
char *name; |
} ipc_m_desc_t; |
extern ipc_m_desc_t ipc_methods[]; |
#endif |
/** @} |
*/ |
/branches/dynload/uspace/app/trace/ipcp.h |
---|
0,0 → 1,55 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 trace |
* @{ |
*/ |
/** @file |
*/ |
#ifndef IPCP_H_ |
#define IPCP_H_ |
#include <ipc/ipc.h> |
#include "proto.h" |
void ipcp_init(void); |
void ipcp_cleanup(void); |
void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash); |
void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer); |
void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash); |
void ipcp_hangup(int phone, int rc); |
void ipcp_connection_set(int phone, int server, proto_t *proto); |
void ipcp_connection_clear(int phone); |
#endif |
/** @} |
*/ |
/branches/dynload/uspace/app/trace/errors.h |
---|
0,0 → 1,48 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 trace |
* @{ |
*/ |
/** @file |
*/ |
#ifndef ERRORS_H_ |
#define ERRORS_H_ |
typedef struct { |
char *name; /**< Error value name (Exx) */ |
char *desc; /**< Error description */ |
} err_desc_t; |
extern const err_desc_t err_desc[]; |
#endif |
/** @} |
*/ |
/branches/dynload/uspace/app/trace/syscalls.h |
---|
0,0 → 1,56 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 trace |
* @{ |
*/ |
/** @file |
*/ |
#ifndef SYSCALLS_H_ |
#define SYSCALLS_H_ |
typedef enum { |
RV_INTEGER, |
RV_HASH, |
RV_ERRNO, |
RV_INT_ERRNO |
} rv_type_t; |
typedef struct { |
char *name; |
int n_args; |
rv_type_t rv_type; |
} sc_desc_t; |
extern const sc_desc_t syscall_desc[]; |
#endif |
/** @} |
*/ |
/branches/dynload/uspace/app/trace/ipc_desc.c |
---|
0,0 → 1,58 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 trace |
* @{ |
*/ |
/** @file |
*/ |
#include <stdlib.h> |
#include <ipc/ipc.h> |
#include "ipc_desc.h" |
ipc_m_desc_t ipc_methods[] = { |
/* System methods */ |
{ IPC_M_CONNECT_TO_ME, "CONNECT_TO_ME" }, |
{ IPC_M_CONNECT_ME_TO, "CONNECT_ME_TO" }, |
{ IPC_M_PHONE_HUNGUP, "PHONE_HUNGUP" }, |
{ IPC_M_SHARE_OUT, "SHARE_OUT" }, |
{ IPC_M_SHARE_IN, "SHARE_IN" }, |
{ IPC_M_DATA_WRITE, "DATA_WRITE" }, |
{ IPC_M_DATA_READ, "DATA_READ" }, |
{ IPC_M_DEBUG_ALL, "DEBUG_ALL" }, |
/* Well-known methods */ |
{ IPC_M_PING, "PING" }, |
/* Terminating entry */ |
{ 0, NULL } |
}; |
/** @} |
*/ |
/branches/dynload/uspace/app/trace/Makefile |
---|
0,0 → 1,78 |
# |
# Copyright (c) 2005 Martin Decky |
# 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. |
# |
## Setup toolchain |
# |
LIBC_PREFIX = ../../lib/libc |
SOFTINT_PREFIX = ../../lib/softint |
include $(LIBC_PREFIX)/Makefile.toolchain |
CFLAGS += -I../../srv/kbd/include |
LIBS = $(LIBC_PREFIX)/libc.a |
## Sources |
# |
OUTPUT = trace |
SOURCES = trace.c \ |
syscalls.c \ |
ipcp.c \ |
ipc_desc.c \ |
proto.c \ |
errors.c |
OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) |
.PHONY: all clean depend disasm |
all: $(OUTPUT) disasm |
-include Makefile.depend |
clean: |
-rm -f $(OUTPUT) $(OBJECTS) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend |
depend: |
$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend |
$(OUTPUT): $(OBJECTS) $(LIBS) |
$(LD) -T $(LIBC_PREFIX)/arch/$(ARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map |
disasm: |
$(OBJDUMP) -d $(OUTPUT) >$(OUTPUT).disasm |
%.o: %.S |
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@ |
%.o: %.s |
$(AS) $(AFLAGS) $< -o $@ |
%.o: %.c |
$(CC) $(DEFS) $(CFLAGS) -c $< -o $@ |
/branches/dynload/uspace/app/trace/errors.c |
---|
0,0 → 1,61 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 trace |
* @{ |
*/ |
/** @file |
*/ |
#include <errno.h> |
#include "errors.h" |
const err_desc_t err_desc[] = { |
[-EOK] = { "EOK", "No error" }, |
[-ENOENT] = { "ENOENT", "No such entry" }, |
[-ENOMEM] = { "ENOMEM", "Not enough memory" }, |
[-ELIMIT] = { "ELIMIT", "Limit exceeded" }, |
[-EREFUSED] = { "EREFUSED", "Connection refused" }, |
[-EFORWARD] = { "EFORWARD", "Forward error" }, |
[-EPERM] = { "EPERM", "Permission denied" }, |
[-EHANGUP] = { "EHANGUP", "Answerbox closed connection" }, |
[-EEXISTS] = { "EEXISTS", "Entry already exists" }, |
[-EBADMEM] = { "EBADMEM", "Bad memory pointer" }, |
[-ENOTSUP] = { "ENOTSUP", "Not supported" }, |
[-EADDRNOTAVAIL] = { "EADDRNOTAVAIL", "Address not available." }, |
[-ETIMEOUT] = { "ETIMEOUT", "Timeout expired" }, |
[-EINVAL] = { "EINVAL", "Invalid value" }, |
[-EBUSY] = { "EBUSY", "Resource is busy" }, |
[-EOVERFLOW] = { "EOVERFLOW", "The result does not fit its size." } |
}; |
/** @} |
*/ |
/branches/dynload/uspace/app/trace/syscalls.c |
---|
0,0 → 1,79 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 trace |
* @{ |
*/ |
/** @file |
*/ |
#include <kernel/syscall/syscall.h> |
#include "syscalls.h" |
const sc_desc_t syscall_desc[] = { |
[SYS_KLOG] ={ "klog", 3, RV_INT_ERRNO }, |
[SYS_TLS_SET] = { "tls_set", 1, RV_ERRNO }, |
[SYS_THREAD_CREATE] = { "thread_create", 3, RV_ERRNO }, |
[SYS_THREAD_EXIT] = { "thread_exit", 1, RV_ERRNO }, |
[SYS_THREAD_GET_ID] = { "thread_get_id", 1, RV_ERRNO }, |
[SYS_TASK_GET_ID] = { "task_get_id", 1, RV_ERRNO }, |
[SYS_FUTEX_SLEEP] = { "futex_sleep_timeout", 3, RV_ERRNO }, |
[SYS_FUTEX_WAKEUP] = { "futex_wakeup", 1, RV_ERRNO }, |
[SYS_AS_AREA_CREATE] = { "as_area_create", 3, RV_ERRNO }, |
[SYS_AS_AREA_RESIZE] = { "as_area_resize", 3, RV_ERRNO }, |
[SYS_AS_AREA_DESTROY] = { "as_area_destroy", 1, RV_ERRNO }, |
[SYS_IPC_CALL_SYNC_FAST] = { "ipc_call_sync_fast", 6, RV_ERRNO }, |
[SYS_IPC_CALL_SYNC_SLOW] = { "ipc_call_sync_slow", 3, RV_ERRNO }, |
[SYS_IPC_CALL_ASYNC_FAST] = { "ipc_call_async_fast", 6, RV_HASH }, |
[SYS_IPC_CALL_ASYNC_SLOW] = { "ipc_call_async_slow", 2, RV_HASH }, |
[SYS_IPC_ANSWER_FAST] = { "ipc_answer_fast", 6, RV_ERRNO }, |
[SYS_IPC_ANSWER_SLOW] = { "ipc_answer_slow", 2, RV_ERRNO }, |
[SYS_IPC_FORWARD_FAST] = { "ipc_forward_fast", 6, RV_ERRNO }, |
[SYS_IPC_WAIT] = { "ipc_wait_for_call", 3, RV_HASH }, |
[SYS_IPC_HANGUP] = { "ipc_hangup", 1, RV_ERRNO }, |
[SYS_IPC_REGISTER_IRQ] = { "ipc_register_irq", 4, RV_ERRNO }, |
[SYS_IPC_UNREGISTER_IRQ] = { "ipc_unregister_irq", 2, RV_ERRNO }, |
[SYS_CAP_GRANT] = { "cap_grant", 2, RV_ERRNO }, |
[SYS_CAP_REVOKE] = { "cap_revoke", 2, RV_ERRNO }, |
[SYS_PHYSMEM_MAP] = { "physmem_map", 4, RV_ERRNO }, |
[SYS_IOSPACE_ENABLE] = { "iospace_enable", 1, RV_ERRNO }, |
[SYS_PREEMPT_CONTROL] = { "preempt_control", 1, RV_ERRNO }, |
[SYS_SYSINFO_VALID] = { "sysinfo_valid", 2, RV_HASH }, |
[SYS_SYSINFO_VALUE] = { "sysinfo_value", 2, RV_HASH }, |
[SYS_DEBUG_ENABLE_CONSOLE] = { "debug_enable_console", 0, RV_ERRNO }, |
[SYS_IPC_CONNECT_KBOX] = { "ipc_connect_kbox", 1, RV_ERRNO } |
}; |
/** @} |
*/ |
/branches/dynload/uspace/lib/libc/include/string.h |
---|
64,6 → 64,9 |
extern long int strtol(const char *, char **, int); |
extern unsigned long strtoul(const char *, char **, int); |
extern char * strtok_r(char *, const char *, char **); |
extern char * strtok(char *, const char *); |
#endif |
/** @} |
/branches/dynload/uspace/lib/libc/include/udebug.h |
---|
0,0 → 1,58 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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_UDEBUG_H_ |
#define LIBC_UDEBUG_H_ |
#include <kernel/udebug/udebug.h> |
#include <sys/types.h> |
#include <libarch/types.h> |
typedef sysarg_t thash_t; |
int udebug_begin(int phoneid); |
int udebug_end(int phoneid); |
int udebug_set_evmask(int phoneid, udebug_evmask_t mask); |
int udebug_thread_read(int phoneid, void *buffer, size_t n, |
size_t *copied, size_t *needed); |
int udebug_mem_read(int phoneid, void *buffer, uintptr_t addr, size_t n); |
int udebug_args_read(int phoneid, thash_t tid, sysarg_t *buffer); |
int udebug_go(int phoneid, thash_t tid, udebug_event_t *ev_type, |
sysarg_t *val0, sysarg_t *val1); |
int udebug_stop(int phoneid, thash_t tid); |
#endif |
/** @} |
*/ |
/branches/dynload/uspace/lib/libc/include/ipc/ipc.h |
---|
288,6 → 288,10 |
extern int ipc_data_write_receive(ipc_callid_t *callid, size_t *size); |
extern int ipc_data_write_finalize(ipc_callid_t callid, void *dst, size_t size); |
#include <task.h> |
extern int ipc_connect_kbox(task_id_t id); |
#endif |
/** @} |
/branches/dynload/uspace/lib/libc/include/ipc/loader.h |
---|
39,6 → 39,7 |
typedef enum { |
LOADER_HELLO = IPC_FIRST_USER_METHOD, |
LOADER_GET_TASKID, |
LOADER_SET_PATHNAME, |
LOADER_SET_ARGS, |
LOADER_RUN |
/branches/dynload/uspace/lib/libc/generic/task.c |
---|
133,6 → 133,7 |
char *pa; |
size_t pa_len; |
task_id_t task_id; |
pa = absolutize(path, &pa_len); |
if (!pa) |
151,6 → 152,18 |
if (rc != EOK) |
return 0; |
/* Get task ID. */ |
req = async_send_0(phone_id, LOADER_GET_TASKID, &answer); |
rc = ipc_data_read_start(phone_id, &task_id, sizeof(task_id)); |
if (rc != EOK) { |
async_wait_for(req, NULL); |
goto error; |
} |
async_wait_for(req, &retval); |
if (retval != EOK) |
goto error; |
/* Send program pathname */ |
req = async_send_0(phone_id, LOADER_SET_PATHNAME, &answer); |
rc = ipc_data_write_start(phone_id, (void *)pa, pa_len); |
175,7 → 188,7 |
/* Success */ |
ipc_hangup(phone_id); |
return 1; |
return task_id; |
/* Error exit */ |
error: |
/branches/dynload/uspace/lib/libc/generic/string.c |
---|
1,5 → 1,7 |
/* |
* Copyright (c) 2005 Martin Decky |
* Copyright (C) 1998 by Wes Peters <wes@softweyr.com> |
* Copyright (c) 1988, 1993 The Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
396,5 → 398,52 |
return (char *) memcpy(ret, s1, len); |
} |
/* Ported from FBSD strtok.c 8.1 (Berkeley) 6/4/93 */ |
char * strtok_r(char *s, const char *delim, char **last) |
{ |
char *spanp, *tok; |
int c, sc; |
if (s == NULL && (s = *last) == NULL) |
return (NULL); |
cont: |
c = *s++; |
for (spanp = (char *)delim; (sc = *spanp++) != 0;) { |
if (c == sc) |
goto cont; |
} |
if (c == 0) { /* no non-delimiter characters */ |
*last = NULL; |
return (NULL); |
} |
tok = s - 1; |
for (;;) { |
c = *s++; |
spanp = (char *)delim; |
do { |
if ((sc = *spanp++) == c) { |
if (c == 0) |
s = NULL; |
else |
s[-1] = '\0'; |
*last = s; |
return (tok); |
} |
} while (sc != 0); |
} |
} |
/* Ported from FBSD strtok.c 8.1 (Berkeley) 6/4/93 */ |
char * strtok(char *s, const char *delim) |
{ |
static char *last; |
return (strtok_r(s, delim, &last)); |
} |
/** @} |
*/ |
/branches/dynload/uspace/lib/libc/generic/ipc.c |
---|
909,6 → 909,18 |
{ |
return ipc_answer_2(callid, EOK, (ipcarg_t) dst, (ipcarg_t) size); |
} |
#include <kernel/syscall/sysarg64.h> |
/** Connect to a task specified by id. |
*/ |
int ipc_connect_kbox(task_id_t id) |
{ |
sysarg64_t arg; |
arg.value = (unsigned long long) id; |
return __SYSCALL1(SYS_IPC_CONNECT_KBOX, (sysarg_t) &arg); |
} |
/** @} |
*/ |
/branches/dynload/uspace/lib/libc/generic/udebug.c |
---|
0,0 → 1,92 |
/* |
* Copyright (c) 2008 Jiri Svoboda |
* 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 <udebug.h> |
#include <sys/types.h> |
#include <syscall.h> |
#include <ipc/ipc.h> |
#include <async.h> |
int udebug_begin(int phoneid) |
{ |
return async_req_1_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_BEGIN); |
} |
int udebug_end(int phoneid) |
{ |
return async_req_1_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_END); |
} |
int udebug_set_evmask(int phoneid, udebug_evmask_t mask) |
{ |
return async_req_2_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_SET_EVMASK, |
mask); |
} |
int udebug_thread_read(int phoneid, void *buffer, size_t n, |
size_t *copied, size_t *needed) |
{ |
unsigned dest_addr; |
return async_req_3_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_THREAD_READ, |
(sysarg_t)buffer, n, &dest_addr, copied, needed); |
} |
int udebug_mem_read(int phoneid, void *buffer, uintptr_t addr, size_t n) |
{ |
return async_req_4_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_MEM_READ, |
(sysarg_t)buffer, addr, n); |
} |
int udebug_args_read(int phoneid, thash_t tid, sysarg_t *buffer) |
{ |
return async_req_3_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_ARGS_READ, |
tid, (sysarg_t)buffer); |
} |
int udebug_go(int phoneid, thash_t tid, udebug_event_t *ev_type, |
sysarg_t *val0, sysarg_t *val1) |
{ |
return async_req_2_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_GO, |
tid, (sysarg_t)ev_type, (sysarg_t)val0, (sysarg_t)val1); |
} |
int udebug_stop(int phoneid, thash_t tid) |
{ |
return async_req_2_0(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_STOP, |
tid); |
} |
/** @} |
*/ |
/branches/dynload/uspace/lib/libc/Makefile |
---|
80,6 → 80,7 |
generic/err.c \ |
generic/stdlib.c \ |
generic/mman.c \ |
generic/udebug.c \ |
generic/vfs/vfs.c \ |
generic/vfs/canonify.c |
/branches/dynload/uspace/srv/loader/main.c |
---|
77,6 → 77,27 |
/** Buffer holding all arguments */ |
static char *arg_buf = NULL; |
static int loader_get_taskid(ipc_callid_t rid, ipc_call_t *request) |
{ |
ipc_callid_t callid; |
task_id_t task_id; |
size_t len; |
task_id = task_get_id(); |
if (!ipc_data_read_receive(&callid, &len)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
if (len > sizeof(task_id)) len = sizeof(task_id); |
ipc_data_write_finalize(callid, &task_id, len); |
ipc_answer_0(rid, EOK); |
} |
/** Receive a call setting pathname of the program to execute. |
* |
* @param rid |
276,6 → 297,9 |
// printf("received call from phone %d, method=%d\n", |
// call.in_phone_hash, IPC_GET_METHOD(call)); |
switch (IPC_GET_METHOD(call)) { |
case LOADER_GET_TASKID: |
loader_get_taskid(callid, &call); |
continue; |
case LOADER_SET_PATHNAME: |
loader_set_pathname(callid, &call); |
continue; |
/branches/dynload/uspace/Makefile |
---|
51,6 → 51,7 |
app/tetris \ |
app/tester \ |
app/dltest \ |
app/trace \ |
app/klog \ |
app/init \ |
app/bdsh |
/branches/dynload/boot/arch/sparc64/loader/Makefile |
---|
94,12 → 94,14 |
COMPONENTS += $(USPACEDIR)/srv/fs/fat/fat |
endif |
RD_TASKS = \ |
RD_SRVS = \ |
$(USPACEDIR)/srv/fb/fb \ |
$(USPACEDIR)/srv/kbd/kbd \ |
$(USPACEDIR)/srv/console/console \ |
$(USPACEDIR)/srv/fs/tmpfs/tmpfs \ |
$(USPACEDIR)/srv/fs/fat/fat \ |
$(USPACEDIR)/srv/fs/fat/fat |
RD_APPS = \ |
$(USPACEDIR)/app/tetris/tetris \ |
$(USPACEDIR)/app/tester/tester \ |
$(USPACEDIR)/app/bdsh/bdsh \ |
121,15 → 123,21 |
-makedepend $(DEFS) $(CFLAGS) -f - $(SOURCES) > Makefile.depend 2> /dev/null |
clean: |
-for task in $(RD_TASKS) ; do \ |
rm -f $(USPACEDIR)/dist/sbin/`basename $$task` ; \ |
-for file in $(RD_SRVS) ; do \ |
rm -f $(USPACEDIR)/dist/srv/`basename $$file` ; \ |
done |
-for file in $(RD_APPS) ; do \ |
rm -f $(USPACEDIR)/dist/app/`basename $$file` ; \ |
done |
-rm -f _components.h _components.c _link.ld $(COMPONENT_OBJECTS) $(OBJECTS) initrd.img image.boot image.map image.disasm Makefile.depend |
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) $(RD_TASKS) _link.ld.in |
for task in $(RD_TASKS) ; do \ |
cp $$task $(USPACEDIR)/dist/sbin/ ; \ |
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) $(RD_SRVS) $(RD_APPS) _link.ld.in |
for file in $(RD_SRVS) ; do \ |
cp $$file $(USPACEDIR)/dist/srv/ ; \ |
done |
for file in $(RD_APPS) ; do \ |
cp $$file $(USPACEDIR)/dist/app/ ; \ |
done |
ifeq ($(RDFMT),tmpfs) |
../../../../tools/mktmpfs.py $(USPACEDIR)/dist/ initrd.fs |
endif |
/branches/dynload/boot/arch/ia64/loader/Makefile |
---|
98,6 → 98,7 |
$(USPACEDIR)/srv/fs/tmpfs/tmpfs \ |
$(USPACEDIR)/srv/devmap/devmap \ |
$(USPACEDIR)/app/cli/cli \ |
$(USPACEDIR)/app/trace/trace \ |
$(USPACEDIR)/app/klog/klog |
OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) |
/branches/dynload/boot/arch/arm32/loader/Makefile |
---|
96,14 → 96,17 |
COMPONENTS += $(USPACEDIR)/srv/fs/fat/fat |
endif |
RD_TASKS = \ |
RD_SRVS = \ |
$(USPACEDIR)/srv/fb/fb \ |
$(USPACEDIR)/srv/kbd/kbd \ |
$(USPACEDIR)/srv/console/console \ |
$(USPACEDIR)/srv/fs/tmpfs/tmpfs \ |
$(USPACEDIR)/srv/fs/fat/fat \ |
$(USPACEDIR)/srv/fs/fat/fat |
RD_APPS = \ |
$(USPACEDIR)/app/tetris/tetris \ |
$(USPACEDIR)/app/tester/tester \ |
$(USPACEDIR)/app/trace/trace \ |
$(USPACEDIR)/app/klog/klog \ |
$(USPACEDIR)/app/bdsh/bdsh |
123,15 → 126,21 |
-makedepend $(DEFS) $(CFLAGS) -f - $(SOURCES) > Makefile.depend 2> /dev/null |
clean: |
-for task in $(RD_TASKS) ; do \ |
rm -f $(USPACEDIR)/dist/sbin/`basename $$task` ; \ |
-for file in $(RD_SRVS) ; do \ |
rm -f $(USPACEDIR)/dist/srv/`basename $$file` ; \ |
done |
-for file in $(RD_APPS) ; do \ |
rm -f $(USPACEDIR)/dist/app/`basename $$file` ; \ |
done |
-rm -f _components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o $(OBJECTS) initrd.img image.boot Makefile.depend |
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) _link.ld.in |
for task in $(RD_TASKS) ; do \ |
cp $$task $(USPACEDIR)/dist/sbin/ ; \ |
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) $(RD_SRVS) $(RD_APPS) _link.ld.in |
for file in $(RD_SRVS) ; do \ |
cp $$file $(USPACEDIR)/dist/srv/ ; \ |
done |
for file in $(RD_APPS) ; do \ |
cp $$file $(USPACEDIR)/dist/app/ ; \ |
done |
ifeq ($(RDFMT),tmpfs) |
../../../../tools/mktmpfs.py $(USPACEDIR)/dist/ initrd.fs |
endif |
/branches/dynload/boot/arch/ppc32/loader/Makefile |
---|
91,15 → 91,18 |
COMPONENTS += $(USPACEDIR)/srv/fs/fat/fat |
endif |
RD_TASKS = \ |
RD_SRVS = \ |
$(USPACEDIR)/srv/fb/fb \ |
$(USPACEDIR)/srv/kbd/kbd \ |
$(USPACEDIR)/srv/console/console \ |
$(USPACEDIR)/srv/fs/tmpfs/tmpfs \ |
$(USPACEDIR)/srv/fs/fat/fat \ |
$(USPACEDIR)/srv/fs/fat/fat |
RD_APPS = \ |
$(USPACEDIR)/app/tetris/tetris \ |
$(USPACEDIR)/app/tester/tester \ |
$(USPACEDIR)/app/dltest/dltest \ |
$(USPACEDIR)/app/trace/trace \ |
$(USPACEDIR)/app/klog/klog \ |
$(USPACEDIR)/app/bdsh/bdsh |
123,21 → 126,27 |
-makedepend $(DEFS) $(CFLAGS) -f - $(SOURCES) > Makefile.depend 2> /dev/null |
clean: |
-for task in $(RD_TASKS) ; do \ |
rm -f $(USPACEDIR)/dist/sbin/`basename $$task` ; \ |
-for file in $(RD_SRVS) ; do \ |
rm -f $(USPACEDIR)/dist/srv/`basename $$file` ; \ |
done |
-for lib in $(RD_LIBS) ; do \ |
rm -f $(USPACEDIR)/dist/lib/`basename $$lib` ; \ |
done |
-for file in $(RD_APPS) ; do \ |
rm -f $(USPACEDIR)/dist/app/`basename $$file` ; \ |
done |
-rm -f _components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o $(OBJECTS) initrd.img image.boot Makefile.depend |
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) $(RD_TASKS) $(RD_LIBS) _link.ld.in |
for task in $(RD_TASKS) ; do \ |
cp $$task $(USPACEDIR)/dist/sbin/ ; \ |
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) $(RD_SRVS) $(RD_LIBS) $(RD_APPS) _link.ld.in |
for file in $(RD_SRVS) ; do \ |
cp $$file $(USPACEDIR)/dist/srv/ ; \ |
done |
for lib in $(RD_LIBS) ; do \ |
cp $$lib $(USPACEDIR)/dist/lib/ ; \ |
done |
for file in $(RD_APPS) ; do \ |
cp $$file $(USPACEDIR)/dist/app/ ; \ |
done |
ifeq ($(RDFMT),tmpfs) |
../../../../tools/mktmpfs.py $(USPACEDIR)/dist/ initrd.fs |
endif |
/branches/dynload/boot/arch/amd64/Makefile.inc |
---|
40,21 → 40,24 |
INIT_TASKS += $(USPACEDIR)/srv/fs/fat/fat |
endif |
RD_TASKS = \ |
RD_SRVS = \ |
$(USPACEDIR)/srv/pci/pci \ |
$(USPACEDIR)/srv/fb/fb \ |
$(USPACEDIR)/srv/kbd/kbd \ |
$(USPACEDIR)/srv/console/console \ |
$(USPACEDIR)/srv/fs/tmpfs/tmpfs \ |
$(USPACEDIR)/srv/fs/fat/fat |
RD_APPS = \ |
$(USPACEDIR)/app/tetris/tetris \ |
$(USPACEDIR)/app/tester/tester \ |
$(USPACEDIR)/app/trace/trace \ |
$(USPACEDIR)/app/klog/klog \ |
$(USPACEDIR)/app/bdsh/bdsh \ |
$(USPACEDIR)/srv/fs/tmpfs/tmpfs \ |
$(USPACEDIR)/srv/fs/fat/fat |
$(USPACEDIR)/app/bdsh/bdsh |
build: $(BASE)/image.iso |
$(BASE)/image.iso: arch/$(ARCH)/grub/stage2_eltorito arch/$(ARCH)/grub/menu.lst $(KERNELDIR)/kernel.bin $(INIT_TASKS) $(RD_TASKS) |
$(BASE)/image.iso: arch/$(ARCH)/grub/stage2_eltorito arch/$(ARCH)/grub/menu.lst $(KERNELDIR)/kernel.bin $(INIT_TASKS) $(RD_SRVS) $(RD_APPS) |
mkdir -p arch/$(ARCH)/iso/boot/grub |
cp arch/$(ARCH)/grub/stage2_eltorito arch/$(ARCH)/iso/boot/grub/ |
ifneq ($(RDFMT),tmpfs) |
67,9 → 70,12 |
for task in $(INIT_TASKS) ; do \ |
cp $$task arch/$(ARCH)/iso/boot/ ; \ |
done |
for task in $(RD_TASKS) ; do \ |
cp $$task $(USPACEDIR)/dist/sbin/ ; \ |
for file in $(RD_SRVS) ; do \ |
cp $$file $(USPACEDIR)/dist/srv/ ; \ |
done |
for file in $(RD_APPS) ; do \ |
cp $$file $(USPACEDIR)/dist/app/ ; \ |
done |
ifeq ($(RDFMT),tmpfs) |
$(BASE)/tools/mktmpfs.py $(USPACEDIR)/dist/ arch/$(ARCH)/iso/boot/initrd.fs |
endif |
81,8 → 87,11 |
mkisofs -J -r -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table -o $(BASE)/image.iso arch/$(ARCH)/iso/ |
clean: |
-for task in $(RD_TASKS) ; do \ |
rm -f $(USPACEDIR)/dist/sbin/`basename $$task` ; \ |
-for file in $(RD_SRVS) ; do \ |
rm -f $(USPACEDIR)/dist/srv/`basename $$file` ; \ |
done |
-for file in $(RD_APPS) ; do \ |
rm -f $(USPACEDIR)/dist/app/`basename $$file` ; \ |
done |
-rm -fr arch/$(ARCH)/iso |
-rm -f $(BASE)/image.iso |
/branches/dynload/boot/arch/ppc64/loader/Makefile |
---|
89,6 → 89,7 |
$(USPACEDIR)/app/init/init \ |
$(USPACEDIR)/app/tetris/tetris \ |
$(USPACEDIR)/app/tester/tester \ |
$(USPACEDIR)/app/trace/trace \ |
$(USPACEDIR)/app/klog/klog |
OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) |
/branches/dynload/boot/arch/mips32/loader/Makefile |
---|
96,18 → 96,20 |
COMPONENTS += $(USPACEDIR)/srv/fs/fat/fat |
endif |
RD_TASKS = \ |
RD_SRVS = \ |
$(USPACEDIR)/srv/fb/fb \ |
$(USPACEDIR)/srv/kbd/kbd \ |
$(USPACEDIR)/srv/console/console \ |
$(USPACEDIR)/srv/fs/tmpfs/tmpfs \ |
$(USPACEDIR)/srv/fs/fat/fat \ |
$(USPACEDIR)/srv/fs/fat/fat |
RD_APPS = \ |
$(USPACEDIR)/app/tetris/tetris \ |
$(USPACEDIR)/app/tester/tester \ |
$(USPACEDIR)/app/trace/trace \ |
$(USPACEDIR)/app/bdsh/bdsh \ |
$(USPACEDIR)/app/klog/klog |
OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) |
COMPONENT_OBJECTS := $(addsuffix .o,$(basename $(notdir $(COMPONENTS)))) |
124,15 → 126,21 |
-makedepend $(DEFS) $(CFLAGS) -f - $(SOURCES) > Makefile.depend 2> /dev/null |
clean: |
-for task in $(RD_TASKS) ; do \ |
rm -f $(USPACEDIR)/dist/sbin/`basename $$task` ; \ |
-for file in $(RD_SRVS) ; do \ |
rm -f $(USPACEDIR)/dist/srv/`basename $$file` ; \ |
done |
-for file in $(RD_APPS) ; do \ |
rm -f $(USPACEDIR)/dist/app/`basename $$file` ; \ |
done |
-rm -f _components.h _components.c _link.ld _link.ld.in $(COMPONENT_OBJECTS) initrd.o $(OBJECTS) initrd.img image.boot Makefile.depend |
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) _link.ld.in |
for task in $(RD_TASKS) ; do \ |
cp $$task $(USPACEDIR)/dist/sbin/ ; \ |
_components.h _components.c _link.ld $(COMPONENT_OBJECTS) initrd.o: $(COMPONENTS) $(RD_SRVS) $(RD_APPS) _link.ld.in |
for file in $(RD_SRVS) ; do \ |
cp $$file $(USPACEDIR)/dist/srv/ ; \ |
done |
for file in $(RD_APPS) ; do \ |
cp $$file $(USPACEDIR)/dist/app/ ; \ |
done |
ifeq ($(RDFMT),tmpfs) |
../../../../tools/mktmpfs.py $(USPACEDIR)/dist/ initrd.fs |
endif |
/branches/dynload/boot/arch/ia32/Makefile.inc |
---|
40,15 → 40,18 |
INIT_TASKS += $(USPACEDIR)/srv/fs/fat/fat |
endif |
RD_TASKS = \ |
RD_SRVS = \ |
$(USPACEDIR)/srv/pci/pci \ |
$(USPACEDIR)/srv/fb/fb \ |
$(USPACEDIR)/srv/kbd/kbd \ |
$(USPACEDIR)/srv/console/console \ |
$(USPACEDIR)/srv/fs/fat/fat \ |
$(USPACEDIR)/srv/fs/fat/fat |
RD_APPS = \ |
$(USPACEDIR)/app/tetris/tetris \ |
$(USPACEDIR)/app/tester/tester \ |
$(USPACEDIR)/app/dltest/dltest \ |
$(USPACEDIR)/app/trace/trace \ |
$(USPACEDIR)/app/klog/klog \ |
$(USPACEDIR)/app/bdsh/bdsh |
58,7 → 61,7 |
build: $(BASE)/image.iso |
$(BASE)/image.iso: arch/$(ARCH)/grub/stage2_eltorito arch/$(ARCH)/grub/menu.lst $(KERNELDIR)/kernel.bin $(INIT_TASKS) $(RD_TASKS) $(RD_LIBS) |
$(BASE)/image.iso: arch/$(ARCH)/grub/stage2_eltorito arch/$(ARCH)/grub/menu.lst $(KERNELDIR)/kernel.bin $(INIT_TASKS) $(RD_SRVS) $(RD_LIBS) $(RD_APPS) |
mkdir -p arch/$(ARCH)/iso/boot/grub |
cp arch/$(ARCH)/grub/stage2_eltorito arch/$(ARCH)/iso/boot/grub/ |
ifneq ($(RDFMT),tmpfs) |
71,12 → 74,15 |
for task in $(INIT_TASKS) ; do \ |
cp $$task arch/$(ARCH)/iso/boot/ ; \ |
done |
for task in $(RD_TASKS) ; do \ |
cp $$task $(USPACEDIR)/dist/sbin/ ; \ |
for file in $(RD_SRVS) ; do \ |
cp $$file $(USPACEDIR)/dist/srv/ ; \ |
done |
for lib in $(RD_LIBS) ; do \ |
cp $$lib $(USPACEDIR)/dist/lib/ ; \ |
done |
for file in $(RD_APPS) ; do \ |
cp $$file $(USPACEDIR)/dist/app/ ; \ |
done |
ifeq ($(RDFMT),tmpfs) |
$(BASE)/tools/mktmpfs.py $(USPACEDIR)/dist/ arch/$(ARCH)/iso/boot/initrd.fs |
endif |
88,11 → 94,14 |
mkisofs -J -r -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table -o $(BASE)/image.iso arch/$(ARCH)/iso/ |
clean: |
-for task in $(RD_TASKS) ; do \ |
rm -f $(USPACEDIR)/dist/sbin/`basename $$task` ; \ |
-for file in $(RD_SRVS) ; do \ |
rm -f $(USPACEDIR)/dist/srv/`basename $$file` ; \ |
done |
-for lib in $(RD_LIBS) ; do \ |
rm -f $(USPACEDIR)/dist/lib/`basename $$lib` ; \ |
done |
-for file in $(RD_APPS) ; do \ |
rm -f $(USPACEDIR)/dist/app/`basename $$file` ; \ |
done |
-rm -fr arch/$(ARCH)/iso |
-rm -f $(BASE)/image.iso |